[gimp/wip/Jehan/fix-language-detect: 3/3] app: detect system language with a more robust logic.




commit 344df3d367217838f84004c36333dcce6d175133
Author: Jehan <jehan girinstud io>
Date:   Thu Jul 7 14:47:28 2022 +0200

    app: detect system language with a more robust logic.
    
    langinfo.h is not on all systems apparently and/or the locale item we
    test for may not be available everywhere. Actually even on Linux, after
    testing more deeply, I could create cases where nl_langinfo() would not
    return a result (if the locale is broken through environment variable
    for instance). setlocale() seems to always return usable value so far,
    so I fallback on it. As a last resort, I look at environment variables
    (even though these may contain invalid contents.
    
    As for Windows and macOS, I try to use more platform-specific methods.
    In macOS in particular, as I understood from reports, GIMP follows
    correctly the language preference order, which means we should not look
    at a single (top) lang, but at the whole list of prefered languages as a
    single settings to determine whether the language was changed or not.
    
    Should fix on Windows:
    
    > fatal error: langinfo.h: No such file or directory
    
    and on macOS:
    
    > error: use of undeclared identifier '_NL_IDENTIFICATION_LANGUAGE'

 app/language.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 configure.ac   | 14 ++++++++++++
 meson.build    |  9 ++++++++
 3 files changed, 84 insertions(+), 7 deletions(-)
---
diff --git a/app/language.c b/app/language.c
index f50bba737a..1db9d6e798 100644
--- a/app/language.c
+++ b/app/language.c
@@ -21,7 +21,9 @@
 
 #include "config.h"
 
+#ifdef HAVE__NL_IDENTIFICATION_LANGUAGE
 #include <langinfo.h>
+#endif
 #include <locale.h>
 
 #include <glib.h>
@@ -34,6 +36,9 @@
 #include "language.h"
 
 
+static gchar * language_get_system_lang_id (void);
+
+
 const gchar *
 language_init (const gchar *language)
 {
@@ -740,13 +745,7 @@ language_init (const gchar *language)
    */
   if (! language || strlen (language) == 0)
     {
-      /* Using system language. It doesn't matter too much that the string
-       * format is different when using system or preference-set language,
-       * because this string is only used for comparison. As long as 2
-       * similar run have the same settings, the strings will be
-       * identical.
-       */
-      actual_language = g_strdup (nl_langinfo (_NL_IDENTIFICATION_LANGUAGE));
+      actual_language = language_get_system_lang_id ();
     }
   else
     {
@@ -758,3 +757,58 @@ language_init (const gchar *language)
 
   return actual_language;
 }
+
+static gchar *
+language_get_system_lang_id (void)
+{
+  const gchar *syslang = NULL;
+
+  /* Using system language. It doesn't matter too much that the string
+   * format is different when using system or preference-set language,
+   * because this string is only used for comparison. As long as 2
+   * similar run have the same settings, the strings will be
+   * identical.
+   */
+#if defined G_OS_WIN32
+  return g_strdup_printf ("LANGID-%d", GetUserDefaultUILanguage());
+#elif defined PLATFORM_OSX
+  NSString *langs;
+
+  /* In macOS, the user sets a list of prefered languages and the
+   * software respects this preference order. I.e. that just storing the
+   * top-prefered lang would not be enough. What if GIMP didn't have
+   * translations for it, then it would fallback to the second lang. If
+   * this second lang changed, GIMP localization would change but we
+   * would not be aware of it. Instead, let's use the whole list as our
+   * language identifier. If this list changes in any way, we consider
+   * the lang may have potentially changed.
+   */
+  langs = [[NSLocale preferredLanguages] componentsJoinedByString:@","];
+
+  return g_strdup_printf ("%s", [langs UTF8String]);
+#elif defined HAVE__NL_IDENTIFICATION_LANGUAGE
+  syslang = nl_langinfo (_NL_IDENTIFICATION_LANGUAGE);
+#endif
+
+  if (syslang == NULL || strlen (syslang) == 0)
+    /* This should return an opaque string which represents the whole
+     * locale configuration on this system.
+     */
+    syslang = setlocale (LC_ALL, NULL);
+
+  /* I don't think we'd ever get here but just in case, as a last
+   * resort, if none of the previous methods returned a valid result,
+   * let's just check environment variables ourselves.
+   * This is the proper order of priority.
+   */
+  if (syslang == NULL || strlen (syslang) == 0)
+    syslang = g_getenv ("LANGUAGE");
+  if (syslang == NULL || strlen (syslang) == 0)
+    syslang = g_getenv ("LC_ALL");
+  if (syslang == NULL || strlen (syslang) == 0)
+    syslang = g_getenv ("LC_MESSAGES");
+  if (syslang == NULL || strlen (syslang) == 0)
+    syslang = g_getenv ("LANG");
+
+  return syslang && strlen (syslang) > 0 ? g_strdup (syslang) : NULL;
+}
diff --git a/configure.ac b/configure.ac
index ec85f0cdda..5ba0447c52 100644
--- a/configure.ac
+++ b/configure.ac
@@ -639,6 +639,20 @@ if test "$nl_ok" = "yes"; then
            [Define to 1 if _NL_MEASUREMENT_MEASUREMENT is available])
 fi
 
+# _NL_IDENTIFICATION_LANGUAGE is an enum and not a define
+AC_MSG_CHECKING([for _NL_IDENTIFICATION_LANGUAGE])
+AC_LINK_IFELSE(
+  [AC_LANG_PROGRAM(
+    [[#include <langinfo.h>]],
+    [[char c = *((unsigned char *) nl_langinfo(_NL_IDENTIFICATION_LANGUAGE));]])],
+  [nl_ok=yes],
+  [nl_ok=no])
+AC_MSG_RESULT($nl_ok)
+if test "$nl_ok" = "yes"; then
+  AC_DEFINE(HAVE__NL_IDENTIFICATION_LANGUAGE, 1,
+           [Define to 1 if _NL_IDENTIFICATION_LANGUAGE is available])
+fi
+
 # Macro to keep track of failed dependencies.
 
 required_deps=''
diff --git a/meson.build b/meson.build
index 19ff90c9d2..f29e9eacd8 100644
--- a/meson.build
+++ b/meson.build
@@ -286,6 +286,15 @@ conf.set('HAVE__NL_MEASUREMENT_MEASUREMENT',
   ''')
 )
 
+conf.set('HAVE__NL_IDENTIFICATION_LANGUAGE',
+  cc.compiles('''
+    #include<langinfo.h>
+    int main() {
+      char c = *((unsigned char *) nl_langinfo(_NL_IDENTIFICATION_LANGUAGE));
+    }
+  ''')
+)
+
 
 ################################################################################
 # Dependencies


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