Respect Language & Input preferences under Android
* doc/emacs/android.texi (Android Environment): * doc/emacs/cmdargs.texi (General Variables): Mention the manner in which the default language environment is selected on Android. * lisp/startup.el (normal-top-level): If android and initial-window-system, call android-locale-for-system-language for the default locale name. * lisp/term/android-win.el (android-locale-for-system-language): New function. * src/androidfns.c (syms_of_androidfns_for_pdumper): New function. (syms_of_androidfns) <Vandroid_os_language>: New variable. Call syms_of_androidfns_for_pdumper both now and after loading the dump image.
This commit is contained in:
parent
33aa46fe94
commit
de25aaa11a
5 changed files with 296 additions and 9 deletions
|
@ -409,15 +409,23 @@ Startup}) connect the Android system to another computer, and run:
|
|||
$ adb shell "settings put global settings_enable_monitor_phantom_procs false"
|
||||
@end example
|
||||
|
||||
@cindex system language settings, Android
|
||||
The ``Languages & Input'' preferences which apply to the operating
|
||||
system do not influence the C locale set for programs, but is taken
|
||||
into account by Emacs during startup: a locale name is generated from
|
||||
the selected language and regional variant and a language environment
|
||||
(@pxref{Language Environment}) is selected on that basis, which does
|
||||
not overwrite @code{LANG} or other locale-related environment
|
||||
variables. The coding system for language environments set in this
|
||||
fashion is @code{utf-8-unix} without exception.
|
||||
|
||||
@cindex C locale settings, Android
|
||||
Emacs does not respect the locale configured for user applications
|
||||
in the system, for the selection of locales available there does not
|
||||
match that supplied by the C library. When Emacs starts on Android
|
||||
5.0 or newer, the @code{LANG} environment variable is set to
|
||||
@code{en_US.utf8}, which induces subprocesses linked against the
|
||||
Android C library to print output sensibly. Earlier versions of
|
||||
Android do not implement locales at all, on account of which the
|
||||
variable is set to @code{C} instead.
|
||||
Instead, the @code{LANG} environment variable (@pxref{General
|
||||
Variables}) is set to @code{en_US.utf8} when Emacs starts on Android
|
||||
5.0 or newer, which induces subprocesses linked against the Android C
|
||||
library to print output sensibly. Earlier versions of Android do not
|
||||
implement locales at all, on account of which the variable is set to
|
||||
@code{C} instead.
|
||||
|
||||
@cindex running emacs in the background, android
|
||||
@cindex emacs killed, android
|
||||
|
|
|
@ -640,6 +640,11 @@ set this in the ``Regional Settings'' Control Panel on some versions
|
|||
of MS-Windows, and in the ``Language and Region'' System Preference on
|
||||
macOS.
|
||||
|
||||
When running a GUI session on Android, @env{LANG} is set to a fixed
|
||||
value, but the language and locale environment is derived from the
|
||||
system's ``Languages & Input'' preferences. @xref{Android
|
||||
Environment}.
|
||||
|
||||
The value of the @env{LC_CTYPE} category is
|
||||
matched against entries in @code{locale-language-names},
|
||||
@code{locale-charset-language-names}, and
|
||||
|
|
|
@ -641,7 +641,23 @@ It is the default value of the variable `top-level'."
|
|||
(setq eol-mnemonic-dos "(DOS)"
|
||||
eol-mnemonic-mac "(Mac)")))
|
||||
|
||||
(set-locale-environment nil)
|
||||
(if (and (featurep 'android)
|
||||
(eq system-type 'android)
|
||||
initial-window-system)
|
||||
;; If Android windowing is enabled, derive a proper locale
|
||||
;; from the system's language preferences. On Android, LANG
|
||||
;; and LC_* must be set to one of the two locales the C
|
||||
;; library supports, but, by contrast with other systems, the
|
||||
;; C library locale does not reflect the configured system
|
||||
;; language.
|
||||
;;
|
||||
;; For this reason, the locale from which Emacs derives a
|
||||
;; default language environment is computed from such
|
||||
;; preferences, rather than environment variables that the C
|
||||
;; library refers to.
|
||||
(set-locale-environment
|
||||
(funcall 'android-locale-for-system-language))
|
||||
(set-locale-environment nil))
|
||||
;; Decode all default-directory's (probably, only *scratch* exists
|
||||
;; at this point). default-directory of *scratch* is the basis
|
||||
;; for many other file-name variables and directory lists, so it
|
||||
|
|
|
@ -424,6 +424,61 @@ denied. ")
|
|||
'follow-link t)
|
||||
(newline))))
|
||||
|
||||
|
||||
;;; Locale preferences.
|
||||
|
||||
(defvar android-os-language)
|
||||
|
||||
(defun android-locale-for-system-language ()
|
||||
"Return a locale representing the system language.
|
||||
This locale reflects the system's language preferences in its
|
||||
language name and country variant fields, and always specifies
|
||||
the UTF-8 coding system."
|
||||
;; android-os-language is a list comprising four elements LANGUAGE,
|
||||
;; COUNTRY, SCRIPT, and VARIANT.
|
||||
;;
|
||||
;; LANGUAGE and COUNTRY are ISO language and country codes identical
|
||||
;; to those stored within POSIX locales.
|
||||
;;
|
||||
;; SCRIPT is an ISO 15924 script tag, representing the script used
|
||||
;; if available, or if required to disambiguate between distinct
|
||||
;; writing systems for the same combination of language and country.
|
||||
;;
|
||||
;; VARIANT is an arbitrary string representing the variant of the
|
||||
;; LANGUAGE or SCRIPT represented.
|
||||
;;
|
||||
;; Each of these fields might be empty, but the locale is invalid if
|
||||
;; LANGUAGE is empty, which if true "en_US.UTF-8" is returned as a
|
||||
;; placeholder.
|
||||
(let ((language (or (nth 0 android-os-language) ""))
|
||||
(country (or (nth 1 android-os-language) ""))
|
||||
(script (or (nth 2 android-os-language) ""))
|
||||
(variant (or (nth 3 android-os-language) ""))
|
||||
locale-base locale-modifier)
|
||||
(if (string-empty-p language)
|
||||
(setq locale-base "en_US.UTF-8")
|
||||
(if (string-empty-p country)
|
||||
(setq locale-base (concat language ".UTF-8"))
|
||||
(setq locale-base (concat language "_" country
|
||||
".UTF-8"))))
|
||||
;; No straightforward relation between Java script and variant
|
||||
;; combinations exist: Java permits both a script and a variant to
|
||||
;; be supplied at once, whereas POSIX's closest analog "modifiers"
|
||||
;; permit only either an alternative script or a variant to be
|
||||
;; supplied.
|
||||
;;
|
||||
;; Emacs disregards variants besides "EURO" and scripts besides
|
||||
;; "Cyrl", for these two never coexist in existing locales, and
|
||||
;; their POSIX equivalents are the sole modifiers recognized by
|
||||
;; Emacs.
|
||||
(if (string-equal script "Cyrl")
|
||||
(setq locale-modifier "@cyrillic")
|
||||
(if (string-equal variant "EURO")
|
||||
(setq locale-modifier "@euro")
|
||||
(setq locale-modifier "")))
|
||||
;; Return the concatenation of both these values.
|
||||
(concat locale-base locale-modifier)))
|
||||
|
||||
|
||||
(provide 'android-win)
|
||||
;; android-win.el ends here.
|
||||
|
|
203
src/androidfns.c
203
src/androidfns.c
|
@ -27,6 +27,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include "keyboard.h"
|
||||
#include "buffer.h"
|
||||
#include "androidgui.h"
|
||||
#include "pdumper.h"
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
|
@ -3170,6 +3171,186 @@ android_set_preeditarea (struct window *w, int x, int y)
|
|||
|
||||
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
static void
|
||||
syms_of_androidfns_for_pdumper (void)
|
||||
{
|
||||
jclass locale;
|
||||
jmethodID method;
|
||||
jobject object;
|
||||
jstring string;
|
||||
Lisp_Object language, country, script, variant;
|
||||
const char *data;
|
||||
|
||||
/* Find the Locale class. */
|
||||
|
||||
locale = (*android_java_env)->FindClass (android_java_env,
|
||||
"java/util/Locale");
|
||||
if (!locale)
|
||||
emacs_abort ();
|
||||
|
||||
/* And the method from which the default locale can be
|
||||
extracted. */
|
||||
|
||||
method = (*android_java_env)->GetStaticMethodID (android_java_env,
|
||||
locale,
|
||||
"getDefault",
|
||||
"()Ljava/util/Locale;");
|
||||
if (!method)
|
||||
emacs_abort ();
|
||||
|
||||
/* Retrieve the default locale. */
|
||||
|
||||
object = (*android_java_env)->CallStaticObjectMethod (android_java_env,
|
||||
locale, method);
|
||||
android_exception_check_1 (locale);
|
||||
|
||||
if (!object)
|
||||
emacs_abort ();
|
||||
|
||||
/* Retrieve its language field. Each of these methods is liable to
|
||||
return the empty string, though if language is empty, the locale
|
||||
is malformed. */
|
||||
|
||||
method = (*android_java_env)->GetMethodID (android_java_env, locale,
|
||||
"getLanguage",
|
||||
"()Ljava/lang/String;");
|
||||
if (!method)
|
||||
emacs_abort ();
|
||||
|
||||
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
|
||||
method);
|
||||
android_exception_check_2 (object, locale);
|
||||
|
||||
if (!string)
|
||||
language = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
data = (*android_java_env)->GetStringUTFChars (android_java_env,
|
||||
string, NULL);
|
||||
android_exception_check_3 (object, locale, string);
|
||||
|
||||
if (!data)
|
||||
language = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
language = build_unibyte_string (data);
|
||||
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
|
||||
string, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the reference to this string. */
|
||||
ANDROID_DELETE_LOCAL_REF (string);
|
||||
|
||||
/* Proceed to retrieve the country code. */
|
||||
|
||||
method = (*android_java_env)->GetMethodID (android_java_env, locale,
|
||||
"getCountry",
|
||||
"()Ljava/lang/String;");
|
||||
if (!method)
|
||||
emacs_abort ();
|
||||
|
||||
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
|
||||
method);
|
||||
android_exception_check_2 (object, locale);
|
||||
|
||||
if (!string)
|
||||
country = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
data = (*android_java_env)->GetStringUTFChars (android_java_env,
|
||||
string, NULL);
|
||||
android_exception_check_3 (object, locale, string);
|
||||
|
||||
if (!data)
|
||||
country = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
country = build_unibyte_string (data);
|
||||
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
|
||||
string, data);
|
||||
}
|
||||
}
|
||||
|
||||
ANDROID_DELETE_LOCAL_REF (string);
|
||||
|
||||
/* Proceed to retrieve the script. */
|
||||
|
||||
method = (*android_java_env)->GetMethodID (android_java_env, locale,
|
||||
"getScript",
|
||||
"()Ljava/lang/String;");
|
||||
if (!method)
|
||||
emacs_abort ();
|
||||
|
||||
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
|
||||
method);
|
||||
android_exception_check_2 (object, locale);
|
||||
|
||||
if (!string)
|
||||
script = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
data = (*android_java_env)->GetStringUTFChars (android_java_env,
|
||||
string, NULL);
|
||||
android_exception_check_3 (object, locale, string);
|
||||
|
||||
if (!data)
|
||||
script = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
script = build_unibyte_string (data);
|
||||
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
|
||||
string, data);
|
||||
}
|
||||
}
|
||||
|
||||
ANDROID_DELETE_LOCAL_REF (string);
|
||||
|
||||
/* And variant. */
|
||||
|
||||
method = (*android_java_env)->GetMethodID (android_java_env, locale,
|
||||
"getVariant",
|
||||
"()Ljava/lang/String;");
|
||||
if (!method)
|
||||
emacs_abort ();
|
||||
|
||||
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
|
||||
method);
|
||||
android_exception_check_2 (object, locale);
|
||||
|
||||
if (!string)
|
||||
variant = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
data = (*android_java_env)->GetStringUTFChars (android_java_env,
|
||||
string, NULL);
|
||||
android_exception_check_3 (object, locale, string);
|
||||
|
||||
if (!data)
|
||||
variant = empty_unibyte_string;
|
||||
else
|
||||
{
|
||||
variant = build_unibyte_string (data);
|
||||
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
|
||||
string, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the reference to this string. */
|
||||
ANDROID_DELETE_LOCAL_REF (string);
|
||||
|
||||
/* And other remaining local references. */
|
||||
ANDROID_DELETE_LOCAL_REF (object);
|
||||
ANDROID_DELETE_LOCAL_REF (locale);
|
||||
|
||||
/* Set Vandroid_os_language. */
|
||||
Vandroid_os_language = list4 (language, country, script, variant);
|
||||
}
|
||||
|
||||
#endif /* ANDROID_STUBIFY */
|
||||
|
||||
void
|
||||
syms_of_androidfns (void)
|
||||
{
|
||||
|
@ -3313,6 +3494,26 @@ element that is activated for a given number of milliseconds upon the
|
|||
bell being rung. */);
|
||||
android_keyboard_bell_duration = 50;
|
||||
|
||||
DEFVAR_LISP ("android-os-language", Vandroid_os_language,
|
||||
doc: /* List representing the system language configured.
|
||||
This list incorporates four elements LANGUAGE, COUNTRY, SCRIPT
|
||||
and VARIANT, of which:
|
||||
|
||||
LANGUAGE and COUNTRY are ISO language and country codes identical to
|
||||
those stored within POSIX locales.
|
||||
|
||||
SCRIPT is an ISO 15924 script tag, representing the script used
|
||||
if available, or if required to disambiguate between distinct
|
||||
writing systems for the same combination of language and country.
|
||||
|
||||
VARIANT is an arbitrary string representing the variant of the
|
||||
LANGUAGE or SCRIPT represented.
|
||||
|
||||
Each of these fields might be empty or nil, but the locale is invalid
|
||||
if LANGUAGE is empty. Users of this variable should consider the
|
||||
language US English in this scenario. */);
|
||||
Vandroid_os_language = Qnil;
|
||||
|
||||
/* Functions defined. */
|
||||
defsubr (&Sx_create_frame);
|
||||
defsubr (&Sxw_color_defined_p);
|
||||
|
@ -3363,5 +3564,7 @@ bell being rung. */);
|
|||
staticpro (&tip_dx);
|
||||
tip_dy = Qnil;
|
||||
staticpro (&tip_dy);
|
||||
|
||||
pdumper_do_now_and_after_load (syms_of_androidfns_for_pdumper);
|
||||
#endif /* !ANDROID_STUBIFY */
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue