14a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 24a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 34a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// found in the LICENSE file. 44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/win/i18n.h" 64a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <windows.h> 84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/logging.h" 104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace { 124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Keep this enum in sync with kLanguageFunctionNames. 144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochenum LanguageFunction { 154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SYSTEM_LANGUAGES, 164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch USER_LANGUAGES, 174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch PROCESS_LANGUAGES, 184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch THREAD_LANGUAGES, 194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NUM_FUNCTIONS 204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}; 214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages"; 234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages"; 244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages"; 254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages"; 264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Keep this array in sync with enum LanguageFunction. 284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char *const kLanguageFunctionNames[] = { 294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &kSystemLanguagesFunctionName[0], 304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &kUserLanguagesFunctionName[0], 314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &kProcessLanguagesFunctionName[0], 324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &kThreadLanguagesFunctionName[0] 334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}; 344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochCOMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames), 364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch language_function_enum_and_names_out_of_sync); 374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Calls one of the MUI Get*PreferredUILanguages functions, placing the result 394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// in |languages|. |function| identifies the function to call and |flags| is 404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or 414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// MUI_LANGUAGE_NAME). Returns true if at least one language is placed in 424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// |languages|. 434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags, 444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::vector<wchar_t>* languages) { 454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(0 <= function && NUM_FUNCTIONS > function); 464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME))); 474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(languages); 484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); 504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (NULL != kernel32) { 514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)( 524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DWORD, PULONG, PZZWSTR, PULONG); 534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GetPreferredUILanguages_Fn get_preferred_ui_languages = 544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch reinterpret_cast<GetPreferredUILanguages_Fn>( 554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GetProcAddress(kernel32, kLanguageFunctionNames[function])); 564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (NULL != get_preferred_ui_languages) { 574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const ULONG call_flags = flags | MUI_LANGUAGE_NAME; 584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ULONG language_count = 0; 594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ULONG buffer_length = 0; 604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (get_preferred_ui_languages(call_flags, &language_count, NULL, 614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &buffer_length) && 624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 0 != buffer_length) { 634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch languages->resize(buffer_length); 644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (get_preferred_ui_languages(call_flags, &language_count, 654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &(*languages)[0], &buffer_length) && 664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 0 != language_count) { 674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(languages->size() == buffer_length); 684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return true; 694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DPCHECK(0 == language_count) 714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch << "Failed getting preferred UI languages."; 724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DPCHECK(0 == buffer_length) 754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch << "Failed getting size of preferred UI languages."; 764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch VLOG(2) << "MUI not available."; 794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NOTREACHED() << "kernel32.dll not found."; 824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) { 884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(language); 894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch LANGID lang_id = ::GetUserDefaultUILanguage(); 914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) { 924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT); 934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9 944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch wchar_t result_buffer[9]; 954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int result_length = 964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &result_buffer[0], 974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch arraysize(result_buffer)); 984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DPCHECK(0 != result_length) << "Failed getting language id"; 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (1 < result_length) { 1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch language->assign(&result_buffer[0], result_length - 1); 1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch region->clear(); 1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) { 1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch result_length = 1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &result_buffer[0], 1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch arraysize(result_buffer)); 1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DPCHECK(0 != result_length) << "Failed getting region id"; 1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (1 < result_length) 1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch region->assign(&result_buffer[0], result_length - 1); 1094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return true; 1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // This is entirely unexpected on pre-Vista, which is the only time we 1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // should try GetUserDefaultUILanguage anyway. 1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NOTREACHED() << "Cannot determine language for a supplemental locale."; 1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetPreferredUILanguageList(LanguageFunction function, ULONG flags, 1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::vector<std::wstring>* languages) { 1224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::vector<wchar_t> buffer; 1234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::wstring language; 1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::wstring region; 1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (GetMUIPreferredUILanguageList(function, flags, &buffer)) { 1274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::vector<wchar_t>::const_iterator scan = buffer.begin(); 1284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch language.assign(&*scan); 1294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch while (!language.empty()) { 1304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch languages->push_back(language); 1314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scan += language.size() + 1; 1324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch language.assign(&*scan); 1334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else if (GetUserDefaultUILanguage(&language, ®ion)) { 1354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Mimic the MUI behavior of putting the neutral version of the lang after 1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // the regional one (e.g., "fr-CA, fr"). 1374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!region.empty()) 1384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch languages->push_back(std::wstring(language) 1394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch .append(1, L'-') 1404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch .append(region)); 1414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch languages->push_back(language); 1424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return true; 1474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace 1504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace base { 1524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace win { 1534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace i18n { 1544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) { 1564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(languages); 1574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages); 1584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) { 1614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(languages); 1624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return GetPreferredUILanguageList( 1634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, 1644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch languages); 1654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace i18n 1684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace win 1694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace base 170