• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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|.
GetMUIPreferredUILanguageList(LanguageFunction function,ULONG flags,std::vector<wchar_t> * 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       VLOG(2) << "MUI not available.";
79     }
80   } else {
81     NOTREACHED() << "kernel32.dll not found.";
82   }
83 
84   return false;
85 }
86 
GetUserDefaultUILanguage(std::wstring * language,std::wstring * region)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 
GetPreferredUILanguageList(LanguageFunction function,ULONG flags,std::vector<std::wstring> * languages)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, &region)) {
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 
GetUserPreferredUILanguageList(std::vector<std::wstring> * languages)155 bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
156   DCHECK(languages);
157   return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages);
158 }
159 
GetThreadPreferredUILanguageList(std::vector<std::wstring> * languages)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
170