OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/translate/translate_language_list.h" | 5 #include "chrome/browser/translate/translate_language_list.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
98 "https://translate.googleapis.com/translate_a/l?client=chrome&cb=sl"; | 98 "https://translate.googleapis.com/translate_a/l?client=chrome&cb=sl"; |
99 | 99 |
100 // Used in kTranslateScriptURL to request supporting languages list including | 100 // Used in kTranslateScriptURL to request supporting languages list including |
101 // "alpha languages". | 101 // "alpha languages". |
102 const char kAlphaLanguageQueryName[] = "alpha"; | 102 const char kAlphaLanguageQueryName[] = "alpha"; |
103 const char kAlphaLanguageQueryValue[] = "1"; | 103 const char kAlphaLanguageQueryValue[] = "1"; |
104 | 104 |
105 // Retry parameter for fetching supporting language list. | 105 // Retry parameter for fetching supporting language list. |
106 const int kMaxRetryLanguageListFetch = 5; | 106 const int kMaxRetryLanguageListFetch = 5; |
107 | 107 |
108 // Parses |language_list| containing the list of languages that the translate | |
109 // server can translate to and from, and fills |set| with them. | |
110 void SetSupportedLanguages(const std::string& language_list, | |
111 std::set<std::string>* set) { | |
112 DCHECK(set); | |
113 // The format is: | |
114 // sl({"sl": {"XX": "LanguageName", ...}, "tl": {"XX": "LanguageName", ...}}) | |
115 // Where "sl(" is set in kLanguageListCallbackName | |
116 // and "tl" is kTargetLanguagesKey | |
117 if (!StartsWithASCII(language_list, | |
118 TranslateLanguageList::kLanguageListCallbackName, | |
119 false) || | |
120 !EndsWith(language_list, ")", false)) { | |
121 // We don't have a NOTREACHED here since this can happen in ui_tests, even | |
122 // though the the BrowserMain function won't call us with parameters.ui_task | |
123 // is NULL some tests don't set it, so we must bail here. | |
124 return; | |
125 } | |
126 static const size_t kLanguageListCallbackNameLength = | |
127 strlen(TranslateLanguageList::kLanguageListCallbackName); | |
128 std::string languages_json = language_list.substr( | |
129 kLanguageListCallbackNameLength, | |
130 language_list.size() - kLanguageListCallbackNameLength - 1); | |
131 scoped_ptr<Value> json_value( | |
132 base::JSONReader::Read(languages_json, base::JSON_ALLOW_TRAILING_COMMAS)); | |
133 if (json_value == NULL || !json_value->IsType(Value::TYPE_DICTIONARY)) { | |
134 NOTREACHED(); | |
135 return; | |
136 } | |
137 // The first level dictionary contains two sub-dict, one for source languages | |
138 // and the other for target languages, we want to use the target languages. | |
139 DictionaryValue* language_dict = | |
140 static_cast<DictionaryValue*>(json_value.get()); | |
141 DictionaryValue* target_languages = NULL; | |
142 if (!language_dict->GetDictionary(TranslateLanguageList::kTargetLanguagesKey, | |
143 &target_languages) || | |
144 target_languages == NULL) { | |
145 NOTREACHED(); | |
146 return; | |
147 } | |
148 | |
149 // Now we can clear language list. | |
150 set->clear(); | |
151 // ... and replace it with the values we just fetched from the server. | |
152 for (DictionaryValue::Iterator iter(*target_languages); | |
153 !iter.IsAtEnd(); | |
154 iter.Advance()) { | |
155 // TODO(toyoshim): Check if UI libraries support adding locale. | |
156 set->insert(iter.key()); | |
157 } | |
158 } | |
159 | |
160 net::URLFetcher* CreateAndStartFetch(const GURL& url, | |
161 net::URLFetcherDelegate* delegate) { | |
162 DCHECK(delegate); | |
163 VLOG(9) << "Fetch supporting language list from: " << url.spec().c_str(); | |
164 | |
165 scoped_ptr<net::URLFetcher> fetcher; | |
166 fetcher.reset(net::URLFetcher::Create(1, | |
167 url, | |
168 net::URLFetcher::GET, | |
169 delegate)); | |
170 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | |
171 net::LOAD_DO_NOT_SAVE_COOKIES); | |
172 fetcher->SetRequestContext(g_browser_process->system_request_context()); | |
173 fetcher->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch); | |
174 fetcher->Start(); | |
175 | |
176 return fetcher.release(); | |
177 } | |
178 | |
108 } // namespace | 179 } // namespace |
109 | 180 |
110 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL. | 181 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL. |
111 const char TranslateLanguageList::kLanguageListCallbackName[] = "sl("; | 182 const char TranslateLanguageList::kLanguageListCallbackName[] = "sl("; |
112 const char TranslateLanguageList::kTargetLanguagesKey[] = "tl"; | 183 const char TranslateLanguageList::kTargetLanguagesKey[] = "tl"; |
113 | 184 |
114 TranslateLanguageList::TranslateLanguageList() { | 185 TranslateLanguageList::TranslateLanguageList() { |
115 // We default to our hard coded list of languages in | 186 // We default to our hard coded list of languages in |
116 // |kDefaultSupportedLanguages|. This list will be overriden by a server | 187 // |kDefaultSupportedLanguages|. This list will be overriden by a server |
117 // providing supported langauges list. | 188 // providing supported langauges list. |
118 for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i) | 189 for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i) |
119 supported_languages_.insert(kDefaultSupportedLanguages[i]); | 190 supported_languages_.insert(kDefaultSupportedLanguages[i]); |
120 } | 191 } |
121 | 192 |
122 TranslateLanguageList::~TranslateLanguageList() {} | 193 TranslateLanguageList::~TranslateLanguageList() {} |
123 | 194 |
124 void TranslateLanguageList::OnURLFetchComplete(const net::URLFetcher* source) { | 195 void TranslateLanguageList::OnURLFetchComplete(const net::URLFetcher* source) { |
125 DCHECK(url_fetcher_.get() == source); | 196 scoped_ptr<const net::URLFetcher> delete_ptr; |
126 scoped_ptr<const net::URLFetcher> delete_ptr(url_fetcher_.release()); | |
127 | 197 |
128 if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && | 198 if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && |
129 source->GetResponseCode() == net::HTTP_OK) { | 199 source->GetResponseCode() == net::HTTP_OK) { |
130 std::string data; | 200 std::string data; |
131 source->GetResponseAsString(&data); | 201 source->GetResponseAsString(&data); |
132 SetSupportedLanguages(data); | 202 if (language_list_fetcher_.get() == source) { |
203 delete_ptr.reset(language_list_fetcher_.release()); | |
204 SetSupportedLanguages(data, &supported_languages_); | |
205 } else if (alpha_language_list_fetcher_.get() == source) { | |
206 delete_ptr.reset(alpha_language_list_fetcher_.release()); | |
207 SetSupportedLanguages(data, &supported_alpha_languages_); | |
208 } else { | |
209 NOTREACHED(); | |
210 } | |
133 } else { | 211 } else { |
134 // TODO(toyoshim): Try again. http://crbug.com/244202 . | 212 // TODO(toyoshim): Try again. http://crbug.com/244202 . |
213 // Also In CrOS, FetchLanguageList is not called at launching Chrome. It | |
214 // will solve this problem that check if FetchLanguageList is already | |
215 // called, and call it if needed in InitSupportedLanguage(). | |
135 VLOG(9) << "Failed to Fetch languages from: " << kLanguageListFetchURL; | 216 VLOG(9) << "Failed to Fetch languages from: " << kLanguageListFetchURL; |
136 } | 217 } |
137 } | 218 } |
138 | 219 |
139 void TranslateLanguageList::GetSupportedLanguages( | 220 void TranslateLanguageList::GetSupportedLanguages( |
140 std::vector<std::string>* languages) { | 221 std::vector<std::string>* languages) { |
141 DCHECK(languages && languages->empty()); | 222 DCHECK(languages && languages->empty()); |
142 std::set<std::string>::const_iterator iter = supported_languages_.begin(); | 223 std::set<std::string>& list = |
143 for (; iter != supported_languages_.end(); ++iter) | 224 supported_alpha_languages_.empty() ? supported_languages_ : |
225 supported_alpha_languages_; | |
226 for (std::set<std::string>::const_iterator iter = list.begin(); | |
227 iter != list.end(); ++iter) | |
144 languages->push_back(*iter); | 228 languages->push_back(*iter); |
145 } | 229 } |
146 | 230 |
147 std::string TranslateLanguageList::GetLanguageCode( | 231 std::string TranslateLanguageList::GetLanguageCode( |
148 const std::string& chrome_locale) { | 232 const std::string& chrome_locale) { |
149 // Only remove the country code for country specific languages we don't | 233 // Only remove the country code for country specific languages we don't |
150 // support specifically yet. | 234 // support specifically yet. |
151 if (IsSupportedLanguage(chrome_locale)) | 235 if (IsSupportedLanguage(chrome_locale)) |
152 return chrome_locale; | 236 return chrome_locale; |
153 | 237 |
154 size_t hypen_index = chrome_locale.find('-'); | 238 size_t hypen_index = chrome_locale.find('-'); |
155 if (hypen_index == std::string::npos) | 239 if (hypen_index == std::string::npos) |
156 return chrome_locale; | 240 return chrome_locale; |
157 return chrome_locale.substr(0, hypen_index); | 241 return chrome_locale.substr(0, hypen_index); |
158 } | 242 } |
159 | 243 |
160 bool TranslateLanguageList::IsSupportedLanguage( | 244 bool TranslateLanguageList::IsSupportedLanguage(const std::string& language) { |
161 const std::string& page_language) { | 245 // Langauge should exist at least one of these two language lists. |
162 return supported_languages_.count(page_language) != 0; | 246 return supported_alpha_languages_.count(language) != 0 || |
247 supported_languages_.count(language) != 0; | |
248 } | |
249 | |
250 bool TranslateLanguageList::IsAlphaLanguage(const std::string& language) { | |
251 // Language should exist only in the alpha language list. | |
252 return supported_alpha_languages_.count(language) != 0 && | |
253 supported_languages_.count(language) == 0; | |
163 } | 254 } |
164 | 255 |
165 void TranslateLanguageList::RequestLanguageList() { | 256 void TranslateLanguageList::RequestLanguageList() { |
166 if (url_fetcher_.get()) | 257 if (language_list_fetcher_.get() || alpha_language_list_fetcher_.get()) |
167 return; | 258 return; |
168 | 259 |
MAD
2013/05/30 14:58:01
I was wondering if we should just isolate them ind
| |
260 // Fetch the stable language list. | |
169 GURL language_list_fetch_url = GURL(kLanguageListFetchURL); | 261 GURL language_list_fetch_url = GURL(kLanguageListFetchURL); |
170 language_list_fetch_url = | 262 language_list_fetch_url = |
171 TranslateURLUtil::AddHostLocaleToUrl(language_list_fetch_url); | 263 TranslateURLUtil::AddHostLocaleToUrl(language_list_fetch_url); |
172 language_list_fetch_url = | 264 language_list_fetch_url = |
173 TranslateURLUtil::AddApiKeyToUrl(language_list_fetch_url); | 265 TranslateURLUtil::AddApiKeyToUrl(language_list_fetch_url); |
174 | 266 |
267 language_list_fetcher_.reset( | |
268 CreateAndStartFetch(language_list_fetch_url, this)); | |
269 | |
270 // TODO(toyoshim): Make it enabled by default. http://crbug.com/242178 | |
175 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 271 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
176 if (command_line.HasSwitch(switches::kEnableTranslateAlphaLanguages)) { | 272 if (!command_line.HasSwitch(switches::kEnableTranslateAlphaLanguages)) |
177 language_list_fetch_url = net::AppendQueryParameter( | 273 return; |
178 language_list_fetch_url, | |
179 kAlphaLanguageQueryName, | |
180 kAlphaLanguageQueryValue); | |
181 } | |
182 | 274 |
183 VLOG(9) << "Fetch supporting language list from: " | 275 // Fetch the alpha language list. |
184 << language_list_fetch_url.spec().c_str(); | 276 language_list_fetch_url = net::AppendQueryParameter( |
277 language_list_fetch_url, | |
278 kAlphaLanguageQueryName, | |
279 kAlphaLanguageQueryValue); | |
185 | 280 |
186 url_fetcher_.reset(net::URLFetcher::Create(1, | 281 alpha_language_list_fetcher_.reset( |
187 language_list_fetch_url, | 282 CreateAndStartFetch(language_list_fetch_url, this)); |
188 net::URLFetcher::GET, | |
189 this)); | |
190 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | |
191 net::LOAD_DO_NOT_SAVE_COOKIES); | |
192 url_fetcher_->SetRequestContext(g_browser_process->system_request_context()); | |
193 url_fetcher_->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch); | |
194 url_fetcher_->Start(); | |
195 } | 283 } |
196 | |
197 void TranslateLanguageList::SetSupportedLanguages( | |
198 const std::string& language_list) { | |
199 // The format is: | |
200 // sl({"sl": {"XX": "LanguageName", ...}, "tl": {"XX": "LanguageName", ...}}) | |
201 // Where "sl(" is set in kLanguageListCallbackName | |
202 // and "tl" is kTargetLanguagesKey | |
203 if (!StartsWithASCII(language_list, | |
204 TranslateLanguageList::kLanguageListCallbackName, | |
205 false) || | |
206 !EndsWith(language_list, ")", false)) { | |
207 // We don't have a NOTREACHED here since this can happen in ui_tests, even | |
208 // though the the BrowserMain function won't call us with parameters.ui_task | |
209 // is NULL some tests don't set it, so we must bail here. | |
210 return; | |
211 } | |
212 static const size_t kLanguageListCallbackNameLength = | |
213 strlen(TranslateLanguageList::kLanguageListCallbackName); | |
214 std::string languages_json = language_list.substr( | |
215 kLanguageListCallbackNameLength, | |
216 language_list.size() - kLanguageListCallbackNameLength - 1); | |
217 scoped_ptr<Value> json_value( | |
218 base::JSONReader::Read(languages_json, base::JSON_ALLOW_TRAILING_COMMAS)); | |
219 if (json_value == NULL || !json_value->IsType(Value::TYPE_DICTIONARY)) { | |
220 NOTREACHED(); | |
221 return; | |
222 } | |
223 // The first level dictionary contains two sub-dict, one for source languages | |
224 // and the other for target languages, we want to use the target languages. | |
225 DictionaryValue* language_dict = | |
226 static_cast<DictionaryValue*>(json_value.get()); | |
227 DictionaryValue* target_languages = NULL; | |
228 if (!language_dict->GetDictionary(TranslateLanguageList::kTargetLanguagesKey, | |
229 &target_languages) || | |
230 target_languages == NULL) { | |
231 NOTREACHED(); | |
232 return; | |
233 } | |
234 // Now we can clear our current state... | |
235 supported_languages_.clear(); | |
236 // ... and replace it with the values we just fetched from the server. | |
237 for (DictionaryValue::Iterator iter(*target_languages); | |
238 !iter.IsAtEnd(); | |
239 iter.Advance()) { | |
240 supported_languages_.insert(iter.key()); | |
241 } | |
242 } | |
OLD | NEW |