Home | History | Annotate | Download | only in translate
      1 // Copyright (c) 2011 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_prefs.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/prefs/pref_service.h"
      9 #include "base/strings/string_split.h"
     10 #include "base/strings/string_util.h"
     11 #include "chrome/browser/prefs/scoped_user_pref_update.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/translate/translate_accept_languages.h"
     14 #include "chrome/browser/translate/translate_manager.h"
     15 #include "chrome/common/chrome_switches.h"
     16 #include "chrome/common/pref_names.h"
     17 #include "chrome/common/translate/translate_util.h"
     18 #include "components/user_prefs/pref_registry_syncable.h"
     19 
     20 const char TranslatePrefs::kPrefTranslateLanguageBlacklist[] =
     21     "translate_language_blacklist";
     22 const char TranslatePrefs::kPrefTranslateSiteBlacklist[] =
     23     "translate_site_blacklist";
     24 const char TranslatePrefs::kPrefTranslateWhitelists[] =
     25     "translate_whitelists";
     26 const char TranslatePrefs::kPrefTranslateDeniedCount[] =
     27     "translate_denied_count";
     28 const char TranslatePrefs::kPrefTranslateAcceptedCount[] =
     29     "translate_accepted_count";
     30 const char TranslatePrefs::kPrefTranslateBlockedLanguages[] =
     31     "translate_blocked_languages";
     32 
     33 namespace {
     34 
     35 void GetBlacklistedLanguages(const PrefService* prefs,
     36                              std::vector<std::string>* languages) {
     37   DCHECK(languages->empty());
     38 
     39   const char* key = TranslatePrefs::kPrefTranslateLanguageBlacklist;
     40   const ListValue* list = prefs->GetList(key);
     41   for (ListValue::const_iterator it = list->begin(); it != list->end(); ++it) {
     42     std::string lang;
     43     (*it)->GetAsString(&lang);
     44     languages->push_back(lang);
     45   }
     46 }
     47 
     48 }  // namespace
     49 
     50 namespace {
     51 
     52 void AppendLanguageToAcceptLanguages(PrefService* prefs,
     53                                      const std::string& language) {
     54   if (!TranslateAcceptLanguages::CanBeAcceptLanguage(language))
     55     return;
     56 
     57   std::string accept_language = language;
     58   TranslateUtil::ToChromeLanguageSynonym(&accept_language);
     59 
     60   std::string accept_languages_str = prefs->GetString(prefs::kAcceptLanguages);
     61   std::vector<std::string> accept_languages;
     62   base::SplitString(accept_languages_str, ',', &accept_languages);
     63   if (std::find(accept_languages.begin(),
     64                 accept_languages.end(),
     65                 accept_language) == accept_languages.end()) {
     66     accept_languages.push_back(accept_language);
     67   }
     68   accept_languages_str = JoinString(accept_languages, ',');
     69   prefs->SetString(prefs::kAcceptLanguages, accept_languages_str);
     70 }
     71 
     72 }  // namespace
     73 
     74 // TranslatePrefs: public: -----------------------------------------------------
     75 
     76 TranslatePrefs::TranslatePrefs(PrefService* user_prefs)
     77     : prefs_(user_prefs) {
     78 }
     79 
     80 bool TranslatePrefs::IsBlockedLanguage(
     81     const std::string& original_language) const {
     82   CommandLine* command_line = CommandLine::ForCurrentProcess();
     83   if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
     84     return IsValueBlacklisted(kPrefTranslateBlockedLanguages,
     85                               original_language);
     86   } else {
     87     return IsValueBlacklisted(kPrefTranslateLanguageBlacklist,
     88                               original_language);
     89   }
     90 }
     91 
     92 void TranslatePrefs::BlockLanguage(
     93     const std::string& original_language) {
     94   CommandLine* command_line = CommandLine::ForCurrentProcess();
     95   if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
     96     BlacklistValue(kPrefTranslateBlockedLanguages, original_language);
     97     AppendLanguageToAcceptLanguages(prefs_, original_language);
     98   } else {
     99     BlacklistValue(kPrefTranslateLanguageBlacklist, original_language);
    100   }
    101 }
    102 
    103 void TranslatePrefs::UnblockLanguage(
    104     const std::string& original_language) {
    105   CommandLine* command_line = CommandLine::ForCurrentProcess();
    106   if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
    107     RemoveValueFromBlacklist(kPrefTranslateBlockedLanguages,
    108                              original_language);
    109   } else {
    110     RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist,
    111                              original_language);
    112   }
    113 }
    114 
    115 void TranslatePrefs::RemoveLanguageFromLegacyBlacklist(
    116     const std::string& original_language) {
    117   RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist,
    118                            original_language);
    119 }
    120 
    121 bool TranslatePrefs::IsSiteBlacklisted(const std::string& site) const {
    122   return IsValueBlacklisted(kPrefTranslateSiteBlacklist, site);
    123 }
    124 
    125 void TranslatePrefs::BlacklistSite(const std::string& site) {
    126   BlacklistValue(kPrefTranslateSiteBlacklist, site);
    127 }
    128 
    129 void TranslatePrefs::RemoveSiteFromBlacklist(const std::string& site) {
    130   RemoveValueFromBlacklist(kPrefTranslateSiteBlacklist, site);
    131 }
    132 
    133 bool TranslatePrefs::IsLanguagePairWhitelisted(
    134     const std::string& original_language,
    135     const std::string& target_language) {
    136   const DictionaryValue* dict = prefs_->GetDictionary(kPrefTranslateWhitelists);
    137   if (dict && !dict->empty()) {
    138     std::string auto_target_lang;
    139     if (dict->GetString(original_language, &auto_target_lang) &&
    140         auto_target_lang == target_language)
    141       return true;
    142   }
    143   return false;
    144 }
    145 
    146 void TranslatePrefs::WhitelistLanguagePair(
    147     const std::string& original_language,
    148     const std::string& target_language) {
    149   DictionaryPrefUpdate update(prefs_, kPrefTranslateWhitelists);
    150   DictionaryValue* dict = update.Get();
    151   if (!dict) {
    152     NOTREACHED() << "Unregistered translate whitelist pref";
    153     return;
    154   }
    155   dict->SetString(original_language, target_language);
    156 }
    157 
    158 void TranslatePrefs::RemoveLanguagePairFromWhitelist(
    159     const std::string& original_language,
    160     const std::string& target_language) {
    161   DictionaryPrefUpdate update(prefs_, kPrefTranslateWhitelists);
    162   DictionaryValue* dict = update.Get();
    163   if (!dict) {
    164     NOTREACHED() << "Unregistered translate whitelist pref";
    165     return;
    166   }
    167   dict->Remove(original_language, NULL);
    168 }
    169 
    170 bool TranslatePrefs::HasBlacklistedLanguages() const {
    171   CommandLine* command_line = CommandLine::ForCurrentProcess();
    172   if (command_line->HasSwitch(switches::kEnableTranslateSettings))
    173     return !IsListEmpty(kPrefTranslateBlockedLanguages);
    174   else
    175     return !IsListEmpty(kPrefTranslateLanguageBlacklist);
    176 }
    177 
    178 void TranslatePrefs::ClearBlacklistedLanguages() {
    179   CommandLine* command_line = CommandLine::ForCurrentProcess();
    180   if (command_line->HasSwitch(switches::kEnableTranslateSettings))
    181     prefs_->ClearPref(kPrefTranslateBlockedLanguages);
    182   else
    183     prefs_->ClearPref(kPrefTranslateLanguageBlacklist);
    184 }
    185 
    186 bool TranslatePrefs::HasBlacklistedSites() const {
    187   return !IsListEmpty(kPrefTranslateSiteBlacklist);
    188 }
    189 
    190 void TranslatePrefs::ClearBlacklistedSites() {
    191   prefs_->ClearPref(kPrefTranslateSiteBlacklist);
    192 }
    193 
    194 bool TranslatePrefs::HasWhitelistedLanguagePairs() const {
    195   return !IsDictionaryEmpty(kPrefTranslateWhitelists);
    196 }
    197 
    198 void TranslatePrefs::ClearWhitelistedLanguagePairs() {
    199   prefs_->ClearPref(kPrefTranslateWhitelists);
    200 }
    201 
    202 int TranslatePrefs::GetTranslationDeniedCount(
    203     const std::string& language) const {
    204   const DictionaryValue* dict =
    205       prefs_->GetDictionary(kPrefTranslateDeniedCount);
    206   int count = 0;
    207   return dict->GetInteger(language, &count) ? count : 0;
    208 }
    209 
    210 void TranslatePrefs::IncrementTranslationDeniedCount(
    211     const std::string& language) {
    212   DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount);
    213   DictionaryValue* dict = update.Get();
    214 
    215   int count = 0;
    216   dict->GetInteger(language, &count);
    217   dict->SetInteger(language, count + 1);
    218 }
    219 
    220 void TranslatePrefs::ResetTranslationDeniedCount(const std::string& language) {
    221   DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount);
    222   update.Get()->SetInteger(language, 0);
    223 }
    224 
    225 int TranslatePrefs::GetTranslationAcceptedCount(const std::string& language) {
    226   const DictionaryValue* dict =
    227       prefs_->GetDictionary(kPrefTranslateAcceptedCount);
    228   int count = 0;
    229   return dict->GetInteger(language, &count) ? count : 0;
    230 }
    231 
    232 void TranslatePrefs::IncrementTranslationAcceptedCount(
    233     const std::string& language) {
    234   DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount);
    235   DictionaryValue* dict = update.Get();
    236   int count = 0;
    237   dict->GetInteger(language, &count);
    238   dict->SetInteger(language, count + 1);
    239 }
    240 
    241 void TranslatePrefs::ResetTranslationAcceptedCount(
    242     const std::string& language) {
    243   DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount);
    244   update.Get()->SetInteger(language, 0);
    245 }
    246 
    247 // TranslatePrefs: public, static: ---------------------------------------------
    248 
    249 // static
    250 bool TranslatePrefs::CanTranslateLanguage(Profile* profile,
    251                                           const std::string& language) {
    252   TranslatePrefs translate_prefs(profile->GetPrefs());
    253   bool blocked = translate_prefs.IsBlockedLanguage(language);
    254 
    255   CommandLine* command_line = CommandLine::ForCurrentProcess();
    256   if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
    257     bool is_accept_language =
    258         TranslateManager::IsAcceptLanguage(profile, language);
    259     bool can_be_accept_language =
    260         TranslateAcceptLanguages::CanBeAcceptLanguage(language);
    261 
    262     // Don't translate any user black-listed languages. Checking
    263     // |is_accept_language| is necessary because if the user eliminates the
    264     // language from the preference, it is natural to forget whether or not
    265     // the language should be translated. Checking |cannot_be_accept_language|
    266     // is also necessary because some minor languages can't be selected in the
    267     // language preference even though the language is available in Translate
    268     // server.
    269     if (blocked && (is_accept_language || !can_be_accept_language))
    270       return false;
    271   } else {
    272     // Don't translate any user user selected language.
    273     if (blocked)
    274       return false;
    275   }
    276 
    277   return true;
    278 }
    279 
    280 // static
    281 bool TranslatePrefs::ShouldAutoTranslate(PrefService* user_prefs,
    282     const std::string& original_language, std::string* target_language) {
    283   TranslatePrefs prefs(user_prefs);
    284   return prefs.IsLanguageWhitelisted(original_language, target_language);
    285 }
    286 
    287 // static
    288 void TranslatePrefs::RegisterProfilePrefs(
    289     user_prefs::PrefRegistrySyncable* registry) {
    290   registry->RegisterListPref(kPrefTranslateLanguageBlacklist,
    291                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    292   registry->RegisterListPref(kPrefTranslateSiteBlacklist,
    293                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    294   registry->RegisterDictionaryPref(
    295       kPrefTranslateWhitelists,
    296       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    297   registry->RegisterDictionaryPref(
    298       kPrefTranslateDeniedCount,
    299       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    300   registry->RegisterDictionaryPref(
    301       kPrefTranslateAcceptedCount,
    302       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    303   registry->RegisterListPref(kPrefTranslateBlockedLanguages,
    304                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    305 }
    306 
    307 // static
    308 void TranslatePrefs::MigrateUserPrefs(PrefService* user_prefs) {
    309   // Old format of kPrefTranslateWhitelists
    310   // - original language -> list of target langs to auto-translate
    311   // - list of langs is in order of being enabled i.e. last in list is the
    312   //   most recent language that user enabled via
    313   //   Always translate |source_lang| to |target_lang|"
    314   // - this results in a one-to-n relationship between source lang and target
    315   //   langs.
    316   // New format:
    317   // - original language -> one target language to auto-translate
    318   // - each time that the user enables the "Always translate..." option, that
    319   //   target lang overwrites the previous one.
    320   // - this results in a one-to-one relationship between source lang and target
    321   //   lang
    322   // - we replace old list of target langs with the last target lang in list,
    323   //   assuming the last (i.e. most recent) target lang is what user wants to
    324   //   keep auto-translated.
    325   DictionaryPrefUpdate update(user_prefs, kPrefTranslateWhitelists);
    326   DictionaryValue* dict = update.Get();
    327   if (dict && !dict->empty()) {
    328     DictionaryValue::Iterator iter(*dict);
    329     while (!iter.IsAtEnd()) {
    330       const ListValue* list = NULL;
    331       if (!iter.value().GetAsList(&list) || !list)
    332         break;  // Dictionary has either been migrated or new format.
    333       std::string key = iter.key();
    334       // Advance the iterator before removing the current element.
    335       iter.Advance();
    336       std::string target_lang;
    337       if (list->empty() ||
    338           !list->GetString(list->GetSize() - 1, &target_lang) ||
    339           target_lang.empty()) {
    340         dict->Remove(key, NULL);
    341       } else {
    342         dict->SetString(key, target_lang);
    343       }
    344     }
    345   }
    346 
    347   // Get the union of the blacklist and the Accept languages, and set this to
    348   // the new language set 'translate_blocked_languages'. This is used for the
    349   // settings UI for Translate and configration to determine which langauage
    350   // should be translated instead of the blacklist. The blacklist is no longer
    351   // used after launching the settings UI.
    352   // After that, Set 'translate_languages_not_translate' to Accept languages to
    353   // enable settings for users.
    354   bool merged = user_prefs->HasPrefPath(kPrefTranslateBlockedLanguages);
    355 
    356   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    357   bool enabled_translate_settings =
    358       command_line.HasSwitch(switches::kEnableTranslateSettings);
    359 
    360   if (!merged && enabled_translate_settings) {
    361     std::vector<std::string> blacklisted_languages;
    362     GetBlacklistedLanguages(user_prefs, &blacklisted_languages);
    363 
    364     std::string accept_languages_str =
    365         user_prefs->GetString(prefs::kAcceptLanguages);
    366     std::vector<std::string> accept_languages;
    367     base::SplitString(accept_languages_str, ',', &accept_languages);
    368 
    369     std::vector<std::string> blocked_languages;
    370     CreateBlockedLanguages(&blocked_languages,
    371                            blacklisted_languages,
    372                            accept_languages);
    373 
    374     // Create the new preference kPrefTranslateBlockedLanguages.
    375     {
    376       ListValue* blocked_languages_list = new ListValue();
    377       for (std::vector<std::string>::const_iterator it =
    378                blocked_languages.begin();
    379            it != blocked_languages.end(); ++it) {
    380         blocked_languages_list->Append(new StringValue(*it));
    381       }
    382       ListPrefUpdate update(user_prefs, kPrefTranslateBlockedLanguages);
    383       ListValue* list = update.Get();
    384       DCHECK(list != NULL);
    385       list->Swap(blocked_languages_list);
    386     }
    387 
    388     // Update kAcceptLanguages
    389     for (std::vector<std::string>::const_iterator it =
    390              blocked_languages.begin();
    391          it != blocked_languages.end(); ++it) {
    392       std::string lang = *it;
    393       TranslateUtil::ToChromeLanguageSynonym(&lang);
    394       bool not_found =
    395           std::find(accept_languages.begin(), accept_languages.end(), lang) ==
    396           accept_languages.end();
    397       if (not_found)
    398         accept_languages.push_back(lang);
    399     }
    400 
    401     std::string new_accept_languages_str = JoinString(accept_languages, ",");
    402     user_prefs->SetString(prefs::kAcceptLanguages, new_accept_languages_str);
    403   }
    404 }
    405 
    406 // TranslatePrefs: private: ----------------------------------------------------
    407 
    408 // static
    409 void TranslatePrefs::CreateBlockedLanguages(
    410     std::vector<std::string>* blocked_languages,
    411     const std::vector<std::string>& blacklisted_languages,
    412     const std::vector<std::string>& accept_languages) {
    413   DCHECK(blocked_languages->empty());
    414 
    415   std::set<std::string> result;
    416 
    417   for (std::vector<std::string>::const_iterator it =
    418            blacklisted_languages.begin();
    419        it != blacklisted_languages.end(); ++it) {
    420     result.insert(*it);
    421   }
    422 
    423   for (std::vector<std::string>::const_iterator it = accept_languages.begin();
    424        it != accept_languages.end(); ++it) {
    425     std::string lang = *it;
    426     TranslateUtil::ToTranslateLanguageSynonym(&lang);
    427     result.insert(lang);
    428   }
    429 
    430   blocked_languages->insert(blocked_languages->begin(),
    431                             result.begin(), result.end());
    432 }
    433 
    434 bool TranslatePrefs::IsValueInList(const ListValue* list,
    435     const std::string& in_value) const {
    436   for (size_t i = 0; i < list->GetSize(); ++i) {
    437     std::string value;
    438     if (list->GetString(i, &value) && value == in_value)
    439       return true;
    440   }
    441   return false;
    442 }
    443 
    444 bool TranslatePrefs::IsValueBlacklisted(const char* pref_id,
    445     const std::string& value) const {
    446   const ListValue* blacklist = prefs_->GetList(pref_id);
    447   return (blacklist && !blacklist->empty() && IsValueInList(blacklist, value));
    448 }
    449 
    450 void TranslatePrefs::BlacklistValue(const char* pref_id,
    451     const std::string& value) {
    452   {
    453     ListPrefUpdate update(prefs_, pref_id);
    454     ListValue* blacklist = update.Get();
    455     if (!blacklist) {
    456       NOTREACHED() << "Unregistered translate blacklist pref";
    457       return;
    458     }
    459     blacklist->Append(new StringValue(value));
    460   }
    461 }
    462 
    463 void TranslatePrefs::RemoveValueFromBlacklist(const char* pref_id,
    464     const std::string& value) {
    465   ListPrefUpdate update(prefs_, pref_id);
    466   ListValue* blacklist = update.Get();
    467   if (!blacklist) {
    468     NOTREACHED() << "Unregistered translate blacklist pref";
    469     return;
    470   }
    471   StringValue string_value(value);
    472   blacklist->Remove(string_value, NULL);
    473 }
    474 
    475 bool TranslatePrefs::IsLanguageWhitelisted(
    476     const std::string& original_language, std::string* target_language) const {
    477   const DictionaryValue* dict = prefs_->GetDictionary(kPrefTranslateWhitelists);
    478   if (dict && dict->GetString(original_language, target_language)) {
    479     DCHECK(!target_language->empty());
    480     return !target_language->empty();
    481   }
    482   return false;
    483 }
    484 
    485 bool TranslatePrefs::IsListEmpty(const char* pref_id) const {
    486   const ListValue* blacklist = prefs_->GetList(pref_id);
    487   return (blacklist == NULL || blacklist->empty());
    488 }
    489 
    490 bool TranslatePrefs::IsDictionaryEmpty(const char* pref_id) const {
    491   const DictionaryValue* dict = prefs_->GetDictionary(pref_id);
    492   return (dict == NULL || dict->empty());
    493 }
    494