emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master de25aaa11a8 1/2: Respect Language & Input preferences under Andro


From: Po Lu
Subject: master de25aaa11a8 1/2: Respect Language & Input preferences under Android
Date: Thu, 14 Dec 2023 00:25:54 -0500 (EST)

branch: master
commit de25aaa11a8ef264c6f76841daa7e2a721c60937
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    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.
---
 doc/emacs/android.texi   |  24 ++++--
 doc/emacs/cmdargs.texi   |   5 ++
 lisp/startup.el          |  18 ++++-
 lisp/term/android-win.el |  55 +++++++++++++
 src/androidfns.c         | 203 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 296 insertions(+), 9 deletions(-)

diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index fe73bc09d67..3cdeec6ba9e 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -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
diff --git a/doc/emacs/cmdargs.texi b/doc/emacs/cmdargs.texi
index 38e683bd7f5..7cdc29ea30b 100644
--- a/doc/emacs/cmdargs.texi
+++ b/doc/emacs/cmdargs.texi
@@ -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
diff --git a/lisp/startup.el b/lisp/startup.el
index e40c316a8e8..09ec24c6c67 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -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
diff --git a/lisp/term/android-win.el b/lisp/term/android-win.el
index 3e759a37a71..b2cc7b5d040 100644
--- a/lisp/term/android-win.el
+++ b/lisp/term/android-win.el
@@ -425,5 +425,60 @@ denied.  ")
       (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.
diff --git a/src/androidfns.c b/src/androidfns.c
index 31a4924e34d..60ace4fd453 100644
--- a/src/androidfns.c
+++ b/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 */
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]