1 /* Determine the user's language preferences.
2 Copyright (C) 2004-2007, 2015 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>.
18 Win32 code originally by Michele Cicciotti <hackbunny@reactos.com>. */
26 #if HAVE_CFPREFERENCESCOPYAPPVALUE
28 # include <CoreFoundation/CFPreferences.h>
29 # include <CoreFoundation/CFPropertyList.h>
30 # include <CoreFoundation/CFArray.h>
31 # include <CoreFoundation/CFString.h>
32 extern void _nl_locale_name_canonicalize (char *name);
35 #if defined _WIN32 || defined __WIN32__
40 # define WIN32_LEAN_AND_MEAN
43 # ifndef MUI_LANGUAGE_NAME
44 # define MUI_LANGUAGE_NAME 8
46 # ifndef STATUS_BUFFER_OVERFLOW
47 # define STATUS_BUFFER_OVERFLOW 0x80000005
50 extern void _nl_locale_name_canonicalize (char *name);
51 extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid);
52 extern const char *_nl_locale_name_from_win32_LCID (LCID lcid);
54 /* Get the preferences list through the MUI APIs. This works on Windows Vista
57 _nl_language_preferences_win32_mui (HMODULE kernel32)
59 /* DWORD GetUserPreferredUILanguages (ULONG dwFlags,
60 PULONG pulNumLanguages,
61 PWSTR pwszLanguagesBuffer,
62 PULONG pcchLanguagesBuffer); */
63 typedef DWORD (WINAPI *GetUserPreferredUILanguages_func) (ULONG, PULONG, PWSTR, PULONG);
64 GetUserPreferredUILanguages_func p_GetUserPreferredUILanguages;
66 p_GetUserPreferredUILanguages =
67 (GetUserPreferredUILanguages_func)
68 GetProcAddress (kernel32, "GetUserPreferredUILanguages");
69 if (p_GetUserPreferredUILanguages != NULL)
76 ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
80 && GetLastError () == STATUS_BUFFER_OVERFLOW
83 WCHAR *buffer = (WCHAR *) malloc (bufsize * sizeof (WCHAR));
86 ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
91 /* Convert the list from NUL-delimited WCHAR[] Win32 locale
92 names to colon-delimited char[] Unix locale names.
93 We assume that all these locale names are in ASCII,
94 nonempty and contain no colons. */
96 (char *) malloc (bufsize + num_languages * 10 + 1);
97 if (languages != NULL)
99 const WCHAR *p = buffer;
102 for (i = 0; i < num_languages; i++)
111 for (; *p != (WCHAR)'\0'; p++)
113 if ((unsigned char) *p != *p || *p == ':')
115 /* A non-ASCII character or a colon inside
116 the Win32 locale name! Punt. */
120 *q++ = (unsigned char) *p;
123 /* An unexpected Win32 locale name occurred. */
126 _nl_locale_name_canonicalize (q2);
127 q = q2 + strlen (q2);
146 /* Get a preference. This works on Windows ME and newer. */
148 _nl_language_preferences_win32_ME (HMODULE kernel32)
150 /* LANGID GetUserDefaultUILanguage (void); */
151 typedef LANGID (WINAPI *GetUserDefaultUILanguage_func) (void);
152 GetUserDefaultUILanguage_func p_GetUserDefaultUILanguage;
154 p_GetUserDefaultUILanguage =
155 (GetUserDefaultUILanguage_func)
156 GetProcAddress (kernel32, "GetUserDefaultUILanguage");
157 if (p_GetUserDefaultUILanguage != NULL)
158 return _nl_locale_name_from_win32_LANGID (p_GetUserDefaultUILanguage ());
162 /* Get a preference. This works on Windows 95 and newer. */
164 _nl_language_preferences_win32_95 ()
166 HKEY desktop_resource_locale_key;
168 if (RegOpenKeyExA (HKEY_CURRENT_USER,
169 "Control Panel\\Desktop\\ResourceLocale",
170 0, KEY_QUERY_VALUE, &desktop_resource_locale_key)
175 DWORD data_size = sizeof (data);
178 ret = RegQueryValueExA (desktop_resource_locale_key, NULL, NULL,
179 &type, data, &data_size);
180 RegCloseKey (desktop_resource_locale_key);
184 /* We expect a string, at most 8 bytes long, that parses as a
185 hexadecimal number. */
187 && data_size <= sizeof (data)
188 && (data_size < sizeof (data)
189 || data[sizeof (data) - 1] == '\0'))
193 /* Ensure it's NUL terminated. */
194 if (data_size < sizeof (data))
195 data[data_size] = '\0';
196 /* Parse it as a hexadecimal number. */
197 lcid = strtoul (data, &endp, 16);
198 if (endp > data && *endp == '\0')
199 return _nl_locale_name_from_win32_LCID (lcid);
206 /* Get the system's preference. This can be used as a fallback. */
208 ret_first_language (HMODULE h, LPCSTR type, LPCSTR name, WORD lang, LONG_PTR param)
210 *(const char **)param = _nl_locale_name_from_win32_LANGID (lang);
214 _nl_language_preferences_win32_system (HMODULE kernel32)
216 const char *languages = NULL;
217 /* Ignore the warning on mingw here. mingw has a wrong definition of the last
218 parameter type of ENUMRESLANGPROC. */
219 EnumResourceLanguages (kernel32, RT_VERSION, MAKEINTRESOURCE (1),
220 ret_first_language, (LONG_PTR)&languages);
226 /* Determine the user's language preferences, as a colon separated list of
227 locale names in XPG syntax
228 language[_territory][.codeset][@modifier]
229 The result must not be freed; it is statically allocated.
230 The LANGUAGE environment variable does not need to be considered; it is
231 already taken into account by the caller. */
234 _nl_language_preferences_default (void)
236 #if HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
238 /* Cache the preferences list, since CoreFoundation calls are expensive. */
239 static const char *cached_languages;
240 static int cache_initialized;
242 if (!cache_initialized)
244 CFTypeRef preferences =
245 CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"),
246 kCFPreferencesCurrentApplication);
247 if (preferences != NULL
248 && CFGetTypeID (preferences) == CFArrayGetTypeID ())
250 CFArrayRef prefArray = (CFArrayRef)preferences;
251 int n = CFArrayGetCount (prefArray);
256 for (i = 0; i < n; i++)
258 CFTypeRef element = CFArrayGetValueAtIndex (prefArray, i);
260 && CFGetTypeID (element) == CFStringGetTypeID ()
261 && CFStringGetCString ((CFStringRef)element,
263 kCFStringEncodingASCII))
265 _nl_locale_name_canonicalize (buf);
266 size += strlen (buf) + 1;
267 /* Most GNU programs use msgids in English and don't ship
268 an en.mo message catalog. Therefore when we see "en"
269 in the preferences list, arrange for gettext() to
270 return the msgid, and ignore all further elements of
271 the preferences list. */
272 if (strcmp (buf, "en") == 0)
280 char *languages = (char *) malloc (size);
282 if (languages != NULL)
286 for (i = 0; i < n; i++)
289 CFArrayGetValueAtIndex (prefArray, i);
291 && CFGetTypeID (element) == CFStringGetTypeID ()
292 && CFStringGetCString ((CFStringRef)element,
294 kCFStringEncodingASCII))
296 _nl_locale_name_canonicalize (buf);
300 if (strcmp (buf, "en") == 0)
308 cached_languages = languages;
312 cache_initialized = 1;
314 if (cached_languages != NULL)
315 return cached_languages;
321 /* Cache the preferences list, since computing it is expensive. */
322 static const char *cached_languages;
323 static int cache_initialized;
325 /* Activate the new code only when the GETTEXT_MUI environment variable is
326 set, for the time being, since the new code is not well tested. */
327 if (!cache_initialized && getenv ("GETTEXT_MUI") != NULL)
329 const char *languages = NULL;
330 HMODULE kernel32 = GetModuleHandle ("kernel32");
332 if (kernel32 != NULL)
333 languages = _nl_language_preferences_win32_mui (kernel32);
335 if (languages == NULL && kernel32 != NULL)
336 languages = _nl_language_preferences_win32_ME (kernel32);
338 if (languages == NULL)
339 languages = _nl_language_preferences_win32_95 ();
341 if (languages == NULL && kernel32 != NULL)
342 languages = _nl_language_preferences_win32_system (kernel32);
344 cached_languages = languages;
345 cache_initialized = 1;
347 if (cached_languages != NULL)
348 return cached_languages;