Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: chrome/browser/translate/translate_prefs.cc

Issue 159883002: Move TranslatePrefs to the Translate component (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@acceptLanguages
Patch Set: Fix ChromeOS browsertests Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <set>
8
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.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/profiles/profile.h"
15 #include "chrome/browser/translate/translate_accept_languages_factory.h"
16 #include "chrome/browser/translate/translate_manager.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/translate/core/browser/translate_accept_languages.h"
19 #include "components/translate/core/browser/translate_download_manager.h"
20 #include "components/translate/core/common/translate_util.h"
21 #include "components/user_prefs/pref_registry_syncable.h"
22
23 const char TranslatePrefs::kPrefTranslateLanguageBlacklist[] =
24 "translate_language_blacklist";
25 const char TranslatePrefs::kPrefTranslateSiteBlacklist[] =
26 "translate_site_blacklist";
27 const char TranslatePrefs::kPrefTranslateWhitelists[] =
28 "translate_whitelists";
29 const char TranslatePrefs::kPrefTranslateDeniedCount[] =
30 "translate_denied_count";
31 const char TranslatePrefs::kPrefTranslateAcceptedCount[] =
32 "translate_accepted_count";
33 const char TranslatePrefs::kPrefTranslateBlockedLanguages[] =
34 "translate_blocked_languages";
35
36 namespace {
37
38 void GetBlacklistedLanguages(const PrefService* prefs,
39 std::vector<std::string>* languages) {
40 DCHECK(languages);
41 DCHECK(languages->empty());
42
43 const char* key = TranslatePrefs::kPrefTranslateLanguageBlacklist;
44 const base::ListValue* list = prefs->GetList(key);
45 for (base::ListValue::const_iterator it = list->begin();
46 it != list->end(); ++it) {
47 std::string lang;
48 (*it)->GetAsString(&lang);
49 languages->push_back(lang);
50 }
51 }
52
53 // Expands language codes to make these more suitable for Accept-Language.
54 // Example: ['en-US', 'ja', 'en-CA'] => ['en-US', 'en', 'ja', 'en-CA'].
55 // 'en' won't appear twice as this function eliminates duplicates.
56 void ExpandLanguageCodes(const std::vector<std::string>& languages,
57 std::vector<std::string>* expanded_languages) {
58 DCHECK(expanded_languages);
59 DCHECK(expanded_languages->empty());
60
61 // used to eliminate duplicates.
62 std::set<std::string> seen;
63
64 for (std::vector<std::string>::const_iterator it = languages.begin();
65 it != languages.end(); ++it) {
66 const std::string& language = *it;
67 if (seen.find(language) == seen.end()) {
68 expanded_languages->push_back(language);
69 seen.insert(language);
70 }
71
72 std::vector<std::string> tokens;
73 base::SplitString(language, '-', &tokens);
74 if (tokens.size() == 0)
75 continue;
76 const std::string& main_part = tokens[0];
77 if (seen.find(main_part) == seen.end()) {
78 expanded_languages->push_back(main_part);
79 seen.insert(main_part);
80 }
81 }
82 }
83
84 } // namespace
85
86 TranslatePrefs::TranslatePrefs(PrefService* user_prefs)
87 : prefs_(user_prefs) {
88 }
89
90 void TranslatePrefs::ResetToDefaults() {
91 ClearBlockedLanguages();
92 ClearBlacklistedSites();
93 ClearWhitelistedLanguagePairs();
94
95 std::vector<std::string> languages;
96 GetLanguageList(&languages);
97 for (std::vector<std::string>::const_iterator it = languages.begin();
98 it != languages.end(); ++it) {
99 const std::string& language = *it;
100 ResetTranslationAcceptedCount(language);
101 ResetTranslationDeniedCount(language);
102 }
103 }
104
105 bool TranslatePrefs::IsBlockedLanguage(
106 const std::string& original_language) const {
107 return IsValueBlacklisted(kPrefTranslateBlockedLanguages,
108 original_language);
109 }
110
111 void TranslatePrefs::BlockLanguage(
112 const std::string& original_language) {
113 BlacklistValue(kPrefTranslateBlockedLanguages, original_language);
114
115 // Add the language to the language list at chrome://settings/languages.
116 std::string language = original_language;
117 translate::ToChromeLanguageSynonym(&language);
118
119 std::vector<std::string> languages;
120 GetLanguageList(&languages);
121
122 if (std::find(languages.begin(), languages.end(), language) ==
123 languages.end()) {
124 languages.push_back(language);
125 UpdateLanguageList(languages);
126 }
127 }
128
129 void TranslatePrefs::UnblockLanguage(
130 const std::string& original_language) {
131 RemoveValueFromBlacklist(kPrefTranslateBlockedLanguages,
132 original_language);
133 }
134
135 void TranslatePrefs::RemoveLanguageFromLegacyBlacklist(
136 const std::string& original_language) {
137 RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist,
138 original_language);
139 }
140
141 bool TranslatePrefs::IsSiteBlacklisted(const std::string& site) const {
142 return IsValueBlacklisted(kPrefTranslateSiteBlacklist, site);
143 }
144
145 void TranslatePrefs::BlacklistSite(const std::string& site) {
146 BlacklistValue(kPrefTranslateSiteBlacklist, site);
147 }
148
149 void TranslatePrefs::RemoveSiteFromBlacklist(const std::string& site) {
150 RemoveValueFromBlacklist(kPrefTranslateSiteBlacklist, site);
151 }
152
153 bool TranslatePrefs::IsLanguagePairWhitelisted(
154 const std::string& original_language,
155 const std::string& target_language) {
156 const base::DictionaryValue* dict =
157 prefs_->GetDictionary(kPrefTranslateWhitelists);
158 if (dict && !dict->empty()) {
159 std::string auto_target_lang;
160 if (dict->GetString(original_language, &auto_target_lang) &&
161 auto_target_lang == target_language)
162 return true;
163 }
164 return false;
165 }
166
167 void TranslatePrefs::WhitelistLanguagePair(
168 const std::string& original_language,
169 const std::string& target_language) {
170 DictionaryPrefUpdate update(prefs_, kPrefTranslateWhitelists);
171 base::DictionaryValue* dict = update.Get();
172 if (!dict) {
173 NOTREACHED() << "Unregistered translate whitelist pref";
174 return;
175 }
176 dict->SetString(original_language, target_language);
177 }
178
179 void TranslatePrefs::RemoveLanguagePairFromWhitelist(
180 const std::string& original_language,
181 const std::string& target_language) {
182 DictionaryPrefUpdate update(prefs_, kPrefTranslateWhitelists);
183 base::DictionaryValue* dict = update.Get();
184 if (!dict) {
185 NOTREACHED() << "Unregistered translate whitelist pref";
186 return;
187 }
188 dict->Remove(original_language, NULL);
189 }
190
191 bool TranslatePrefs::HasBlockedLanguages() const {
192 return !IsListEmpty(kPrefTranslateBlockedLanguages);
193 }
194
195 void TranslatePrefs::ClearBlockedLanguages() {
196 prefs_->ClearPref(kPrefTranslateBlockedLanguages);
197 }
198
199 bool TranslatePrefs::HasBlacklistedSites() const {
200 return !IsListEmpty(kPrefTranslateSiteBlacklist);
201 }
202
203 void TranslatePrefs::ClearBlacklistedSites() {
204 prefs_->ClearPref(kPrefTranslateSiteBlacklist);
205 }
206
207 bool TranslatePrefs::HasWhitelistedLanguagePairs() const {
208 return !IsDictionaryEmpty(kPrefTranslateWhitelists);
209 }
210
211 void TranslatePrefs::ClearWhitelistedLanguagePairs() {
212 prefs_->ClearPref(kPrefTranslateWhitelists);
213 }
214
215 int TranslatePrefs::GetTranslationDeniedCount(
216 const std::string& language) const {
217 const base::DictionaryValue* dict =
218 prefs_->GetDictionary(kPrefTranslateDeniedCount);
219 int count = 0;
220 return dict->GetInteger(language, &count) ? count : 0;
221 }
222
223 void TranslatePrefs::IncrementTranslationDeniedCount(
224 const std::string& language) {
225 DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount);
226 base::DictionaryValue* dict = update.Get();
227
228 int count = 0;
229 dict->GetInteger(language, &count);
230 dict->SetInteger(language, count + 1);
231 }
232
233 void TranslatePrefs::ResetTranslationDeniedCount(const std::string& language) {
234 DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount);
235 update.Get()->SetInteger(language, 0);
236 }
237
238 int TranslatePrefs::GetTranslationAcceptedCount(const std::string& language) {
239 const base::DictionaryValue* dict =
240 prefs_->GetDictionary(kPrefTranslateAcceptedCount);
241 int count = 0;
242 return dict->GetInteger(language, &count) ? count : 0;
243 }
244
245 void TranslatePrefs::IncrementTranslationAcceptedCount(
246 const std::string& language) {
247 DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount);
248 base::DictionaryValue* dict = update.Get();
249 int count = 0;
250 dict->GetInteger(language, &count);
251 dict->SetInteger(language, count + 1);
252 }
253
254 void TranslatePrefs::ResetTranslationAcceptedCount(
255 const std::string& language) {
256 DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount);
257 update.Get()->SetInteger(language, 0);
258 }
259
260 void TranslatePrefs::GetLanguageList(std::vector<std::string>* languages) {
261 DCHECK(languages);
262 DCHECK(languages->empty());
263
264 #if defined(OS_CHROMEOS)
265 const char* key = prefs::kLanguagePreferredLanguages;
266 #else
267 const char* key = prefs::kAcceptLanguages;
268 #endif
269
270 std::string languages_str = prefs_->GetString(key);
271 base::SplitString(languages_str, ',', languages);
272 }
273
274 void TranslatePrefs::UpdateLanguageList(
275 const std::vector<std::string>& languages) {
276 #if defined(OS_CHROMEOS)
277 std::string languages_str = JoinString(languages, ',');
278 prefs_->SetString(prefs::kLanguagePreferredLanguages, languages_str);
279 #endif
280
281 // Save the same language list as accept languages preference as well, but we
282 // need to expand the language list, to make it more acceptable. For instance,
283 // some web sites don't understand 'en-US' but 'en'. See crosbug.com/9884.
284 std::vector<std::string> accept_languages;
285 ExpandLanguageCodes(languages, &accept_languages);
286 std::string accept_languages_str = JoinString(accept_languages, ',');
287 prefs_->SetString(prefs::kAcceptLanguages, accept_languages_str);
288 }
289
290 // static
291 bool TranslatePrefs::CanTranslateLanguage(Profile* profile,
292 const std::string& language) {
293 TranslatePrefs translate_prefs(profile->GetPrefs());
294 bool blocked = translate_prefs.IsBlockedLanguage(language);
295
296 TranslateAcceptLanguages* accept_languages =
297 TranslateAcceptLanguagesFactory::GetForBrowserContext(profile);
298 bool is_accept_language = accept_languages->IsAcceptLanguage(language);
299 bool can_be_accept_language =
300 TranslateAcceptLanguages::CanBeAcceptLanguage(language);
301
302 // Don't translate any user black-listed languages. Checking
303 // |is_accept_language| is necessary because if the user eliminates the
304 // language from the preference, it is natural to forget whether or not
305 // the language should be translated. Checking |cannot_be_accept_language|
306 // is also necessary because some minor languages can't be selected in the
307 // language preference even though the language is available in Translate
308 // server.
309 if (blocked && (is_accept_language || !can_be_accept_language))
310 return false;
311
312 return true;
313 }
314
315 // static
316 bool TranslatePrefs::ShouldAutoTranslate(PrefService* user_prefs,
317 const std::string& original_language, std::string* target_language) {
318 TranslatePrefs prefs(user_prefs);
319 return prefs.IsLanguageWhitelisted(original_language, target_language);
320 }
321
322 // static
323 void TranslatePrefs::RegisterProfilePrefs(
324 user_prefs::PrefRegistrySyncable* registry) {
325 registry->RegisterListPref(kPrefTranslateLanguageBlacklist,
326 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
327 registry->RegisterListPref(kPrefTranslateSiteBlacklist,
328 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
329 registry->RegisterDictionaryPref(
330 kPrefTranslateWhitelists,
331 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
332 registry->RegisterDictionaryPref(
333 kPrefTranslateDeniedCount,
334 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
335 registry->RegisterDictionaryPref(
336 kPrefTranslateAcceptedCount,
337 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
338 registry->RegisterListPref(kPrefTranslateBlockedLanguages,
339 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
340 }
341
342 // static
343 void TranslatePrefs::MigrateUserPrefs(PrefService* user_prefs) {
344 // Old format of kPrefTranslateWhitelists
345 // - original language -> list of target langs to auto-translate
346 // - list of langs is in order of being enabled i.e. last in list is the
347 // most recent language that user enabled via
348 // Always translate |source_lang| to |target_lang|"
349 // - this results in a one-to-n relationship between source lang and target
350 // langs.
351 // New format:
352 // - original language -> one target language to auto-translate
353 // - each time that the user enables the "Always translate..." option, that
354 // target lang overwrites the previous one.
355 // - this results in a one-to-one relationship between source lang and target
356 // lang
357 // - we replace old list of target langs with the last target lang in list,
358 // assuming the last (i.e. most recent) target lang is what user wants to
359 // keep auto-translated.
360 DictionaryPrefUpdate update(user_prefs, kPrefTranslateWhitelists);
361 base::DictionaryValue* dict = update.Get();
362 if (dict && !dict->empty()) {
363 base::DictionaryValue::Iterator iter(*dict);
364 while (!iter.IsAtEnd()) {
365 const base::ListValue* list = NULL;
366 if (!iter.value().GetAsList(&list) || !list)
367 break; // Dictionary has either been migrated or new format.
368 std::string key = iter.key();
369 // Advance the iterator before removing the current element.
370 iter.Advance();
371 std::string target_lang;
372 if (list->empty() ||
373 !list->GetString(list->GetSize() - 1, &target_lang) ||
374 target_lang.empty()) {
375 dict->Remove(key, NULL);
376 } else {
377 dict->SetString(key, target_lang);
378 }
379 }
380 }
381
382 // Get the union of the blacklist and the Accept languages, and set this to
383 // the new language set 'translate_blocked_languages'. This is used for the
384 // settings UI for Translate and configration to determine which langauage
385 // should be translated instead of the blacklist. The blacklist is no longer
386 // used after launching the settings UI.
387 // After that, Set 'translate_languages_not_translate' to Accept languages to
388 // enable settings for users.
389 bool merged = user_prefs->HasPrefPath(kPrefTranslateBlockedLanguages);
390
391 if (!merged) {
392 std::vector<std::string> blacklisted_languages;
393 GetBlacklistedLanguages(user_prefs, &blacklisted_languages);
394
395 std::string accept_languages_str =
396 user_prefs->GetString(prefs::kAcceptLanguages);
397 std::vector<std::string> accept_languages;
398 base::SplitString(accept_languages_str, ',', &accept_languages);
399
400 std::vector<std::string> blocked_languages;
401 CreateBlockedLanguages(&blocked_languages,
402 blacklisted_languages,
403 accept_languages);
404
405 // Create the new preference kPrefTranslateBlockedLanguages.
406 {
407 base::ListValue blocked_languages_list;
408 for (std::vector<std::string>::const_iterator it =
409 blocked_languages.begin();
410 it != blocked_languages.end(); ++it) {
411 blocked_languages_list.Append(new base::StringValue(*it));
412 }
413 ListPrefUpdate update(user_prefs, kPrefTranslateBlockedLanguages);
414 base::ListValue* list = update.Get();
415 DCHECK(list != NULL);
416 list->Swap(&blocked_languages_list);
417 }
418
419 // Update kAcceptLanguages
420 for (std::vector<std::string>::const_iterator it =
421 blocked_languages.begin();
422 it != blocked_languages.end(); ++it) {
423 std::string lang = *it;
424 translate::ToChromeLanguageSynonym(&lang);
425 bool not_found =
426 std::find(accept_languages.begin(), accept_languages.end(), lang) ==
427 accept_languages.end();
428 if (not_found)
429 accept_languages.push_back(lang);
430 }
431
432 std::string new_accept_languages_str = JoinString(accept_languages, ",");
433 user_prefs->SetString(prefs::kAcceptLanguages, new_accept_languages_str);
434 }
435 }
436
437 // static
438 void TranslatePrefs::CreateBlockedLanguages(
439 std::vector<std::string>* blocked_languages,
440 const std::vector<std::string>& blacklisted_languages,
441 const std::vector<std::string>& accept_languages) {
442 DCHECK(blocked_languages);
443 DCHECK(blocked_languages->empty());
444
445 std::set<std::string> result;
446
447 for (std::vector<std::string>::const_iterator it =
448 blacklisted_languages.begin();
449 it != blacklisted_languages.end(); ++it) {
450 result.insert(*it);
451 }
452
453 const std::string& app_locale = g_browser_process->GetApplicationLocale();
454 std::string ui_lang = TranslateDownloadManager::GetLanguageCode(app_locale);
455 bool is_ui_english = ui_lang == "en" ||
456 StartsWithASCII(ui_lang, "en-", false);
457
458 for (std::vector<std::string>::const_iterator it = accept_languages.begin();
459 it != accept_languages.end(); ++it) {
460 std::string converted_lang = ConvertLangCodeForTranslation(*it);
461
462 // Regarding http://crbug.com/36182, even though English exists in Accept
463 // language list, English could be translated on non-English locale.
464 if (converted_lang == "en" && !is_ui_english)
465 continue;
466
467 result.insert(converted_lang);
468 }
469
470 blocked_languages->insert(blocked_languages->begin(),
471 result.begin(), result.end());
472 }
473
474 // static
475 std::string TranslatePrefs::ConvertLangCodeForTranslation(
476 const std::string &lang) {
477 std::vector<std::string> tokens;
478 base::SplitString(lang, '-', &tokens);
479 if (tokens.size() < 1)
480 return lang;
481
482 std::string main_part = tokens[0];
483
484 // Translate doesn't support General Chinese and the sub code is necessary.
485 if (main_part == "zh")
486 return lang;
487
488 translate::ToTranslateLanguageSynonym(&main_part);
489 return main_part;
490 }
491
492 bool TranslatePrefs::IsValueInList(const base::ListValue* list,
493 const std::string& in_value) const {
494 for (size_t i = 0; i < list->GetSize(); ++i) {
495 std::string value;
496 if (list->GetString(i, &value) && value == in_value)
497 return true;
498 }
499 return false;
500 }
501
502 bool TranslatePrefs::IsValueBlacklisted(const char* pref_id,
503 const std::string& value) const {
504 const base::ListValue* blacklist = prefs_->GetList(pref_id);
505 return (blacklist && !blacklist->empty() && IsValueInList(blacklist, value));
506 }
507
508 void TranslatePrefs::BlacklistValue(const char* pref_id,
509 const std::string& value) {
510 {
511 ListPrefUpdate update(prefs_, pref_id);
512 base::ListValue* blacklist = update.Get();
513 if (!blacklist) {
514 NOTREACHED() << "Unregistered translate blacklist pref";
515 return;
516 }
517 blacklist->Append(new base::StringValue(value));
518 }
519 }
520
521 void TranslatePrefs::RemoveValueFromBlacklist(const char* pref_id,
522 const std::string& value) {
523 ListPrefUpdate update(prefs_, pref_id);
524 base::ListValue* blacklist = update.Get();
525 if (!blacklist) {
526 NOTREACHED() << "Unregistered translate blacklist pref";
527 return;
528 }
529 base::StringValue string_value(value);
530 blacklist->Remove(string_value, NULL);
531 }
532
533 bool TranslatePrefs::IsLanguageWhitelisted(
534 const std::string& original_language, std::string* target_language) const {
535 const base::DictionaryValue* dict =
536 prefs_->GetDictionary(kPrefTranslateWhitelists);
537 if (dict && dict->GetString(original_language, target_language)) {
538 DCHECK(!target_language->empty());
539 return !target_language->empty();
540 }
541 return false;
542 }
543
544 bool TranslatePrefs::IsListEmpty(const char* pref_id) const {
545 const base::ListValue* blacklist = prefs_->GetList(pref_id);
546 return (blacklist == NULL || blacklist->empty());
547 }
548
549 bool TranslatePrefs::IsDictionaryEmpty(const char* pref_id) const {
550 const base::DictionaryValue* dict = prefs_->GetDictionary(pref_id);
551 return (dict == NULL || dict->empty());
552 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698