Home | History | Annotate | Download | only in translate
      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