input_method_util.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
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 "chrome/browser/chromeos/input_method/input_method_util.h" 6 7#include <algorithm> 8#include <map> 9#include <utility> 10 11#include "unicode/uloc.h" 12 13#include "app/l10n_util.h" 14#include "app/l10n_util_collator.h" 15#include "base/basictypes.h" 16#include "base/hash_tables.h" 17#include "base/scoped_ptr.h" 18#include "base/singleton.h" 19#include "base/string_split.h" 20#include "base/string_util.h" 21#include "base/utf_string_conversions.h" 22#include "chrome/browser/browser_process.h" 23#include "chrome/browser/browser_thread.h" 24#include "chrome/browser/chromeos/cros/cros_library.h" 25#include "chrome/browser/chromeos/cros/keyboard_library.h" 26#include "chrome/browser/chromeos/language_preferences.h" 27#include "grit/generated_resources.h" 28 29namespace { 30 31// Map from language code to associated input method IDs, etc. 32typedef std::multimap<std::string, std::string> LanguageCodeToIdsMap; 33struct IdMaps { 34 scoped_ptr<LanguageCodeToIdsMap> language_code_to_ids; 35 scoped_ptr<std::map<std::string, std::string> > id_to_language_code; 36 scoped_ptr<std::map<std::string, std::string> > id_to_display_name; 37 38 void ReloadMaps() { 39 chromeos::InputMethodLibrary* library = 40 chromeos::CrosLibrary::Get()->GetInputMethodLibrary(); 41 scoped_ptr<chromeos::InputMethodDescriptors> supported_input_methods( 42 library->GetSupportedInputMethods()); 43 if (supported_input_methods->size() <= 1) { 44 LOG(ERROR) << "GetSupportedInputMethods returned a fallback ID"; 45 // TODO(yusukes): Handle this error in nicer way. 46 } 47 48 language_code_to_ids->clear(); 49 id_to_language_code->clear(); 50 id_to_display_name->clear(); 51 52 // Build the id to descriptor map for handling kExtraLanguages later. 53 typedef std::map<std::string, 54 const chromeos::InputMethodDescriptor*> DescMap; 55 DescMap id_to_descriptor_map; 56 57 for (size_t i = 0; i < supported_input_methods->size(); ++i) { 58 const chromeos::InputMethodDescriptor& input_method = 59 supported_input_methods->at(i); 60 const std::string language_code = 61 chromeos::input_method::GetLanguageCodeFromDescriptor(input_method); 62 AddInputMethodToMaps(language_code, input_method); 63 // Remember the pair. 64 id_to_descriptor_map.insert( 65 std::make_pair(input_method.id, &input_method)); 66 } 67 68 // Go through the languages listed in kExtraLanguages. 69 using chromeos::input_method::kExtraLanguages; 70 for (size_t i = 0; i < arraysize(kExtraLanguages); ++i) { 71 const char* language_code = kExtraLanguages[i].language_code; 72 const char* input_method_id = kExtraLanguages[i].input_method_id; 73 DescMap::const_iterator iter = id_to_descriptor_map.find(input_method_id); 74 // If the associated input method descriptor is found, add the 75 // language code and the input method. 76 if (iter != id_to_descriptor_map.end()) { 77 const chromeos::InputMethodDescriptor& input_method = *(iter->second); 78 AddInputMethodToMaps(language_code, input_method); 79 } 80 } 81 } 82 83 private: 84 IdMaps() : language_code_to_ids(new LanguageCodeToIdsMap), 85 id_to_language_code(new std::map<std::string, std::string>), 86 id_to_display_name(new std::map<std::string, std::string>) { 87 ReloadMaps(); 88 } 89 90 void AddInputMethodToMaps( 91 const std::string& language_code, 92 const chromeos::InputMethodDescriptor& input_method) { 93 language_code_to_ids->insert( 94 std::make_pair(language_code, input_method.id)); 95 id_to_language_code->insert( 96 std::make_pair(input_method.id, language_code)); 97 id_to_display_name->insert(std::make_pair( 98 input_method.id, 99 chromeos::input_method::GetStringUTF8(input_method.display_name))); 100 } 101 102 friend struct DefaultSingletonTraits<IdMaps>; 103 104 DISALLOW_COPY_AND_ASSIGN(IdMaps); 105}; 106 107const struct EnglishToResouceId { 108 const char* english_string_from_ibus; 109 int resource_id; 110} kEnglishToResourceIdArray[] = { 111 // For ibus-mozc: third_party/ibus-mozc/files/src/unix/ibus/. 112 { "Direct input", IDS_STATUSBAR_IME_JAPANESE_IME_STATUS_DIRECT_INPUT }, 113 { "Hiragana", IDS_STATUSBAR_IME_JAPANESE_IME_STATUS_HIRAGANA }, 114 { "Katakana", IDS_STATUSBAR_IME_JAPANESE_IME_STATUS_KATAKANA }, 115 { "Half width katakana", // small k is not a typo. 116 IDS_STATUSBAR_IME_JAPANESE_IME_STATUS_HALF_WIDTH_KATAKANA }, 117 { "Latin", IDS_STATUSBAR_IME_JAPANESE_IME_STATUS_LATIN }, 118 { "Wide Latin", IDS_STATUSBAR_IME_JAPANESE_IME_STATUS_WIDE_LATIN }, 119 120 // For ibus-hangul: third_party/ibus-hangul/files/po/. 121 { "Enable/Disable Hanja mode", IDS_STATUSBAR_IME_KOREAN_HANJA_MODE }, 122 123 // For ibus-pinyin: third_party/ibus-pinyin/files/po/. 124 { "Chinese", IDS_STATUSBAR_IME_CHINESE_PINYIN_TOGGLE_CHINESE_ENGLISH }, 125 { "Full/Half width", 126 IDS_STATUSBAR_IME_CHINESE_PINYIN_TOGGLE_FULL_HALF }, 127 { "Full/Half width punctuation", 128 IDS_STATUSBAR_IME_CHINESE_PINYIN_TOGGLE_FULL_HALF_PUNCTUATION }, 129 { "Simplfied/Traditional Chinese", 130 IDS_STATUSBAR_IME_CHINESE_PINYIN_TOGGLE_S_T_CHINESE }, 131 132 // For ibus-chewing: third_party/ibus-chewing/files/src/IBusChewingEngine.gob. 133 { "Chi", IDS_STATUSBAR_IME_CHINESE_CHEWING_SWITCH_CHINESE_TO_ENGLISH }, 134 { "Eng", IDS_STATUSBAR_IME_CHINESE_CHEWING_SWITCH_ENGLISH_TO_CHINESE }, 135 { "Full", IDS_STATUSBAR_IME_CHINESE_CHEWING_SWITCH_FULL_TO_HALF }, 136 { "Half", IDS_STATUSBAR_IME_CHINESE_CHEWING_SWITCH_HALF_TO_FULL }, 137 138 // For the "Languages and Input" dialog. 139 { "kbd (m17n)", IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_STANDARD_INPUT_METHOD }, 140 { "itrans (m17n)", // also uses the "STANDARD_INPUT_METHOD" id. 141 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_STANDARD_INPUT_METHOD }, 142 { "cangjie (m17n)", 143 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_CHINESE_CANGJIE_INPUT_METHOD }, 144 { "quick (m17n)", 145 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_CHINESE_QUICK_INPUT_METHOD }, 146 { "isiri (m17n)", 147 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_PERSIAN_ISIRI_2901_INPUT_METHOD }, 148 { "kesmanee (m17n)", 149 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_THAI_KESMANEE_INPUT_METHOD }, 150 { "tis820 (m17n)", 151 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_THAI_TIS820_INPUT_METHOD }, 152 { "pattachote (m17n)", 153 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_THAI_PATTACHOTE_INPUT_METHOD }, 154 { "tcvn (m17n)", 155 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_VIETNAMESE_TCVN_INPUT_METHOD }, 156 { "telex (m17n)", 157 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_VIETNAMESE_TELEX_INPUT_METHOD }, 158 { "viqr (m17n)", 159 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_VIETNAMESE_VIQR_INPUT_METHOD }, 160 { "vni (m17n)", 161 IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_VIETNAMESE_VNI_INPUT_METHOD }, 162 { "Bopomofo", IDS_OPTIONS_SETTINGS_LANGUAGES_BOPOMOFO_INPUT_METHOD }, 163 { "Chewing", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_INPUT_METHOD }, 164 { "Pinyin", IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_INPUT_METHOD }, 165 { "Mozc (US keyboard layout)", 166 IDS_OPTIONS_SETTINGS_LANGUAGES_JAPANESE_MOZC_US_INPUT_METHOD }, 167 { "Mozc (US Dvorak keyboard layout)", 168 IDS_OPTIONS_SETTINGS_LANGUAGES_JAPANESE_MOZC_US_DV_INPUT_METHOD }, 169 { "Mozc (Japanese keyboard layout)", 170 IDS_OPTIONS_SETTINGS_LANGUAGES_JAPANESE_MOZC_JP_INPUT_METHOD }, 171 { "Google Japanese Input (US keyboard layout)", 172 IDS_OPTIONS_SETTINGS_LANGUAGES_JAPANESE_GOOGLE_US_INPUT_METHOD }, 173 { "Google Japanese Input (US Dvorak keyboard layout)", 174 IDS_OPTIONS_SETTINGS_LANGUAGES_JAPANESE_GOOGLE_US_DV_INPUT_METHOD }, 175 { "Google Japanese Input (Japanese keyboard layout)", 176 IDS_OPTIONS_SETTINGS_LANGUAGES_JAPANESE_GOOGLE_JP_INPUT_METHOD }, 177 { "Korean", IDS_OPTIONS_SETTINGS_LANGUAGES_KOREAN_INPUT_METHOD }, 178 179 // For ibus-xkb-layouts engine: third_party/ibus-xkb-layouts/files 180 { "Japan", IDS_STATUSBAR_LAYOUT_JAPAN }, 181 { "Slovenia", IDS_STATUSBAR_LAYOUT_SLOVENIA }, 182 { "Germany", IDS_STATUSBAR_LAYOUT_GERMANY }, 183 { "Italy", IDS_STATUSBAR_LAYOUT_ITALY }, 184 { "Estonia", IDS_STATUSBAR_LAYOUT_ESTONIA }, 185 { "Hungary", IDS_STATUSBAR_LAYOUT_HUNGARY }, 186 { "Poland", IDS_STATUSBAR_LAYOUT_POLAND }, 187 { "Denmark", IDS_STATUSBAR_LAYOUT_DENMARK }, 188 { "Croatia", IDS_STATUSBAR_LAYOUT_CROATIA }, 189 { "Brazil", IDS_STATUSBAR_LAYOUT_BRAZIL }, 190 { "Serbia", IDS_STATUSBAR_LAYOUT_SERBIA }, 191 { "Czechia", IDS_STATUSBAR_LAYOUT_CZECHIA }, 192 { "USA - Dvorak", IDS_STATUSBAR_LAYOUT_USA_DVORAK }, 193 { "Romania", IDS_STATUSBAR_LAYOUT_ROMANIA }, 194 { "USA", IDS_STATUSBAR_LAYOUT_USA }, 195 { "USA - International (AltGr dead keys)", 196 IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL }, 197 { "Lithuania", IDS_STATUSBAR_LAYOUT_LITHUANIA }, 198 { "United Kingdom - Extended - Winkeys", 199 IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM }, 200 { "Slovakia", IDS_STATUSBAR_LAYOUT_SLOVAKIA }, 201 { "Russia", IDS_STATUSBAR_LAYOUT_RUSSIA }, 202 { "Russia - Phonetic", IDS_STATUSBAR_LAYOUT_RUSSIA_PHONETIC }, 203 { "Greece", IDS_STATUSBAR_LAYOUT_GREECE }, 204 { "Belgium", IDS_STATUSBAR_LAYOUT_BELGIUM }, 205 { "Bulgaria", IDS_STATUSBAR_LAYOUT_BULGARIA }, 206 { "Bulgaria - Traditional phonetic", IDS_STATUSBAR_LAYOUT_BULGARIA_PHONETIC }, 207 { "Switzerland", IDS_STATUSBAR_LAYOUT_SWITZERLAND }, 208 { "Switzerland - French", IDS_STATUSBAR_LAYOUT_SWITZERLAND_FRENCH }, 209 { "Turkey", IDS_STATUSBAR_LAYOUT_TURKEY }, 210 { "Portugal", IDS_STATUSBAR_LAYOUT_PORTUGAL }, 211 { "Spain", IDS_STATUSBAR_LAYOUT_SPAIN }, 212 { "Finland", IDS_STATUSBAR_LAYOUT_FINLAND }, 213 { "Ukraine", IDS_STATUSBAR_LAYOUT_UKRAINE }, 214 { "Spain - Catalan variant with middle-dot L", 215 IDS_STATUSBAR_LAYOUT_SPAIN_CATALAN }, 216 { "France", IDS_STATUSBAR_LAYOUT_FRANCE }, 217 { "Norway", IDS_STATUSBAR_LAYOUT_NORWAY }, 218 { "Sweden", IDS_STATUSBAR_LAYOUT_SWEDEN }, 219 { "Netherlands", IDS_STATUSBAR_LAYOUT_NETHERLANDS }, 220 { "Latvia", IDS_STATUSBAR_LAYOUT_LATVIA }, 221 { "Canada", IDS_STATUSBAR_LAYOUT_CANADA }, 222 { "Canada - English", IDS_STATUSBAR_LAYOUT_CANADA_ENGLISH }, 223 { "Israel", IDS_STATUSBAR_LAYOUT_ISRAEL }, 224 { "Korea, Republic of - 101/104 key Compatible", 225 IDS_STATUSBAR_LAYOUT_KOREA_104 }, 226}; 227const size_t kNumEntries = arraysize(kEnglishToResourceIdArray); 228 229// There are some differences between ISO 639-2 (T) and ISO 639-2 B, and 230// some language codes are not recognized by ICU (i.e. ICU cannot convert 231// these codes to two-letter language codes and display names). Hence we 232// convert these codes to ones that ICU recognize. 233// 234// See http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for details. 235const char* kIso639VariantMapping[][2] = { 236 {"cze", "ces"}, 237 {"ger", "deu"}, 238 {"gre", "ell"}, 239 // "scr" is not a ISO 639 code. For some reason, evdev.xml uses "scr" as 240 // the language code for Croatian. 241 {"scr", "hrv"}, 242 {"rum", "ron"}, 243 {"slo", "slk"}, 244}; 245 246// The comparator is used for sorting language codes by their 247// corresponding language names, using the ICU collator. 248struct CompareLanguageCodesByLanguageName 249 : std::binary_function<const std::string&, const std::string&, bool> { 250 explicit CompareLanguageCodesByLanguageName(icu::Collator* collator) 251 : collator_(collator) { 252 } 253 254 // Calling GetLanguageDisplayNameFromCode() in the comparator is not 255 // efficient, but acceptable as the function is cheap, and the language 256 // list is short (about 40 at most). 257 bool operator()(const std::string& s1, const std::string& s2) const { 258 const std::wstring key1 = 259 chromeos::input_method::GetLanguageDisplayNameFromCode(s1); 260 const std::wstring key2 = 261 chromeos::input_method::GetLanguageDisplayNameFromCode(s2); 262 return l10n_util::StringComparator<std::wstring>(collator_)(key1, key2); 263 } 264 265 private: 266 icu::Collator* collator_; 267}; 268 269// The comparator is used for sorting input method ids by their 270// corresponding language names, using the ICU collator. 271struct CompareInputMethodIdsByLanguageName 272 : std::binary_function<const std::string&, const std::string&, bool> { 273 CompareInputMethodIdsByLanguageName( 274 icu::Collator* collator, 275 const std::map<std::string, std::string>& id_to_language_code_map) 276 : comparator_(collator), 277 id_to_language_code_map_(id_to_language_code_map) { 278 } 279 280 bool operator()(const std::string& s1, const std::string& s2) const { 281 std::string language_code_1; 282 std::map<std::string, std::string>::const_iterator iter = 283 id_to_language_code_map_.find(s1); 284 if (iter != id_to_language_code_map_.end()) { 285 language_code_1 = iter->second; 286 } 287 std::string language_code_2; 288 iter = id_to_language_code_map_.find(s2); 289 if (iter != id_to_language_code_map_.end()) { 290 language_code_2 = iter->second; 291 } 292 return comparator_(language_code_1, language_code_2); 293 } 294 295 private: 296 const CompareLanguageCodesByLanguageName comparator_; 297 const std::map<std::string, std::string>& id_to_language_code_map_; 298}; 299 300bool GetLocalizedString( 301 const std::string& english_string, string16 *out_string) { 302 DCHECK(out_string); 303 typedef base::hash_map<std::string, int> HashType; 304 static HashType* english_to_resource_id = NULL; 305 306 // Initialize the map if needed. 307 if (!english_to_resource_id) { 308 // We don't free this map. 309 english_to_resource_id = new HashType(kNumEntries); 310 for (size_t i = 0; i < kNumEntries; ++i) { 311 const bool result = english_to_resource_id->insert( 312 std::make_pair(kEnglishToResourceIdArray[i].english_string_from_ibus, 313 kEnglishToResourceIdArray[i].resource_id)).second; 314 DCHECK(result) << "Duplicated string is found: " 315 << kEnglishToResourceIdArray[i].english_string_from_ibus; 316 } 317 } 318 319 HashType::const_iterator iter = english_to_resource_id->find(english_string); 320 if (iter == english_to_resource_id->end()) { 321 // TODO(yusukes): Write Autotest which checks if all display names and all 322 // property names for supported input methods are listed in the resource ID 323 // array (crosbug.com/4572). 324 LOG(ERROR) << "Resource ID is not found for: " << english_string; 325 return false; 326 } 327 328 *out_string = l10n_util::GetStringUTF16(iter->second); 329 return true; 330}; 331 332} // namespace 333 334namespace chromeos { 335namespace input_method { 336 337std::wstring GetString(const std::string& english_string) { 338 string16 localized_string; 339 if (GetLocalizedString(english_string, &localized_string)) { 340 return UTF16ToWide(localized_string); 341 } 342 return UTF8ToWide(english_string); 343} 344 345std::string GetStringUTF8(const std::string& english_string) { 346 string16 localized_string; 347 if (GetLocalizedString(english_string, &localized_string)) { 348 return UTF16ToUTF8(localized_string); 349 } 350 return english_string; 351} 352 353string16 GetStringUTF16(const std::string& english_string) { 354 string16 localized_string; 355 if (GetLocalizedString(english_string, &localized_string)) { 356 return localized_string; 357 } 358 return UTF8ToUTF16(english_string); 359} 360 361bool StringIsSupported(const std::string& english_string) { 362 string16 localized_string; 363 return GetLocalizedString(english_string, &localized_string); 364} 365 366std::string NormalizeLanguageCode( 367 const std::string& language_code) { 368 // Some ibus engines return locale codes like "zh_CN" as language codes. 369 // Normalize these to like "zh-CN". 370 if (language_code.size() >= 5 && language_code[2] == '_') { 371 std::string copied_language_code = language_code; 372 copied_language_code[2] = '-'; 373 // Downcase the language code part. 374 for (size_t i = 0; i < 2; ++i) { 375 copied_language_code[i] = base::ToLowerASCII(copied_language_code[i]); 376 } 377 // Upcase the country code part. 378 for (size_t i = 3; i < copied_language_code.size(); ++i) { 379 copied_language_code[i] = base::ToUpperASCII(copied_language_code[i]); 380 } 381 return copied_language_code; 382 } 383 // We only handle three-letter codes from here. 384 if (language_code.size() != 3) { 385 return language_code; 386 } 387 388 // Convert special language codes. See comments at kIso639VariantMapping. 389 std::string copied_language_code = language_code; 390 for (size_t i = 0; i < arraysize(kIso639VariantMapping); ++i) { 391 if (language_code == kIso639VariantMapping[i][0]) { 392 copied_language_code = kIso639VariantMapping[i][1]; 393 } 394 } 395 // Convert the three-letter code to two letter-code. 396 UErrorCode error = U_ZERO_ERROR; 397 char two_letter_code[ULOC_LANG_CAPACITY]; 398 uloc_getLanguage(copied_language_code.c_str(), 399 two_letter_code, sizeof(two_letter_code), &error); 400 if (U_FAILURE(error)) { 401 return language_code; 402 } 403 return two_letter_code; 404} 405 406bool IsKeyboardLayout(const std::string& input_method_id) { 407 const bool kCaseInsensitive = false; 408 return StartsWithASCII(input_method_id, "xkb:", kCaseInsensitive); 409} 410 411std::string GetLanguageCodeFromDescriptor( 412 const InputMethodDescriptor& descriptor) { 413 // Handle some Chinese input methods as zh-CN/zh-TW, rather than zh. 414 // TODO: we should fix this issue in engines rather than here. 415 if (descriptor.language_code == "zh") { 416 if (descriptor.id == "pinyin") { 417 return "zh-CN"; 418 } else if (descriptor.id == "bopomofo" || 419 descriptor.id == "chewing" || 420 descriptor.id == "m17n:zh:cangjie" || 421 descriptor.id == "m17n:zh:quick") { 422 return "zh-TW"; 423 } 424 } 425 426 std::string language_code = NormalizeLanguageCode(descriptor.language_code); 427 428 // Add country codes to language codes of some XKB input methods to make 429 // these compatible with Chrome's application locale codes like "en-US". 430 // TODO(satorux): Maybe we need to handle "es" for "es-419". 431 // TODO: We should not rely on the format of the engine name. Should we add 432 // |country_code| in InputMethodDescriptor? 433 if (IsKeyboardLayout(descriptor.id) && 434 (language_code == "en" || 435 language_code == "zh" || 436 language_code == "pt")) { 437 std::vector<std::string> portions; 438 base::SplitString(descriptor.id, ':', &portions); 439 if (portions.size() >= 2 && !portions[1].empty()) { 440 language_code.append("-"); 441 language_code.append(StringToUpperASCII(portions[1])); 442 } 443 } 444 return language_code; 445} 446 447std::string GetLanguageCodeFromInputMethodId( 448 const std::string& input_method_id) { 449 // The code should be compatible with one of codes used for UI languages, 450 // defined in app/l10_util.cc. 451 const char kDefaultLanguageCode[] = "en-US"; 452 std::map<std::string, std::string>::const_iterator iter 453 = Singleton<IdMaps>::get()->id_to_language_code->find(input_method_id); 454 return (iter == Singleton<IdMaps>::get()->id_to_language_code->end()) ? 455 // Returning |kDefaultLanguageCode| here is not for Chrome OS but for 456 // Ubuntu where the ibus-xkb-layouts engine could be missing. 457 kDefaultLanguageCode : iter->second; 458} 459 460std::string GetKeyboardLayoutName(const std::string& input_method_id) { 461 if (!StartsWithASCII(input_method_id, "xkb:", true)) { 462 return ""; 463 } 464 465 std::vector<std::string> splitted_id; 466 base::SplitString(input_method_id, ':', &splitted_id); 467 return (splitted_id.size() > 1) ? splitted_id[1] : ""; 468} 469 470std::string GetInputMethodDisplayNameFromId( 471 const std::string& input_method_id) { 472 static const char kDefaultDisplayName[] = "USA"; 473 std::map<std::string, std::string>::const_iterator iter 474 = Singleton<IdMaps>::get()->id_to_display_name->find(input_method_id); 475 return (iter == Singleton<IdMaps>::get()->id_to_display_name->end()) ? 476 kDefaultDisplayName : iter->second; 477} 478 479std::wstring GetLanguageDisplayNameFromCode(const std::string& language_code) { 480 if (!g_browser_process) { 481 return L""; 482 } 483 return UTF16ToWide(l10n_util::GetDisplayNameForLocale( 484 language_code, g_browser_process->GetApplicationLocale(), true)); 485} 486 487std::wstring GetLanguageNativeDisplayNameFromCode( 488 const std::string& language_code) { 489 return UTF16ToWide(l10n_util::GetDisplayNameForLocale( 490 language_code, language_code, true)); 491} 492 493void SortLanguageCodesByNames(std::vector<std::string>* language_codes) { 494 if (!g_browser_process) { 495 return; 496 } 497 // We should build collator outside of the comparator. We cannot have 498 // scoped_ptr<> in the comparator for a subtle STL reason. 499 UErrorCode error = U_ZERO_ERROR; 500 icu::Locale locale(g_browser_process->GetApplicationLocale().c_str()); 501 scoped_ptr<icu::Collator> collator( 502 icu::Collator::createInstance(locale, error)); 503 if (U_FAILURE(error)) { 504 collator.reset(); 505 } 506 std::sort(language_codes->begin(), language_codes->end(), 507 CompareLanguageCodesByLanguageName(collator.get())); 508} 509 510void SortInputMethodIdsByNames(std::vector<std::string>* input_method_ids) { 511 SortInputMethodIdsByNamesInternal( 512 *(Singleton<IdMaps>::get()->id_to_language_code), input_method_ids); 513} 514 515void SortInputMethodIdsByNamesInternal( 516 const std::map<std::string, std::string>& id_to_language_code_map, 517 std::vector<std::string>* input_method_ids) { 518 if (!g_browser_process) { 519 return; 520 } 521 UErrorCode error = U_ZERO_ERROR; 522 icu::Locale locale(g_browser_process->GetApplicationLocale().c_str()); 523 scoped_ptr<icu::Collator> collator( 524 icu::Collator::createInstance(locale, error)); 525 if (U_FAILURE(error)) { 526 collator.reset(); 527 } 528 std::stable_sort(input_method_ids->begin(), input_method_ids->end(), 529 CompareInputMethodIdsByLanguageName( 530 collator.get(), id_to_language_code_map)); 531} 532 533bool GetInputMethodIdsFromLanguageCode( 534 const std::string& normalized_language_code, 535 InputMethodType type, 536 std::vector<std::string>* out_input_method_ids) { 537 return GetInputMethodIdsFromLanguageCodeInternal( 538 *Singleton<IdMaps>::get()->language_code_to_ids, 539 normalized_language_code, type, out_input_method_ids); 540} 541 542bool GetInputMethodIdsFromLanguageCodeInternal( 543 const std::multimap<std::string, std::string>& language_code_to_ids, 544 const std::string& normalized_language_code, 545 InputMethodType type, 546 std::vector<std::string>* out_input_method_ids) { 547 DCHECK(out_input_method_ids); 548 out_input_method_ids->clear(); 549 550 bool result = false; 551 std::pair<LanguageCodeToIdsMap::const_iterator, 552 LanguageCodeToIdsMap::const_iterator> range = 553 language_code_to_ids.equal_range(normalized_language_code); 554 for (LanguageCodeToIdsMap::const_iterator iter = range.first; 555 iter != range.second; ++iter) { 556 const std::string& input_method_id = iter->second; 557 if ((type == kAllInputMethods) || IsKeyboardLayout(input_method_id)) { 558 out_input_method_ids->push_back(input_method_id); 559 result = true; 560 } 561 } 562 if ((type == kAllInputMethods) && !result) { 563 LOG(ERROR) << "Unknown language code: " << normalized_language_code; 564 } 565 return result; 566} 567 568void EnableInputMethods(const std::string& language_code, InputMethodType type, 569 const std::string& initial_input_method_id) { 570 std::vector<std::string> input_method_ids; 571 GetInputMethodIdsFromLanguageCode(language_code, type, &input_method_ids); 572 573 std::string keyboard = CrosLibrary::Get()->GetKeyboardLibrary()-> 574 GetHardwareKeyboardLayoutName(); 575 if (std::count(input_method_ids.begin(), input_method_ids.end(), 576 keyboard) == 0) { 577 input_method_ids.push_back(keyboard); 578 } 579 // First, sort the vector by input method id, then by its display name. 580 std::sort(input_method_ids.begin(), input_method_ids.end()); 581 SortInputMethodIdsByNames(&input_method_ids); 582 583 // Update ibus-daemon setting. 584 ImeConfigValue value; 585 value.type = ImeConfigValue::kValueTypeStringList; 586 value.string_list_value = input_method_ids; 587 InputMethodLibrary* library = CrosLibrary::Get()->GetInputMethodLibrary(); 588 library->SetImeConfig(language_prefs::kGeneralSectionName, 589 language_prefs::kPreloadEnginesConfigName, value); 590 if (!initial_input_method_id.empty()) { 591 library->ChangeInputMethod(initial_input_method_id); 592 } 593} 594 595void OnLocaleChanged() { 596 Singleton<IdMaps>::get()->ReloadMaps(); 597} 598 599} // namespace input_method 600} // namespace chromeos 601