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/language_combobox_model.h" 6 7 #include "base/i18n/rtl.h" 8 #include "base/string_split.h" 9 #include "base/stringprintf.h" 10 #include "base/utf_string_conversions.h" 11 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/metrics/user_metrics.h" 13 #include "chrome/browser/prefs/pref_service.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "grit/generated_resources.h" 16 #include "ui/base/l10n/l10n_util.h" 17 #include "unicode/uloc.h" 18 19 /////////////////////////////////////////////////////////////////////////////// 20 // LanguageList used to enumerate native names corresponding to the 21 // language code (e.g. English (United States) for en-US) 22 // 23 24 LanguageList::LanguageList() { 25 // Enumerate the languages we know about. 26 const std::vector<std::string>& locale_codes = 27 l10n_util::GetAvailableLocales(); 28 InitNativeNames(locale_codes); 29 } 30 31 LanguageList::LanguageList( 32 const std::vector<std::string>& locale_codes) { 33 InitNativeNames(locale_codes); 34 } 35 36 LanguageList::~LanguageList() {} 37 38 void LanguageList::InitNativeNames( 39 const std::vector<std::string>& locale_codes) { 40 const std::string app_locale = g_browser_process->GetApplicationLocale(); 41 for (size_t i = 0; i < locale_codes.size(); ++i) { 42 std::string locale_code_str = locale_codes[i]; 43 const char* locale_code = locale_codes[i].c_str(); 44 45 // TODO(jungshik): Even though these strings are used for the UI, 46 // the old code does not add an RTL mark for RTL locales. Make sure 47 // that it's ok without that. 48 string16 name_in_current_ui = 49 l10n_util::GetDisplayNameForLocale(locale_code, app_locale, false); 50 string16 name_native = 51 l10n_util::GetDisplayNameForLocale(locale_code, locale_code, false); 52 53 locale_names_.push_back(name_in_current_ui); 54 native_names_[name_in_current_ui] = 55 LocaleData(name_native, locale_codes[i]); 56 } 57 58 // Sort using locale specific sorter. 59 l10n_util::SortStrings16(g_browser_process->GetApplicationLocale(), 60 &locale_names_); 61 } 62 63 void LanguageList::CopySpecifiedLanguagesUp(const std::string& locale_codes) { 64 DCHECK(!locale_names_.empty()); 65 std::vector<std::string> locale_codes_vector; 66 base::SplitString(locale_codes, ',', &locale_codes_vector); 67 for (size_t i = 0; i != locale_codes_vector.size(); i++) { 68 const int locale_index = GetIndexFromLocale(locale_codes_vector[i]); 69 CHECK_NE(locale_index, -1); 70 locale_names_.insert(locale_names_.begin(), locale_names_[locale_index]); 71 } 72 } 73 74 // Overridden from ComboboxModel: 75 int LanguageList::get_languages_count() const { 76 return static_cast<int>(locale_names_.size()); 77 } 78 79 string16 LanguageList::GetLanguageNameAt(int index) const { 80 DCHECK(static_cast<int>(locale_names_.size()) > index); 81 LocaleDataMap::const_iterator it = 82 native_names_.find(locale_names_[index]); 83 DCHECK(it != native_names_.end()); 84 85 // If the name is the same in the native language and local language, 86 // don't show it twice. 87 if (it->second.native_name == locale_names_[index]) 88 return it->second.native_name; 89 90 // We must add directionality formatting to both the native name and the 91 // locale name in order to avoid text rendering problems such as misplaced 92 // parentheses or languages appearing in the wrong order. 93 string16 locale_name = locale_names_[index]; 94 base::i18n::AdjustStringForLocaleDirection(&locale_name); 95 96 string16 native_name = it->second.native_name; 97 base::i18n::AdjustStringForLocaleDirection(&native_name); 98 99 // We used to have a localizable template here, but none of translators 100 // changed the format. We also want to switch the order of locale_name 101 // and native_name without going back to translators. 102 std::string formatted_item; 103 base::SStringPrintf(&formatted_item, "%s - %s", 104 UTF16ToUTF8(locale_name).c_str(), 105 UTF16ToUTF8(native_name).c_str()); 106 if (base::i18n::IsRTL()) 107 // Somehow combo box (even with LAYOUTRTL flag) doesn't get this 108 // right so we add RTL BDO (U+202E) to set the direction 109 // explicitly. 110 formatted_item.insert(0, "\xE2\x80\xAE"); // U+202E = UTF-8 0xE280AE 111 return UTF8ToUTF16(formatted_item); 112 } 113 114 // Return the locale for the given index. E.g., may return pt-BR. 115 std::string LanguageList::GetLocaleFromIndex(int index) const { 116 DCHECK(static_cast<int>(locale_names_.size()) > index); 117 LocaleDataMap::const_iterator it = 118 native_names_.find(locale_names_[index]); 119 DCHECK(it != native_names_.end()); 120 121 return it->second.locale_code; 122 } 123 124 int LanguageList::GetIndexFromLocale(const std::string& locale) const { 125 for (size_t i = 0; i < locale_names_.size(); ++i) { 126 LocaleDataMap::const_iterator it = 127 native_names_.find(locale_names_[i]); 128 DCHECK(it != native_names_.end()); 129 if (it->second.locale_code == locale) 130 return static_cast<int>(i); 131 } 132 return -1; 133 } 134 135 /////////////////////////////////////////////////////////////////////////////// 136 // LanguageComboboxModel used to populate a combobox with native names 137 // 138 139 LanguageComboboxModel::LanguageComboboxModel() 140 : profile_(NULL) { 141 } 142 143 LanguageComboboxModel::LanguageComboboxModel( 144 Profile* profile, const std::vector<std::string>& locale_codes) 145 : LanguageList(locale_codes), 146 profile_(profile) { 147 } 148 149 LanguageComboboxModel::~LanguageComboboxModel() {} 150 151 int LanguageComboboxModel::GetItemCount() { 152 return get_languages_count(); 153 } 154 155 string16 LanguageComboboxModel::GetItemAt(int index) { 156 return GetLanguageNameAt(index); 157 } 158 159 // Returns the index of the language currently specified in the user's 160 // preference file. Note that it's possible for language A to be picked 161 // while chrome is currently in language B if the user specified language B 162 // via --lang. Since --lang is not a persistent setting, it seems that it 163 // shouldn't be reflected in this combo box. We return -1 if the value in 164 // the pref doesn't map to a know language (possible if the user edited the 165 // prefs file manually). 166 int LanguageComboboxModel::GetSelectedLanguageIndex(const std::string& prefs) { 167 PrefService* local_state; 168 if (!profile_) 169 local_state = g_browser_process->local_state(); 170 else 171 local_state = profile_->GetPrefs(); 172 173 DCHECK(local_state); 174 const std::string& current_locale = local_state->GetString(prefs.c_str()); 175 176 return GetIndexFromLocale(current_locale); 177 } 178