OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "base/win/i18n.h" | |
6 | |
7 #include <windows.h> | |
8 | |
9 #include "base/logging.h" | |
10 | |
11 namespace { | |
12 | |
13 // Keep this enum in sync with kLanguageFunctionNames. | |
14 enum LanguageFunction { | |
15 SYSTEM_LANGUAGES, | |
16 USER_LANGUAGES, | |
17 PROCESS_LANGUAGES, | |
18 THREAD_LANGUAGES, | |
19 NUM_FUNCTIONS | |
20 }; | |
21 | |
22 const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages"; | |
23 const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages"; | |
24 const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages"; | |
25 const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages"; | |
26 | |
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] | |
33 }; | |
34 | |
35 COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames), | |
36 language_function_enum_and_names_out_of_sync); | |
37 | |
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 | |
42 // |languages|. | |
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))); | |
47 DCHECK(languages); | |
48 | |
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, | |
61 &buffer_length) && | |
62 0 != buffer_length) { | |
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); | |
68 return true; | |
69 } else { | |
70 DPCHECK(0 == language_count) | |
71 << "Failed getting preferred UI languages."; | |
72 } | |
73 } else { | |
74 DPCHECK(0 == buffer_length) | |
75 << "Failed getting size of preferred UI languages."; | |
76 } | |
77 } else { | |
78 DVLOG(2) << "MUI not available."; | |
79 } | |
80 } else { | |
81 NOTREACHED() << "kernel32.dll not found."; | |
82 } | |
83 | |
84 return false; | |
85 } | |
86 | |
87 bool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) { | |
88 DCHECK(language); | |
89 | |
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]; | |
95 int result_length = | |
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); | |
101 region->clear(); | |
102 if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) { | |
103 result_length = | |
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); | |
109 } | |
110 return true; | |
111 } | |
112 } else { | |
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."; | |
116 } | |
117 return false; | |
118 } | |
119 | |
120 bool GetPreferredUILanguageList(LanguageFunction function, ULONG flags, | |
121 std::vector<std::wstring>* languages) { | |
122 std::vector<wchar_t> buffer; | |
123 std::wstring language; | |
124 std::wstring region; | |
125 | |
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); | |
133 } | |
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"). | |
137 if (!region.empty()) | |
138 languages->push_back(std::wstring(language) | |
139 .append(1, L'-') | |
140 .append(region)); | |
141 languages->push_back(language); | |
142 } else { | |
143 return false; | |
144 } | |
145 | |
146 return true; | |
147 } | |
148 | |
149 } // namespace | |
150 | |
151 namespace base { | |
152 namespace win { | |
153 namespace i18n { | |
154 | |
155 bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) { | |
156 DCHECK(languages); | |
157 return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages); | |
158 } | |
159 | |
160 bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) { | |
161 DCHECK(languages); | |
162 return GetPreferredUILanguageList( | |
163 THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, | |
164 languages); | |
165 } | |
166 | |
167 } // namespace i18n | |
168 } // namespace win | |
169 } // namespace base | |
OLD | NEW |