]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
New routines for determining the language preferences under Windows.
authorBruno Haible <bruno@clisp.org>
Wed, 26 Dec 2007 16:07:05 +0000 (16:07 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:15:35 +0000 (12:15 +0200)
gettext-runtime/intl/ChangeLog
gettext-runtime/intl/gettextP.h
gettext-runtime/intl/langprefs.c
gettext-runtime/intl/localename.c

index b436af6278270fb45162884d51ba84bfec77180e..e79f02ee983ec55209e0dadb21aaaca91006ef0a 100644 (file)
@@ -1,3 +1,21 @@
+2007-12-25  KJK::Hyperion  <hackbunny@reactos.com>
+            Bruno Haible  <bruno@clisp.org>
+
+       * gettextP.h (gl_locale_name_from_win32_LANGID,
+       gl_locale_name_from_win32_LCID): New macros.
+       * localename.c (gl_locale_name_canonicalize) [WIN32_NATIVE]: New
+       function.
+       (gl_locale_name_from_win32_LANGID, gl_locale_name_from_win32_LCID):
+       New functions, mostly extracted from gl_locale_name_default.
+       (gl_locale_name_default): Use gl_locale_name_from_win32_LCID.
+       * langprefs.c [WIN32_NATIVE] (_nl_locale_name_canonicalize,
+       _nl_locale_name_from_win32_LANGID, _nl_locale_name_from_win32_LCID):
+       New declarations.
+       (_nl_language_preferences_win32_mui, _nl_language_preferences_win32_ME,
+       _nl_language_preferences_win32_95, ret_first_language,
+       _nl_language_preferences_win32_system): New functions.
+       (_nl_language_preferences_default): Use them.
+
 2007-11-30  Bruno Haible  <bruno@clisp.org>
 
        * lock.h (gl_recursive_lock_init) [PTHREAD &&
index 5706fb505618dcc600ca501bc0652edf41fa9d84..39af4a7704055acf695d4e6d9a0aec90c17f6773 100644 (file)
@@ -231,6 +231,10 @@ extern LIBINTL_DLL_EXPORTED int _nl_msg_cat_cntr;
 extern const char *_nl_language_preferences_default (void);
 # define gl_locale_name_canonicalize _nl_locale_name_canonicalize
 extern void _nl_locale_name_canonicalize (char *name);
+# define gl_locale_name_from_win32_LANGID _nl_locale_name_from_win32_LANGID
+/* extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid); */
+# define gl_locale_name_from_win32_LCID _nl_locale_name_from_win32_LCID
+/* extern const char *_nl_locale_name_from_win32_LCID (LCID lcid); */
 # define gl_locale_name_posix _nl_locale_name_posix
 extern const char *_nl_locale_name_posix (int category,
                                          const char *categoryname);
index 59c8def215e895e4a2d8d3bbdbe87b9ab225b45e..847a94aff7eb88734ee8013faaefe8a3f55727d0 100644 (file)
@@ -1,5 +1,5 @@
 /* Determine the user's language preferences.
-   Copyright (C) 2004-2006 Free Software Foundation, Inc.
+   Copyright (C) 2004-2007 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published
@@ -16,7 +16,8 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
    USA.  */
 
-/* Written by Bruno Haible <bruno@clisp.org>.  */
+/* Written by Bruno Haible <bruno@clisp.org>.
+   Win32 code originally by Michele Cicciotti <hackbunny@reactos.com>.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 extern void _nl_locale_name_canonicalize (char *name);
 #endif
 
+#if defined _WIN32 || defined __WIN32__
+# define WIN32_NATIVE
+#endif
+
+#ifdef WIN32_NATIVE
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+# ifndef MUI_LANGUAGE_NAME
+# define MUI_LANGUAGE_NAME 8
+# endif
+# ifndef STATUS_BUFFER_OVERFLOW
+# define STATUS_BUFFER_OVERFLOW 0x80000005
+# endif
+
+extern void _nl_locale_name_canonicalize (char *name);
+extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid);
+extern const char *_nl_locale_name_from_win32_LCID (LCID lcid);
+
+/* Get the preferences list through the MUI APIs. This works on Windows Vista
+   and newer.  */
+static const char *
+_nl_language_preferences_win32_mui (HMODULE kernel32)
+{
+  /* DWORD GetUserPreferredUILanguages (ULONG dwFlags,
+                                       PULONG pulNumLanguages,
+                                       PWSTR pwszLanguagesBuffer,
+                                       PULONG pcchLanguagesBuffer);  */
+  typedef DWORD (WINAPI *GetUserPreferredUILanguages_func) (ULONG, PULONG, PWSTR, PULONG);
+  GetUserPreferredUILanguages_func p_GetUserPreferredUILanguages;
+
+  p_GetUserPreferredUILanguages =
+   (GetUserPreferredUILanguages_func)
+   GetProcAddress (kernel32, "GetUserPreferredUILanguages");
+  if (p_GetUserPreferredUILanguages != NULL)
+    {
+      ULONG num_languages;
+      ULONG bufsize;
+      DWORD ret;
+
+      bufsize = 0;
+      ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
+                                          &num_languages,
+                                          NULL, &bufsize);
+      if (ret == 0
+         && GetLastError () == STATUS_BUFFER_OVERFLOW
+         && bufsize > 0)
+       {
+         WCHAR *buffer = (WCHAR *) malloc (bufsize * sizeof (WCHAR));
+         if (buffer != NULL)
+           {
+             ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
+                                                  &num_languages,
+                                                  buffer, &bufsize);
+             if (ret)
+               {
+                 /* Convert the list from NUL-delimited WCHAR[] Win32 locale
+                    names to colon-delimited char[] Unix locale names.
+                    We assume that all these locale names are in ASCII,
+                    nonempty and contain no colons.  */
+                 char *languages =
+                   (char *) malloc (bufsize + num_languages * 10 + 1);
+                 if (languages != NULL)
+                   {
+                     const WCHAR *p = buffer;
+                     char *q = languages;
+                     ULONG i;
+                     for (i = 0; i < num_languages; i++)
+                       {
+                         char *q1;
+                         char *q2;
+
+                         q1 = q;
+                         if (i > 0)
+                           *q++ = ':';
+                         q2 = q;
+                         for (; *p != (WCHAR)'\0'; p++)
+                           {
+                             if ((unsigned char) *p != *p || *p == ':')
+                               {
+                                 /* A non-ASCII character or a colon inside
+                                    the Win32 locale name! Punt.  */
+                                 q = q1;
+                                 break;
+                               }
+                             *q++ = (unsigned char) *p;
+                           }
+                         if (q == q1)
+                           /* An unexpected Win32 locale name occurred.  */
+                           break;
+                         *q = '\0';
+                         _nl_locale_name_canonicalize (q2);
+                         q = q2 + strlen (q2);
+                         p++;
+                       }
+                     *q = '\0';
+                     if (q > languages)
+                       {
+                         free (buffer);
+                         return languages;
+                       }
+                     free (languages);
+                   }
+               }
+             free (buffer);
+           }
+       }
+    }
+  return NULL;
+}
+
+/* Get a preference.  This works on Windows ME and newer.  */
+static const char *
+_nl_language_preferences_win32_ME (HMODULE kernel32)
+{
+  /* LANGID GetUserDefaultUILanguage (void);  */
+  typedef LANGID (WINAPI *GetUserDefaultUILanguage_func) (void);
+  GetUserDefaultUILanguage_func p_GetUserDefaultUILanguage;
+
+  p_GetUserDefaultUILanguage =
+   (GetUserDefaultUILanguage_func)
+   GetProcAddress (kernel32, "GetUserDefaultUILanguage");
+  if (p_GetUserDefaultUILanguage != NULL)
+    return _nl_locale_name_from_win32_LANGID (p_GetUserDefaultUILanguage ());
+  return NULL;
+}
+
+/* Get a preference.  This works on Windows 95 and newer.  */
+static const char *
+_nl_language_preferences_win32_95 ()
+{
+  HKEY desktop_resource_locale_key;
+
+  if (RegOpenKeyExA (HKEY_CURRENT_USER,
+                    "Control Panel\\Desktop\\ResourceLocale",
+                    0, KEY_QUERY_VALUE, &desktop_resource_locale_key)
+      == NO_ERROR)
+    {
+      DWORD type;
+      char data[8 + 1];
+      DWORD data_size = sizeof (data);
+      DWORD ret;
+
+      ret = RegQueryValueExA (desktop_resource_locale_key, NULL, NULL,
+                             &type, data, &data_size);
+      RegCloseKey (desktop_resource_locale_key);
+
+      if (ret == NO_ERROR)
+        {
+         /* We expect a string, at most 8 bytes long, that parses as a
+            hexadecimal number.  */
+         if (type == REG_SZ
+             && data_size <= sizeof (data)
+             && (data_size < sizeof (data)
+                 || data[sizeof (data) - 1] == '\0'))
+           {
+             LCID lcid;
+             char *endp;
+             /* Ensure it's NUL terminated.  */
+             if (data_size < sizeof (data))
+               data[data_size] = '\0';
+             /* Parse it as a hexadecimal number.  */
+             lcid = strtoul (data, &endp, 16);
+             if (endp > data && *endp == '\0')
+               return _nl_locale_name_from_win32_LCID (lcid);
+           }
+       }
+    }
+  return NULL;
+}
+
+/* Get the system's preference.  This can be used as a fallback.  */
+static BOOL CALLBACK
+ret_first_language (HMODULE h, LPCSTR type, LPCSTR name, WORD lang, LONG_PTR param)
+{
+  *(const char **)param = _nl_locale_name_from_win32_LANGID (lang);
+  return FALSE;
+}
+static const char *
+_nl_language_preferences_win32_system (HMODULE kernel32)
+{
+  const char *languages = NULL;
+  /* Ignore the warning on mingw here. mingw has a wrong definition of the last
+     parameter type of ENUMRESLANGPROC.  */
+  EnumResourceLanguages (kernel32, RT_VERSION, MAKEINTRESOURCE (1),
+                        ret_first_language, (LONG_PTR)&languages);
+  return languages;
+}
+
+#endif
+
 /* Determine the user's language preferences, as a colon separated list of
    locale names in XPG syntax
      language[_territory][.codeset][@modifier]
@@ -126,5 +318,38 @@ _nl_language_preferences_default (void)
   }
 #endif
 
+#ifdef WIN32_NATIVE
+  {
+    /* Cache the preferences list, since computing it is expensive.  */
+    static const char *cached_languages;
+    static int cache_initialized;
+
+    /* Activate the new code only when the GETTEXT_MUI environment variable is
+       set, for the time being, since the new code is not well tested.  */
+    if (!cache_initialized && getenv ("GETTEXT_MUI") != NULL)
+      {
+       const char *languages = NULL;
+       HMODULE kernel32 = GetModuleHandle ("kernel32");
+
+       if (kernel32 != NULL)
+         languages = _nl_language_preferences_win32_mui (kernel32);
+
+       if (languages == NULL && kernel32 != NULL)
+         languages = _nl_language_preferences_win32_ME (kernel32);
+
+       if (languages == NULL)
+         languages = _nl_language_preferences_win32_95 ();
+
+       if (languages == NULL && kernel32 != NULL)
+         languages = _nl_language_preferences_win32_system (kernel32);
+
+       cached_languages = languages;
+       cache_initialized = 1;
+      }
+    if (cached_languages != NULL)
+      return cached_languages;
+  }
+#endif
+
   return NULL;
 }
index af4c229a3094e6281deaee89c7b2151a8fcf6107..8e213461c075943e87487094d70412f41b0283fe 100644 (file)
 # ifndef SUBLANG_UZBEK_CYRILLIC
 # define SUBLANG_UZBEK_CYRILLIC 0x02
 # endif
+/* GetLocaleInfoA operations.  */
+# ifndef LOCALE_SNAME
+# define LOCALE_SNAME 0x5c
+# endif
 #endif
 
-# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
+
+#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
 /* MacOS X 10.2 or newer */
 
 /* Canonicalize a MacOS X locale name to a Unix locale name.
    NAME is a sufficiently large buffer.
    On input, it contains the MacOS X locale name.
    On output, it contains the Unix locale name.  */
-#  if !defined IN_LIBINTL
+# if !defined IN_LIBINTL
 static
-#  endif
+# endif
 void
 gl_locale_name_canonicalize (char *name)
 {
@@ -975,127 +980,74 @@ gl_locale_name_canonicalize (char *name)
 
 #endif
 
-/* XPG3 defines the result of 'setlocale (category, NULL)' as:
-   "Directs 'setlocale()' to query 'category' and return the current
-    setting of 'local'."
-   However it does not specify the exact format.  Neither do SUSV2 and
-   ISO C 99.  So we can use this feature only on selected systems (e.g.
-   those using GNU C Library).  */
-#if defined _LIBC || (defined __GLIBC__ && __GLIBC__ >= 2)
-# define HAVE_LOCALE_NULL
-#endif
-
-/* Determine the current locale's name, and canonicalize it into XPG syntax
-     language[_territory][.codeset][@modifier]
-   The codeset part in the result is not reliable; the locale_charset()
-   should be used for codeset information instead.
-   The result must not be freed; it is statically allocated.  */
-
-const char *
-gl_locale_name_posix (int category, const char *categoryname)
-{
-  /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
-     On some systems this can be done by the 'setlocale' function itself.  */
-#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
-  return setlocale (category, NULL);
-#else
-  const char *retval;
-
-  /* Setting of LC_ALL overrides all other.  */
-  retval = getenv ("LC_ALL");
-  if (retval != NULL && retval[0] != '\0')
-    return retval;
-  /* Next comes the name of the desired category.  */
-  retval = getenv (categoryname);
-  if (retval != NULL && retval[0] != '\0')
-    return retval;
-  /* Last possibility is the LANG environment variable.  */
-  retval = getenv ("LANG");
-  if (retval != NULL && retval[0] != '\0')
-    return retval;
 
-  return NULL;
-#endif
-}
+#ifdef WIN32_NATIVE
 
-const char *
-gl_locale_name_default (void)
+/* Canonicalize a Win32 native locale name to a Unix locale name.
+   NAME is a sufficiently large buffer.
+   On input, it contains the Win32 locale name.
+   On output, it contains the Unix locale name.  */
+# if !defined IN_LIBINTL
+static
+# endif
+void
+gl_locale_name_canonicalize (char *name)
 {
-  /* POSIX:2001 says:
-     "All implementations shall define a locale as the default locale, to be
-      invoked when no environment variables are set, or set to the empty
-      string.  This default locale can be the POSIX locale or any other
-      implementation-defined locale.  Some implementations may provide
-      facilities for local installation administrators to set the default
-      locale, customizing it for each location.  POSIX:2001 does not require
-      such a facility.  */
+  /* FIXME: This is probably incomplete: it does not handle "zh-Hans" and
+     "zh-Hant".  */
+  char *p;
 
-#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined(WIN32_NATIVE))
-
-  /* The system does not have a way of setting the locale, other than the
-     POSIX specified environment variables.  We use C as default locale.  */
-  return "C";
-
-#else
-
-  /* Return an XPG style locale name language[_territory][@modifier].
-     Don't even bother determining the codeset; it's not useful in this
-     context, because message catalogs are not specific to a single
-     codeset.  */
-
-# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
-  /* MacOS X 10.2 or newer */
-  {
-    /* Cache the locale name, since CoreFoundation calls are expensive.  */
-    static const char *cached_localename;
-
-    if (cached_localename == NULL)
+  for (p = name; *p != '\0'; p++)
+    if (*p == '-')
       {
-       char namebuf[256];
-#  if HAVE_CFLOCALECOPYCURRENT /* MacOS X 10.3 or newer */
-       CFLocaleRef locale = CFLocaleCopyCurrent ();
-       CFStringRef name = CFLocaleGetIdentifier (locale);
-
-       if (CFStringGetCString (name, namebuf, sizeof(namebuf),
-                               kCFStringEncodingASCII))
-         {
-           gl_locale_name_canonicalize (namebuf);
-           cached_localename = strdup (namebuf);
-         }
-       CFRelease (locale);
-#  elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
-       CFTypeRef value =
-         CFPreferencesCopyAppValue (CFSTR ("AppleLocale"),
-                                    kCFPreferencesCurrentApplication);
-       if (value != NULL
-           && CFGetTypeID (value) == CFStringGetTypeID ()
-           && CFStringGetCString ((CFStringRef)value, namebuf, sizeof(namebuf),
-                                  kCFStringEncodingASCII))
+       *p = '_';
+       p++;
+       for (; *p != '\0'; p++)
          {
-           gl_locale_name_canonicalize (namebuf);
-           cached_localename = strdup (namebuf);
+           if (*p >= 'a' && *p <= 'z')
+             *p += 'A' - 'a';
+           if (*p == '-')
+             {
+               *p = '\0';
+               return;
+             }
          }
-#  endif
-       if (cached_localename == NULL)
-         cached_localename = "C";
+       return;
       }
-    return cached_localename;
-  }
+}
 
+# if !defined IN_LIBINTL
+static
 # endif
+const char *
+gl_locale_name_from_win32_LANGID (LANGID langid)
+{
+  /* Activate the new code only when the GETTEXT_MUI environment variable is
+     set, for the time being, since the new code is not well tested.  */
+  if (getenv ("GETTEXT_MUI") != NULL)
+    {
+      static char namebuf[256];
 
-# if defined(WIN32_NATIVE) /* WIN32, not Cygwin */
+      /* Query the system's notion of locale name.
+        On Windows95/98/ME, GetLocaleInfoA returns some incorrect results.
+        But we don't need to support systems that are so old.  */
+      if (GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT), LOCALE_SNAME,
+                         namebuf, sizeof (namebuf) - 1))
+       {
+         /* Convert it to a Unix locale name.  */
+         gl_locale_name_canonicalize (namebuf);
+         return namebuf;
+       }
+    }
+  /* Internet Explorer has an LCID to RFC3066 name mapping stored in
+     HKEY_CLASSES_ROOT\Mime\Database\Rfc1766.  But we better don't use that
+     since IE's i18n subsystem is known to be inconsistent with the Win32 base
+     (e.g. they have different character conversion facilities that produce
+     different results).  */
+  /* Use our own table.  */
   {
-    LCID lcid;
-    LANGID langid;
     int primary, sub;
 
-    /* Use native Win32 API locale ID.  */
-    lcid = GetThreadLocale ();
-
-    /* Strip off the sorting rules, keep only the language part.  */
-    langid = LANGIDFROMLCID (lcid);
-
     /* Split into language and territory part.  */
     primary = PRIMARYLANGID (langid);
     sub = SUBLANGID (langid);
@@ -1490,6 +1442,143 @@ gl_locale_name_default (void)
       default: return "C";
       }
   }
+}
+
+# if !defined IN_LIBINTL
+static
+# endif
+const char *
+gl_locale_name_from_win32_LCID (LCID lcid)
+{
+  LANGID langid;
+
+  /* Strip off the sorting rules, keep only the language part.  */
+  langid = LANGIDFROMLCID (lcid);
+
+  return gl_locale_name_from_win32_LANGID (langid);
+}
+
+#endif
+
+
+/* XPG3 defines the result of 'setlocale (category, NULL)' as:
+   "Directs 'setlocale()' to query 'category' and return the current
+    setting of 'local'."
+   However it does not specify the exact format.  Neither do SUSV2 and
+   ISO C 99.  So we can use this feature only on selected systems (e.g.
+   those using GNU C Library).  */
+#if defined _LIBC || (defined __GLIBC__ && __GLIBC__ >= 2)
+# define HAVE_LOCALE_NULL
+#endif
+
+/* Determine the current locale's name, and canonicalize it into XPG syntax
+     language[_territory][.codeset][@modifier]
+   The codeset part in the result is not reliable; the locale_charset()
+   should be used for codeset information instead.
+   The result must not be freed; it is statically allocated.  */
+
+const char *
+gl_locale_name_posix (int category, const char *categoryname)
+{
+  /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
+     On some systems this can be done by the 'setlocale' function itself.  */
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
+  return setlocale (category, NULL);
+#else
+  const char *retval;
+
+  /* Setting of LC_ALL overrides all other.  */
+  retval = getenv ("LC_ALL");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+  /* Next comes the name of the desired category.  */
+  retval = getenv (categoryname);
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+  /* Last possibility is the LANG environment variable.  */
+  retval = getenv ("LANG");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  return NULL;
+#endif
+}
+
+const char *
+gl_locale_name_default (void)
+{
+  /* POSIX:2001 says:
+     "All implementations shall define a locale as the default locale, to be
+      invoked when no environment variables are set, or set to the empty
+      string.  This default locale can be the POSIX locale or any other
+      implementation-defined locale.  Some implementations may provide
+      facilities for local installation administrators to set the default
+      locale, customizing it for each location.  POSIX:2001 does not require
+      such a facility.  */
+
+#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined(WIN32_NATIVE))
+
+  /* The system does not have a way of setting the locale, other than the
+     POSIX specified environment variables.  We use C as default locale.  */
+  return "C";
+
+#else
+
+  /* Return an XPG style locale name language[_territory][@modifier].
+     Don't even bother determining the codeset; it's not useful in this
+     context, because message catalogs are not specific to a single
+     codeset.  */
+
+# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
+  /* MacOS X 10.2 or newer */
+  {
+    /* Cache the locale name, since CoreFoundation calls are expensive.  */
+    static const char *cached_localename;
+
+    if (cached_localename == NULL)
+      {
+       char namebuf[256];
+#  if HAVE_CFLOCALECOPYCURRENT /* MacOS X 10.3 or newer */
+       CFLocaleRef locale = CFLocaleCopyCurrent ();
+       CFStringRef name = CFLocaleGetIdentifier (locale);
+
+       if (CFStringGetCString (name, namebuf, sizeof(namebuf),
+                               kCFStringEncodingASCII))
+         {
+           gl_locale_name_canonicalize (namebuf);
+           cached_localename = strdup (namebuf);
+         }
+       CFRelease (locale);
+#  elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
+       CFTypeRef value =
+         CFPreferencesCopyAppValue (CFSTR ("AppleLocale"),
+                                    kCFPreferencesCurrentApplication);
+       if (value != NULL
+           && CFGetTypeID (value) == CFStringGetTypeID ()
+           && CFStringGetCString ((CFStringRef)value, namebuf, sizeof(namebuf),
+                                  kCFStringEncodingASCII))
+         {
+           gl_locale_name_canonicalize (namebuf);
+           cached_localename = strdup (namebuf);
+         }
+#  endif
+       if (cached_localename == NULL)
+         cached_localename = "C";
+      }
+    return cached_localename;
+  }
+
+# endif
+
+# if defined(WIN32_NATIVE) /* WIN32, not Cygwin */
+  {
+    LCID lcid;
+
+    /* Use native Win32 API locale ID.  */
+    lcid = GetThreadLocale ();
+
+    return gl_locale_name_from_win32_LCID (lcid);
+  }
 # endif
 #endif
 }