| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome_frame/simple_resource_loader.h" | 5 #include "chrome_frame/simple_resource_loader.h" |
| 6 | 6 |
| 7 #include <atlbase.h> |
| 8 |
| 7 #include <algorithm> | 9 #include <algorithm> |
| 8 | 10 |
| 9 #include <atlbase.h> | |
| 10 | |
| 11 #include "base/base_paths.h" | 11 #include "base/base_paths.h" |
| 12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
| 13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 14 #include "base/path_service.h" | 14 #include "base/path_service.h" |
| 15 #include "base/i18n/file_util_icu.h" | |
| 16 #include "base/i18n/rtl.h" | 15 #include "base/i18n/rtl.h" |
| 17 #include "base/singleton.h" | 16 #include "base/singleton.h" |
| 18 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 19 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
| 19 #include "base/win/i18n.h" |
| 20 #include "base/win/windows_version.h" | 20 #include "base/win/windows_version.h" |
| 21 | 21 |
| 22 #include "chrome_frame/policy_settings.h" | 22 #include "chrome_frame/policy_settings.h" |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 const wchar_t kLocalesDirName[] = L"Locales"; | 26 const wchar_t kLocalesDirName[] = L"Locales"; |
| 27 | 27 |
| 28 bool IsInvalidTagCharacter(wchar_t tag_character) { | 28 bool IsInvalidTagCharacter(wchar_t tag_character) { |
| 29 return !(L'-' == tag_character || | 29 return !(L'-' == tag_character || |
| (...skipping 24 matching lines...) Expand all Loading... |
| 54 std::vector<std::wstring>* collection) { | 54 std::vector<std::wstring>* collection) { |
| 55 if (collection->end() == | 55 if (collection->end() == |
| 56 std::find_if(collection->begin(), collection->end(), | 56 std::find_if(collection->begin(), collection->end(), |
| 57 CompareInsensitiveASCII(value))) { | 57 CompareInsensitiveASCII(value))) { |
| 58 collection->push_back(value); | 58 collection->push_back(value); |
| 59 return true; | 59 return true; |
| 60 } | 60 } |
| 61 return false; | 61 return false; |
| 62 } | 62 } |
| 63 | 63 |
| 64 // Returns true if the collection is modified. |
| 65 bool PushBackWithFallbackIfAbsent( |
| 66 const std::wstring& language, |
| 67 std::vector<std::wstring>* collection) { |
| 68 bool modified = false; |
| 69 |
| 70 if (!language.empty()) { |
| 71 // Try adding the language itself. |
| 72 modified = PushBackIfAbsent(language, collection); |
| 73 |
| 74 // Now try adding its fallback, if it has one. |
| 75 std::wstring::size_type dash_pos = language.find(L'-'); |
| 76 if (0 < dash_pos && language.size() - 1 > dash_pos) |
| 77 modified |= PushBackIfAbsent(language.substr(0, dash_pos), collection); |
| 78 } |
| 79 |
| 80 return modified; |
| 81 } |
| 82 |
| 64 } // namespace | 83 } // namespace |
| 65 | 84 |
| 66 SimpleResourceLoader::SimpleResourceLoader() | 85 SimpleResourceLoader::SimpleResourceLoader() |
| 67 : locale_dll_handle_(NULL) { | 86 : locale_dll_handle_(NULL) { |
| 68 // Find and load the resource DLL. | 87 // Find and load the resource DLL. |
| 69 std::vector<std::wstring> language_tags; | 88 std::vector<std::wstring> language_tags; |
| 70 | 89 |
| 71 // First, try the locale dictated by policy and its fallback. | 90 // First, try the locale dictated by policy and its fallback. |
| 72 std::wstring application_locale = | 91 PushBackWithFallbackIfAbsent(Singleton<PolicySettings>()->ApplicationLocale(), |
| 73 Singleton<PolicySettings>()->ApplicationLocale(); | 92 &language_tags); |
| 74 if (!application_locale.empty()) { | |
| 75 language_tags.push_back(application_locale); | |
| 76 std::wstring::size_type dash = application_locale.find(L'-'); | |
| 77 if (std::wstring::npos != dash) { | |
| 78 if (0 != dash) { | |
| 79 language_tags.push_back(application_locale.substr(0, dash)); | |
| 80 } else { | |
| 81 NOTREACHED() << "Group Policy application locale begins with a dash."; | |
| 82 } | |
| 83 } | |
| 84 } | |
| 85 | 93 |
| 86 // Next, try the thread, process, user, system languages. | 94 // Next, try the thread, process, user, system languages. |
| 87 GetPreferredLanguages(&language_tags); | 95 GetPreferredLanguages(&language_tags); |
| 88 | 96 |
| 89 // Finally, fall-back on "en-US" (which may already be present in the vector, | 97 // Finally, fall-back on "en-US" (which may already be present in the vector, |
| 90 // but that's okay since we'll exit with success when the first is tried). | 98 // but that's okay since we'll exit with success when the first is tried). |
| 91 language_tags.push_back(L"en-US"); | 99 language_tags.push_back(L"en-US"); |
| 92 | 100 |
| 93 FilePath locales_path; | 101 FilePath locales_path; |
| 94 FilePath locale_dll_path; | 102 FilePath locale_dll_path; |
| 95 | 103 |
| 96 DetermineLocalesDirectory(&locales_path); | 104 DetermineLocalesDirectory(&locales_path); |
| 97 if (LoadLocaleDll(language_tags, locales_path, &locale_dll_handle_, | 105 if (LoadLocaleDll(language_tags, locales_path, &locale_dll_handle_, |
| 98 &locale_dll_path)) { | 106 &locale_dll_path)) { |
| 99 language_ = locale_dll_path.BaseName().RemoveExtension().value(); | 107 language_ = locale_dll_path.BaseName().RemoveExtension().value(); |
| 100 } else { | 108 } else { |
| 101 NOTREACHED() << "Failed loading any resource dll (even \"en-US\")."; | 109 NOTREACHED() << "Failed loading any resource dll (even \"en-US\")."; |
| 102 } | 110 } |
| 103 } | 111 } |
| 104 | 112 |
| 105 SimpleResourceLoader::~SimpleResourceLoader() { | 113 SimpleResourceLoader::~SimpleResourceLoader() { |
| 106 locale_dll_handle_ = NULL; | 114 locale_dll_handle_ = NULL; |
| 107 } | 115 } |
| 108 | 116 |
| 109 // static | 117 // static |
| 110 void SimpleResourceLoader::GetPreferredLanguages( | 118 void SimpleResourceLoader::GetPreferredLanguages( |
| 111 std::vector<std::wstring>* language_tags) { | 119 std::vector<std::wstring>* language_tags) { |
| 120 DCHECK(language_tags); |
| 112 // The full set of preferred languages and their fallbacks are given priority. | 121 // The full set of preferred languages and their fallbacks are given priority. |
| 113 GetThreadPreferredUILanguages(language_tags); | 122 std::vector<std::wstring> languages; |
| 123 if (base::win::i18n::GetThreadPreferredUILanguageList(&languages)) { |
| 124 for (std::vector<std::wstring>::const_iterator scan = languages.begin(), |
| 125 end = languages.end(); scan != end; ++scan) { |
| 126 PushBackIfAbsent(*scan, language_tags); |
| 127 } |
| 128 } |
| 114 | 129 |
| 115 // The above gives us nothing pre-Vista, so use ICU to get the system | 130 // Use the base i18n routines (i.e., ICU) as a last, best hope for something |
| 116 // language and add it and its fallback to the end of the list if not present. | 131 // meaningful for the user. |
| 117 std::wstring language; | 132 PushBackWithFallbackIfAbsent(ASCIIToWide(base::i18n::GetConfiguredLocale()), |
| 118 std::wstring region; | 133 language_tags); |
| 119 | |
| 120 GetICUSystemLanguage(&language, ®ion); | |
| 121 if (!region.empty()) { | |
| 122 std::wstring combined; | |
| 123 combined.reserve(language.size() + 1 + region.size()); | |
| 124 combined.assign(language).append(L"-").append(region); | |
| 125 PushBackIfAbsent(combined, language_tags); | |
| 126 } | |
| 127 PushBackIfAbsent(language, language_tags); | |
| 128 } | 134 } |
| 129 | 135 |
| 130 // static | 136 // static |
| 131 bool SimpleResourceLoader::GetThreadPreferredUILanguages( | |
| 132 std::vector<std::wstring>* language_tags) { | |
| 133 typedef BOOL (WINAPI* GetThreadPreferredUILanguages_Fn)( | |
| 134 DWORD, PULONG, PZZWSTR, PULONG); | |
| 135 HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); | |
| 136 DCHECK(kernel32) << "Failed finding kernel32.dll!"; | |
| 137 GetThreadPreferredUILanguages_Fn get_thread_preferred_ui_languages = | |
| 138 reinterpret_cast<GetThreadPreferredUILanguages_Fn>( | |
| 139 GetProcAddress(kernel32, "GetThreadPreferredUILanguages")); | |
| 140 bool have_mui = (NULL != get_thread_preferred_ui_languages); | |
| 141 if (have_mui) { | |
| 142 const DWORD kNameAndFallbackFlags = | |
| 143 MUI_LANGUAGE_NAME | MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK; | |
| 144 ULONG language_count = 0; | |
| 145 ULONG buffer_length = 0; | |
| 146 | |
| 147 if (get_thread_preferred_ui_languages( | |
| 148 kNameAndFallbackFlags, | |
| 149 &language_count, | |
| 150 NULL, | |
| 151 &buffer_length) && 0 != buffer_length) { | |
| 152 std::vector<wchar_t> language_names(buffer_length); | |
| 153 | |
| 154 if (get_thread_preferred_ui_languages( | |
| 155 kNameAndFallbackFlags, | |
| 156 &language_count, | |
| 157 &language_names[0], | |
| 158 &buffer_length)) { | |
| 159 std::vector<wchar_t>::const_iterator scan = language_names.begin(); | |
| 160 std::wstring language(&*scan); | |
| 161 while (!language.empty()) { | |
| 162 language_tags->push_back(language); | |
| 163 scan += language.size() + 1; | |
| 164 language.assign(&*scan); | |
| 165 } | |
| 166 } | |
| 167 } | |
| 168 } | |
| 169 return have_mui; | |
| 170 } | |
| 171 | |
| 172 // static | |
| 173 void SimpleResourceLoader::GetICUSystemLanguage(std::wstring* language, | |
| 174 std::wstring* region) { | |
| 175 DCHECK(language); | |
| 176 DCHECK(region); | |
| 177 | |
| 178 std::string icu_language, icu_region; | |
| 179 base::i18n::GetLanguageAndRegionFromOS(&icu_language, &icu_region); | |
| 180 if (!icu_language.empty()) { | |
| 181 *language = ASCIIToWide(icu_language); | |
| 182 } else { | |
| 183 language->clear(); | |
| 184 } | |
| 185 if (!icu_region.empty()) { | |
| 186 *region = ASCIIToWide(icu_region); | |
| 187 } else { | |
| 188 region->clear(); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 // static | |
| 193 void SimpleResourceLoader::DetermineLocalesDirectory(FilePath* locales_path) { | 137 void SimpleResourceLoader::DetermineLocalesDirectory(FilePath* locales_path) { |
| 194 DCHECK(locales_path); | 138 DCHECK(locales_path); |
| 195 | 139 |
| 196 FilePath module_path; | 140 FilePath module_path; |
| 197 PathService::Get(base::DIR_MODULE, &module_path); | 141 PathService::Get(base::DIR_MODULE, &module_path); |
| 198 *locales_path = module_path.Append(kLocalesDirName); | 142 *locales_path = module_path.Append(kLocalesDirName); |
| 199 | 143 |
| 200 // We may be residing in the "locales" directory's parent, or we might be | 144 // We may be residing in the "locales" directory's parent, or we might be |
| 201 // in a sibling directory. Move up one and look for Locales again in the | 145 // in a sibling directory. Move up one and look for Locales again in the |
| 202 // latter case. | 146 // latter case. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 | 239 |
| 296 // static | 240 // static |
| 297 std::wstring SimpleResourceLoader::Get(int message_id) { | 241 std::wstring SimpleResourceLoader::Get(int message_id) { |
| 298 SimpleResourceLoader* loader = SimpleResourceLoader::instance(); | 242 SimpleResourceLoader* loader = SimpleResourceLoader::instance(); |
| 299 return loader->GetLocalizedResource(message_id); | 243 return loader->GetLocalizedResource(message_id); |
| 300 } | 244 } |
| 301 | 245 |
| 302 HMODULE SimpleResourceLoader::GetResourceModuleHandle() { | 246 HMODULE SimpleResourceLoader::GetResourceModuleHandle() { |
| 303 return locale_dll_handle_; | 247 return locale_dll_handle_; |
| 304 } | 248 } |
| OLD | NEW |