1 /* Determine the user's language preferences.
2 Copyright (C) 2004-2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, or (at your option)
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 GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 /* Written by Bruno Haible <bruno@clisp.org>.
20 Win32 code originally by Michele Cicciotti <hackbunny@reactos.com>. */
28 #if HAVE_CFPREFERENCESCOPYAPPVALUE
30 # include <CoreFoundation/CFPreferences.h>
31 # include <CoreFoundation/CFPropertyList.h>
32 # include <CoreFoundation/CFArray.h>
33 # include <CoreFoundation/CFString.h>
34 extern void _nl_locale_name_canonicalize (char *name);
37 #if defined _WIN32 || defined __WIN32__
42 # define WIN32_LEAN_AND_MEAN
45 # ifndef MUI_LANGUAGE_NAME
46 # define MUI_LANGUAGE_NAME 8
48 # ifndef STATUS_BUFFER_OVERFLOW
49 # define STATUS_BUFFER_OVERFLOW 0x80000005
52 extern void _nl_locale_name_canonicalize (char *name);
53 extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid);
54 extern const char *_nl_locale_name_from_win32_LCID (LCID lcid);
56 /* Get the preferences list through the MUI APIs. This works on Windows Vista
59 _nl_language_preferences_win32_mui (HMODULE kernel32)
61 /* DWORD GetUserPreferredUILanguages (ULONG dwFlags,
62 PULONG pulNumLanguages,
63 PWSTR pwszLanguagesBuffer,
64 PULONG pcchLanguagesBuffer); */
65 typedef DWORD (WINAPI *GetUserPreferredUILanguages_func) (ULONG, PULONG, PWSTR, PULONG);
66 GetUserPreferredUILanguages_func p_GetUserPreferredUILanguages;
68 p_GetUserPreferredUILanguages =
69 (GetUserPreferredUILanguages_func)
70 GetProcAddress (kernel32, "GetUserPreferredUILanguages");
71 if (p_GetUserPreferredUILanguages != NULL)
78 ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
82 && GetLastError () == STATUS_BUFFER_OVERFLOW
85 WCHAR *buffer = (WCHAR *) malloc (bufsize * sizeof (WCHAR));
88 ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
93 /* Convert the list from NUL-delimited WCHAR[] Win32 locale
94 names to colon-delimited char[] Unix locale names.
95 We assume that all these locale names are in ASCII,
96 nonempty and contain no colons. */
98 (char *) malloc (bufsize + num_languages * 10 + 1);
99 if (languages != NULL)
101 const WCHAR *p = buffer;
104 for (i = 0; i < num_languages; i++)
113 for (; *p != (WCHAR)'\0'; p++)
115 if ((unsigned char) *p != *p || *p == ':')
117 /* A non-ASCII character or a colon inside
118 the Win32 locale name! Punt. */
122 *q++ = (unsigned char) *p;
125 /* An unexpected Win32 locale name occurred. */
128 _nl_locale_name_canonicalize (q2);
129 q = q2 + strlen (q2);
148 /* Get a preference. This works on Windows ME and newer. */
150 _nl_language_preferences_win32_ME (HMODULE kernel32)
152 /* LANGID GetUserDefaultUILanguage (void); */
153 typedef LANGID (WINAPI *GetUserDefaultUILanguage_func) (void);
154 GetUserDefaultUILanguage_func p_GetUserDefaultUILanguage;
156 p_GetUserDefaultUILanguage =
157 (GetUserDefaultUILanguage_func)
158 GetProcAddress (kernel32, "GetUserDefaultUILanguage");
159 if (p_GetUserDefaultUILanguage != NULL)
160 return _nl_locale_name_from_win32_LANGID (p_GetUserDefaultUILanguage ());
164 /* Get a preference. This works on Windows 95 and newer. */
166 _nl_language_preferences_win32_95 ()
168 HKEY desktop_resource_locale_key;
170 if (RegOpenKeyExA (HKEY_CURRENT_USER,
171 "Control Panel\\Desktop\\ResourceLocale",
172 0, KEY_QUERY_VALUE, &desktop_resource_locale_key)
177 DWORD data_size = sizeof (data);
180 ret = RegQueryValueExA (desktop_resource_locale_key, NULL, NULL,
181 &type, data, &data_size);
182 RegCloseKey (desktop_resource_locale_key);
186 /* We expect a string, at most 8 bytes long, that parses as a
187 hexadecimal number. */
189 && data_size <= sizeof (data)
190 && (data_size < sizeof (data)
191 || data[sizeof (data) - 1] == '\0'))
195 /* Ensure it's NUL terminated. */
196 if (data_size < sizeof (data))
197 data[data_size] = '\0';
198 /* Parse it as a hexadecimal number. */
199 lcid = strtoul (data, &endp, 16);
200 if (endp > data && *endp == '\0')
201 return _nl_locale_name_from_win32_LCID (lcid);
208 /* Get the system's preference. This can be used as a fallback. */
210 ret_first_language (HMODULE h, LPCSTR type, LPCSTR name, WORD lang, LONG_PTR param)
212 *(const char **)param = _nl_locale_name_from_win32_LANGID (lang);
216 _nl_language_preferences_win32_system (HMODULE kernel32)
218 const char *languages = NULL;
219 /* Ignore the warning on mingw here. mingw has a wrong definition of the last
220 parameter type of ENUMRESLANGPROC. */
221 EnumResourceLanguages (kernel32, RT_VERSION, MAKEINTRESOURCE (1),
222 ret_first_language, (LONG_PTR)&languages);
228 /* Determine the user's language preferences, as a colon separated list of
229 locale names in XPG syntax
230 language[_territory][.codeset][@modifier]
231 The result must not be freed; it is statically allocated.
232 The LANGUAGE environment variable does not need to be considered; it is
233 already taken into account by the caller. */
236 _nl_language_preferences_default (void)
238 #if HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
240 /* Cache the preferences list, since CoreFoundation calls are expensive. */
241 static const char *cached_languages;
242 static int cache_initialized;
244 if (!cache_initialized)
246 CFTypeRef preferences =
247 CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"),
248 kCFPreferencesCurrentApplication);
249 if (preferences != NULL
250 && CFGetTypeID (preferences) == CFArrayGetTypeID ())
252 CFArrayRef prefArray = (CFArrayRef)preferences;
253 int n = CFArrayGetCount (prefArray);
258 for (i = 0; i < n; i++)
260 CFTypeRef element = CFArrayGetValueAtIndex (prefArray, i);
262 && CFGetTypeID (element) == CFStringGetTypeID ()
263 && CFStringGetCString ((CFStringRef)element,
265 kCFStringEncodingASCII))
267 _nl_locale_name_canonicalize (buf);
268 size += strlen (buf) + 1;
269 /* Most GNU programs use msgids in English and don't ship
270 an en.mo message catalog. Therefore when we see "en"
271 in the preferences list, arrange for gettext() to
272 return the msgid, and ignore all further elements of
273 the preferences list. */
274 if (strcmp (buf, "en") == 0)
282 char *languages = (char *) malloc (size);
284 if (languages != NULL)
288 for (i = 0; i < n; i++)
291 CFArrayGetValueAtIndex (prefArray, i);
293 && CFGetTypeID (element) == CFStringGetTypeID ()
294 && CFStringGetCString ((CFStringRef)element,
296 kCFStringEncodingASCII))
298 _nl_locale_name_canonicalize (buf);
302 if (strcmp (buf, "en") == 0)
310 cached_languages = languages;
314 cache_initialized = 1;
316 if (cached_languages != NULL)
317 return cached_languages;
323 /* Cache the preferences list, since computing it is expensive. */
324 static const char *cached_languages;
325 static int cache_initialized;
327 /* Activate the new code only when the GETTEXT_MUI environment variable is
328 set, for the time being, since the new code is not well tested. */
329 if (!cache_initialized && getenv ("GETTEXT_MUI") != NULL)
331 const char *languages = NULL;
332 HMODULE kernel32 = GetModuleHandle ("kernel32");
334 if (kernel32 != NULL)
335 languages = _nl_language_preferences_win32_mui (kernel32);
337 if (languages == NULL && kernel32 != NULL)
338 languages = _nl_language_preferences_win32_ME (kernel32);
340 if (languages == NULL)
341 languages = _nl_language_preferences_win32_95 ();
343 if (languages == NULL && kernel32 != NULL)
344 languages = _nl_language_preferences_win32_system (kernel32);
346 cached_languages = languages;
347 cache_initialized = 1;
349 if (cached_languages != NULL)
350 return cached_languages;