1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/win/i18n.h"
9 #include "base/logging.h"
13 // Keep this enum in sync with kLanguageFunctionNames.
14 enum LanguageFunction
{
22 const char kSystemLanguagesFunctionName
[] = "GetSystemPreferredUILanguages";
23 const char kUserLanguagesFunctionName
[] = "GetUserPreferredUILanguages";
24 const char kProcessLanguagesFunctionName
[] = "GetProcessPreferredUILanguages";
25 const char kThreadLanguagesFunctionName
[] = "GetThreadPreferredUILanguages";
27 // Keep this array in sync with enum LanguageFunction.
28 const char *const kLanguageFunctionNames
[] = {
29 &kSystemLanguagesFunctionName
[0],
30 &kUserLanguagesFunctionName
[0],
31 &kProcessLanguagesFunctionName
[0],
32 &kThreadLanguagesFunctionName
[0]
35 COMPILE_ASSERT(NUM_FUNCTIONS
== arraysize(kLanguageFunctionNames
),
36 language_function_enum_and_names_out_of_sync
);
38 // Calls one of the MUI Get*PreferredUILanguages functions, placing the result
39 // in |languages|. |function| identifies the function to call and |flags| is
40 // the function-specific flags (callers must not specify MUI_LANGUAGE_ID or
41 // MUI_LANGUAGE_NAME). Returns true if at least one language is placed in
43 bool GetMUIPreferredUILanguageList(LanguageFunction function
, ULONG flags
,
44 std::vector
<wchar_t>* languages
) {
45 DCHECK(0 <= function
&& NUM_FUNCTIONS
> function
);
46 DCHECK_EQ(0U, (flags
& (MUI_LANGUAGE_ID
| MUI_LANGUAGE_NAME
)));
49 HMODULE kernel32
= GetModuleHandle(L
"kernel32.dll");
50 if (NULL
!= kernel32
) {
51 typedef BOOL (WINAPI
* GetPreferredUILanguages_Fn
)(
52 DWORD
, PULONG
, PZZWSTR
, PULONG
);
53 GetPreferredUILanguages_Fn get_preferred_ui_languages
=
54 reinterpret_cast<GetPreferredUILanguages_Fn
>(
55 GetProcAddress(kernel32
, kLanguageFunctionNames
[function
]));
56 if (NULL
!= get_preferred_ui_languages
) {
57 const ULONG call_flags
= flags
| MUI_LANGUAGE_NAME
;
58 ULONG language_count
= 0;
59 ULONG buffer_length
= 0;
60 if (get_preferred_ui_languages(call_flags
, &language_count
, NULL
,
63 languages
->resize(buffer_length
);
64 if (get_preferred_ui_languages(call_flags
, &language_count
,
65 &(*languages
)[0], &buffer_length
) &&
66 0 != language_count
) {
67 DCHECK(languages
->size() == buffer_length
);
70 DPCHECK(0 == language_count
)
71 << "Failed getting preferred UI languages.";
74 DPCHECK(0 == buffer_length
)
75 << "Failed getting size of preferred UI languages.";
78 DVLOG(2) << "MUI not available.";
81 NOTREACHED() << "kernel32.dll not found.";
87 bool GetUserDefaultUILanguage(std::wstring
* language
, std::wstring
* region
) {
90 LANGID lang_id
= ::GetUserDefaultUILanguage();
91 if (LOCALE_CUSTOM_UI_DEFAULT
!= lang_id
) {
92 const LCID locale_id
= MAKELCID(lang_id
, SORT_DEFAULT
);
93 // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9
94 wchar_t result_buffer
[9];
96 GetLocaleInfo(locale_id
, LOCALE_SISO639LANGNAME
, &result_buffer
[0],
97 arraysize(result_buffer
));
98 DPCHECK(0 != result_length
) << "Failed getting language id";
99 if (1 < result_length
) {
100 language
->assign(&result_buffer
[0], result_length
- 1);
102 if (SUBLANG_NEUTRAL
!= SUBLANGID(lang_id
)) {
104 GetLocaleInfo(locale_id
, LOCALE_SISO3166CTRYNAME
, &result_buffer
[0],
105 arraysize(result_buffer
));
106 DPCHECK(0 != result_length
) << "Failed getting region id";
107 if (1 < result_length
)
108 region
->assign(&result_buffer
[0], result_length
- 1);
113 // This is entirely unexpected on pre-Vista, which is the only time we
114 // should try GetUserDefaultUILanguage anyway.
115 NOTREACHED() << "Cannot determine language for a supplemental locale.";
120 bool GetPreferredUILanguageList(LanguageFunction function
, ULONG flags
,
121 std::vector
<std::wstring
>* languages
) {
122 std::vector
<wchar_t> buffer
;
123 std::wstring language
;
126 if (GetMUIPreferredUILanguageList(function
, flags
, &buffer
)) {
127 std::vector
<wchar_t>::const_iterator scan
= buffer
.begin();
128 language
.assign(&*scan
);
129 while (!language
.empty()) {
130 languages
->push_back(language
);
131 scan
+= language
.size() + 1;
132 language
.assign(&*scan
);
134 } else if (GetUserDefaultUILanguage(&language
, ®ion
)) {
135 // Mimic the MUI behavior of putting the neutral version of the lang after
136 // the regional one (e.g., "fr-CA, fr").
138 languages
->push_back(std::wstring(language
)
141 languages
->push_back(language
);
155 bool GetUserPreferredUILanguageList(std::vector
<std::wstring
>* languages
) {
157 return GetPreferredUILanguageList(USER_LANGUAGES
, 0, languages
);
160 bool GetThreadPreferredUILanguageList(std::vector
<std::wstring
>* languages
) {
162 return GetPreferredUILanguageList(
163 THREAD_LANGUAGES
, MUI_MERGE_SYSTEM_FALLBACK
| MUI_MERGE_USER_FALLBACK
,