1 // Copyright 2013 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/translate/translate_accept_languages.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/prefs/pref_change_registrar.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/strings/string_split.h" 12 #include "base/strings/string_util.h" 13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/chrome_notification_types.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/translate/translate_manager.h" 17 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/pref_names.h" 19 #include "chrome/common/translate/translate_util.h" 20 #include "content/public/browser/notification_source.h" 21 #include "net/url_request/url_fetcher.h" 22 #include "ui/base/l10n/l10n_util.h" 23 24 TranslateAcceptLanguages::TranslateAcceptLanguages() { 25 } 26 27 TranslateAcceptLanguages::~TranslateAcceptLanguages() { 28 } 29 30 // static 31 bool TranslateAcceptLanguages::CanBeAcceptLanguage( 32 const std::string& language) { 33 std::string accept_language = language; 34 TranslateUtil::ToChromeLanguageSynonym(&accept_language); 35 36 const std::string locale = g_browser_process->GetApplicationLocale(); 37 std::vector<std::string> accept_language_codes; 38 l10n_util::GetAcceptLanguagesForLocale(locale, &accept_language_codes); 39 40 if (std::find(accept_language_codes.begin(), 41 accept_language_codes.end(), 42 accept_language) != accept_language_codes.end()) { 43 return true; 44 } 45 46 return false; 47 } 48 49 bool TranslateAcceptLanguages::IsAcceptLanguage(Profile* profile, 50 const std::string& language) { 51 DCHECK(profile); 52 53 PrefService* pref_service = profile->GetPrefs(); 54 PrefServiceLanguagesMap::const_iterator iter = 55 accept_languages_.find(pref_service); 56 if (iter == accept_languages_.end()) { 57 InitAcceptLanguages(pref_service); 58 // Listen for this profile going away, in which case we would need to clear 59 // the accepted languages for the profile. 60 notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, 61 content::Source<Profile>(profile)); 62 // Also start listening for changes in the accept languages. 63 DCHECK(pref_change_registrars_.find(pref_service) == 64 pref_change_registrars_.end()); 65 PrefChangeRegistrar* pref_change_registrar = new PrefChangeRegistrar; 66 pref_change_registrar->Init(pref_service); 67 pref_change_registrar->Add( 68 prefs::kAcceptLanguages, 69 base::Bind(&TranslateAcceptLanguages::InitAcceptLanguages, 70 base::Unretained(this), 71 pref_service)); 72 pref_change_registrars_[pref_service] = pref_change_registrar; 73 74 iter = accept_languages_.find(pref_service); 75 } 76 77 std::string accept_language = language; 78 TranslateUtil::ToChromeLanguageSynonym(&accept_language); 79 return iter->second.count(accept_language) != 0; 80 } 81 82 void TranslateAcceptLanguages::InitAcceptLanguages(PrefService* prefs) { 83 DCHECK(prefs); 84 85 // We have been asked for this profile, build the languages. 86 std::string accept_langs_str = prefs->GetString(prefs::kAcceptLanguages); 87 std::vector<std::string> accept_langs_list; 88 LanguageSet accept_langs_set; 89 base::SplitString(accept_langs_str, ',', &accept_langs_list); 90 std::vector<std::string>::const_iterator iter; 91 std::string app_locale = g_browser_process->GetApplicationLocale(); 92 std::string ui_lang = TranslateManager::GetLanguageCode(app_locale); 93 bool is_ui_english = StartsWithASCII(ui_lang, "en-", false); 94 95 CommandLine* command_line = CommandLine::ForCurrentProcess(); 96 bool enable_translate_settings = 97 command_line->HasSwitch(switches::kEnableTranslateSettings); 98 99 for (iter = accept_langs_list.begin(); 100 iter != accept_langs_list.end(); ++iter) { 101 // Get rid of the locale extension if any (ex: en-US -> en), but for Chinese 102 // for which the CLD reports zh-CN and zh-TW. 103 std::string accept_lang(*iter); 104 size_t index = iter->find("-"); 105 if (index != std::string::npos && *iter != "zh-CN" && *iter != "zh-TW") 106 accept_lang = iter->substr(0, index); 107 108 // Special-case English until we resolve bug 36182 properly. 109 // Add English only if the UI language is not English. This will annoy 110 // users of non-English Chrome who can comprehend English until English is 111 // black-listed. 112 // TODO(jungshik): Once we determine that it's safe to remove English from 113 // the default Accept-Language values for most locales, remove this 114 // special-casing. 115 // TODO(hajimehoshi): We can remove this special-casing if the Translate 116 // settings UI is enabled by default. 117 if (!enable_translate_settings && accept_lang == "en" && !is_ui_english) 118 continue; 119 120 accept_langs_set.insert(accept_lang); 121 } 122 accept_languages_[prefs] = accept_langs_set; 123 } 124 125 void TranslateAcceptLanguages::Observe(int type, 126 const content::NotificationSource& source, 127 const content::NotificationDetails& details) { 128 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 129 130 PrefService* pref_service = 131 content::Source<Profile>(source).ptr()->GetPrefs(); 132 notification_registrar_.Remove(this, 133 chrome::NOTIFICATION_PROFILE_DESTROYED, 134 source); 135 size_t count = accept_languages_.erase(pref_service); 136 // We should know about this profile since we are listening for 137 // notifications on it. 138 DCHECK_EQ(1u, count); 139 PrefChangeRegistrar* pref_change_registrar = 140 pref_change_registrars_[pref_service]; 141 count = pref_change_registrars_.erase(pref_service); 142 DCHECK_EQ(1u, count); 143 delete pref_change_registrar; 144 } 145