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/prefs/pref_change_registrar.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/translate/translate_manager.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/translate/common/translate_util.h"
18 #include "content/public/browser/notification_source.h"
19 #include "net/url_request/url_fetcher.h"
20 #include "ui/base/l10n/l10n_util.h"
21
TranslateAcceptLanguages()22 TranslateAcceptLanguages::TranslateAcceptLanguages() {
23 }
24
~TranslateAcceptLanguages()25 TranslateAcceptLanguages::~TranslateAcceptLanguages() {
26 }
27
28 // static
CanBeAcceptLanguage(const std::string & language)29 bool TranslateAcceptLanguages::CanBeAcceptLanguage(
30 const std::string& language) {
31 std::string accept_language = language;
32 translate::ToChromeLanguageSynonym(&accept_language);
33
34 const std::string locale = g_browser_process->GetApplicationLocale();
35 std::vector<std::string> accept_language_codes;
36 l10n_util::GetAcceptLanguagesForLocale(locale, &accept_language_codes);
37
38 if (std::find(accept_language_codes.begin(),
39 accept_language_codes.end(),
40 accept_language) != accept_language_codes.end()) {
41 return true;
42 }
43
44 return false;
45 }
46
IsAcceptLanguage(Profile * profile,const std::string & language)47 bool TranslateAcceptLanguages::IsAcceptLanguage(Profile* profile,
48 const std::string& language) {
49 DCHECK(profile);
50
51 PrefService* pref_service = profile->GetPrefs();
52 PrefServiceLanguagesMap::const_iterator iter =
53 accept_languages_.find(pref_service);
54 if (iter == accept_languages_.end()) {
55 InitAcceptLanguages(pref_service);
56 // Listen for this profile going away, in which case we would need to clear
57 // the accepted languages for the profile.
58 notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
59 content::Source<Profile>(profile));
60 // Also start listening for changes in the accept languages.
61 DCHECK(pref_change_registrars_.find(pref_service) ==
62 pref_change_registrars_.end());
63 PrefChangeRegistrar* pref_change_registrar = new PrefChangeRegistrar;
64 pref_change_registrar->Init(pref_service);
65 pref_change_registrar->Add(
66 prefs::kAcceptLanguages,
67 base::Bind(&TranslateAcceptLanguages::InitAcceptLanguages,
68 base::Unretained(this),
69 pref_service));
70 pref_change_registrars_[pref_service] = pref_change_registrar;
71
72 iter = accept_languages_.find(pref_service);
73 }
74
75 std::string accept_language = language;
76 translate::ToChromeLanguageSynonym(&accept_language);
77 return iter->second.count(accept_language) != 0;
78 }
79
InitAcceptLanguages(PrefService * prefs)80 void TranslateAcceptLanguages::InitAcceptLanguages(PrefService* prefs) {
81 DCHECK(prefs);
82
83 // We have been asked for this profile, build the languages.
84 std::string accept_langs_str = prefs->GetString(prefs::kAcceptLanguages);
85 std::vector<std::string> accept_langs_list;
86 LanguageSet accept_langs_set;
87 base::SplitString(accept_langs_str, ',', &accept_langs_list);
88 std::vector<std::string>::const_iterator iter;
89
90 for (iter = accept_langs_list.begin();
91 iter != accept_langs_list.end(); ++iter) {
92 // Get rid of the locale extension if any (ex: en-US -> en), but for Chinese
93 // for which the CLD reports zh-CN and zh-TW.
94 std::string accept_lang(*iter);
95 size_t index = iter->find("-");
96 if (index != std::string::npos && *iter != "zh-CN" && *iter != "zh-TW")
97 accept_lang = iter->substr(0, index);
98
99 accept_langs_set.insert(accept_lang);
100 }
101 accept_languages_[prefs] = accept_langs_set;
102 }
103
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)104 void TranslateAcceptLanguages::Observe(int type,
105 const content::NotificationSource& source,
106 const content::NotificationDetails& details) {
107 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
108
109 PrefService* pref_service =
110 content::Source<Profile>(source).ptr()->GetPrefs();
111 notification_registrar_.Remove(this,
112 chrome::NOTIFICATION_PROFILE_DESTROYED,
113 source);
114 size_t count = accept_languages_.erase(pref_service);
115 // We should know about this profile since we are listening for
116 // notifications on it.
117 DCHECK_EQ(1u, count);
118 PrefChangeRegistrar* pref_change_registrar =
119 pref_change_registrars_[pref_service];
120 count = pref_change_registrars_.erase(pref_service);
121 DCHECK_EQ(1u, count);
122 delete pref_change_registrar;
123 }
124