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

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

Issue 7171002: Get the list of supported languages from the translate server. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 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_manager.h" 5 #include "chrome/browser/translate/translate_manager.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/json/json_reader.h"
9 #include "base/memory/singleton.h" 10 #include "base/memory/singleton.h"
10 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
11 #include "base/string_split.h" 12 #include "base/string_split.h"
12 #include "base/string_util.h" 13 #include "base/string_util.h"
14 #include "base/values.h"
13 #include "chrome/browser/autofill/autofill_manager.h" 15 #include "chrome/browser/autofill/autofill_manager.h"
14 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/prefs/pref_service.h" 17 #include "chrome/browser/prefs/pref_service.h"
16 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/tab_contents/language_state.h" 19 #include "chrome/browser/tab_contents/language_state.h"
18 #include "chrome/browser/tab_contents/tab_util.h" 20 #include "chrome/browser/tab_contents/tab_util.h"
19 #include "chrome/browser/tabs/tab_strip_model.h" 21 #include "chrome/browser/tabs/tab_strip_model.h"
20 #include "chrome/browser/translate/page_translated_details.h" 22 #include "chrome/browser/translate/page_translated_details.h"
21 #include "chrome/browser/translate/translate_infobar_delegate.h" 23 #include "chrome/browser/translate/translate_infobar_delegate.h"
22 #include "chrome/browser/translate/translate_tab_helper.h" 24 #include "chrome/browser/translate/translate_tab_helper.h"
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 "yi", // Yiddish 119 "yi", // Yiddish
118 }; 120 };
119 121
120 const char* const kTranslateScriptURL = 122 const char* const kTranslateScriptURL =
121 "http://translate.google.com/translate_a/element.js?" 123 "http://translate.google.com/translate_a/element.js?"
122 "cb=cr.googleTranslate.onTranslateElementLoad"; 124 "cb=cr.googleTranslate.onTranslateElementLoad";
123 const char* const kTranslateScriptHeader = 125 const char* const kTranslateScriptHeader =
124 "Google-Translate-Element-Mode: library"; 126 "Google-Translate-Element-Mode: library";
125 const char* const kReportLanguageDetectionErrorURL = 127 const char* const kReportLanguageDetectionErrorURL =
126 "http://translate.google.com/translate_error"; 128 "http://translate.google.com/translate_error";
127 129 const char* const kLanguageListFetchURL =
130 "http://translate.googleapis.com/translate_a/l?client=chrome&cb=sl";
131 const int kMaxRetryLanguageListFetch = 5;
128 const int kTranslateScriptExpirationDelayMS = 24 * 60 * 60 * 1000; // 1 day. 132 const int kTranslateScriptExpirationDelayMS = 24 * 60 * 60 * 1000; // 1 day.
129 133
130 } // namespace 134 } // namespace
131 135
136 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL.
137 const char* const TranslateManager::kLanguageListCallbackName = "sl(";
138 const char* const TranslateManager::kTargetLanguagesKey = "tl";
139
132 // static 140 // static
133 base::LazyInstance<std::set<std::string> > 141 base::LazyInstance<std::set<std::string> >
134 TranslateManager::supported_languages_(base::LINKER_INITIALIZED); 142 TranslateManager::supported_languages_(base::LINKER_INITIALIZED);
135 143
136 TranslateManager::~TranslateManager() { 144 TranslateManager::~TranslateManager() {
137 } 145 }
138 146
139 // static 147 // static
140 TranslateManager* TranslateManager::GetInstance() { 148 TranslateManager* TranslateManager::GetInstance() {
141 return Singleton<TranslateManager>::get(); 149 return Singleton<TranslateManager>::get();
142 } 150 }
143 151
144 // static 152 // static
145 bool TranslateManager::IsTranslatableURL(const GURL& url) { 153 bool TranslateManager::IsTranslatableURL(const GURL& url) {
146 // A URLs is translatable unless it is one of the following: 154 // A URLs is translatable unless it is one of the following:
147 // - an internal URL (chrome:// and others) 155 // - an internal URL (chrome:// and others)
148 // - the devtools (which is considered UI) 156 // - the devtools (which is considered UI)
149 // - an FTP page (as FTP pages tend to have long lists of filenames that may 157 // - an FTP page (as FTP pages tend to have long lists of filenames that may
150 // confuse the CLD) 158 // confuse the CLD)
151 return !url.SchemeIs(chrome::kChromeUIScheme) && 159 return !url.SchemeIs(chrome::kChromeUIScheme) &&
152 !url.SchemeIs(chrome::kChromeDevToolsScheme) && 160 !url.SchemeIs(chrome::kChromeDevToolsScheme) &&
153 !url.SchemeIs(chrome::kFtpScheme); 161 !url.SchemeIs(chrome::kFtpScheme);
154 } 162 }
155 163
156 // static 164 // static
165 void TranslateManager::SetSupportedLanguages(const std::string& language_list) {
166 // The format is:
167 // sl({'sl': {'XX': 'LanguageName', ...}, 'tl': {'XX': 'LanguageName', ...}})
168 // Where "sl(" is set in kLanguageListCallbackName
169 // and 'tl' is kTargetLanguagesKey
170 if (!StartsWithASCII(language_list, kLanguageListCallbackName, false) ||
171 !EndsWith(language_list, ")", false)) {
172 // We don't have a NOTREACHED here since this can happen in ui_tests, even
173 // though the the BrowserMain function won't call us with parameters.ui_task
174 // is NULL some tests don't set it, so we must bail here.
175 return;
176 }
177 static const size_t kLanguageListCallbackNameLength =
178 strlen(kLanguageListCallbackName);
179 std::string languages_json = language_list.substr(
180 kLanguageListCallbackNameLength,
181 language_list.size() - kLanguageListCallbackNameLength - 1);
182 // JSON doesn't support single quotes though this is what is used on the
183 // translate server so we must replace them with double quotes.
184 ReplaceSubstringsAfterOffset(&languages_json, 0, "'", "\"");
185 scoped_ptr<Value> json_value(base::JSONReader::Read(languages_json, true));
186 if (json_value == NULL || !json_value->IsType(Value::TYPE_DICTIONARY)) {
187 NOTREACHED();
188 return;
189 }
190 // The first level dictionary contains two sub-dict, one for source languages
191 // and the other for target languages, we want to use the target languages.
192 DictionaryValue* language_dict =
193 static_cast<DictionaryValue*>(json_value.get());
194 DictionaryValue* target_languages = NULL;
195 if (!language_dict->GetDictionary(kTargetLanguagesKey, &target_languages) ||
196 target_languages == NULL) {
197 NOTREACHED();
198 return;
199 }
200 // Now we can clear our current state...
201 std::set<std::string>* supported_languages = supported_languages_.Pointer();
202 supported_languages->clear();
203 // ... and replace it with the values we just fetched from the server.
204 DictionaryValue::key_iterator iter = target_languages->begin_keys();
205 for (; iter != target_languages->end_keys(); ++iter)
206 supported_languages_.Pointer()->insert(*iter);
207 }
208
209 // static
210 void TranslateManager::InitSupportedLanguages() {
211 // If our list of supported languages have not been set yet, we default
212 // to our hard coded list of languages in kSupportedLanguages.
213 if (supported_languages_.Pointer()->empty()) {
214 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i)
215 supported_languages_.Pointer()->insert(kSupportedLanguages[i]);
216 }
217 }
218
219 // static
157 void TranslateManager::GetSupportedLanguages( 220 void TranslateManager::GetSupportedLanguages(
158 std::vector<std::string>* languages) { 221 std::vector<std::string>* languages) {
159 DCHECK(languages && languages->empty()); 222 DCHECK(languages && languages->empty());
160 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i) 223 InitSupportedLanguages();
161 languages->push_back(kSupportedLanguages[i]); 224 std::set<std::string>* supported_languages = supported_languages_.Pointer();
225 std::set<std::string>::const_iterator iter = supported_languages->begin();
226 for (; iter != supported_languages->end(); ++iter)
227 languages->push_back(*iter);
162 } 228 }
163 229
164 // static 230 // static
165 std::string TranslateManager::GetLanguageCode( 231 std::string TranslateManager::GetLanguageCode(
166 const std::string& chrome_locale) { 232 const std::string& chrome_locale) {
167 // 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
168 // support specifically yet. 234 // support specifically yet.
169 if (IsSupportedLanguage(chrome_locale)) 235 if (IsSupportedLanguage(chrome_locale))
170 return chrome_locale; 236 return chrome_locale;
171 237
172 size_t hypen_index = chrome_locale.find('-'); 238 size_t hypen_index = chrome_locale.find('-');
173 if (hypen_index == std::string::npos) 239 if (hypen_index == std::string::npos)
174 return chrome_locale; 240 return chrome_locale;
175 return chrome_locale.substr(0, hypen_index); 241 return chrome_locale.substr(0, hypen_index);
176 } 242 }
177 243
178 // static 244 // static
179 bool TranslateManager::IsSupportedLanguage(const std::string& page_language) { 245 bool TranslateManager::IsSupportedLanguage(const std::string& page_language) {
180 std::set<std::string>* supported_languages = supported_languages_.Pointer(); 246 InitSupportedLanguages();
181 if (supported_languages->empty()) { 247 return supported_languages_.Pointer()->count(page_language) != 0;
182 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i)
183 supported_languages->insert(kSupportedLanguages[i]);
184 }
185 return supported_languages->find(page_language) != supported_languages->end();
186 } 248 }
187 249
188 void TranslateManager::Observe(NotificationType type, 250 void TranslateManager::Observe(NotificationType type,
189 const NotificationSource& source, 251 const NotificationSource& source,
190 const NotificationDetails& details) { 252 const NotificationDetails& details) {
191 switch (type.value) { 253 switch (type.value) {
192 case NotificationType::NAV_ENTRY_COMMITTED: { 254 case NotificationType::NAV_ENTRY_COMMITTED: {
193 NavigationController* controller = 255 NavigationController* controller =
194 Source<NavigationController>(source).ptr(); 256 Source<NavigationController>(source).ptr();
195 content::LoadCommittedDetails* load_details = 257 content::LoadCommittedDetails* load_details =
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 } 343 }
282 } 344 }
283 345
284 void TranslateManager::OnURLFetchComplete(const URLFetcher* source, 346 void TranslateManager::OnURLFetchComplete(const URLFetcher* source,
285 const GURL& url, 347 const GURL& url,
286 const net::URLRequestStatus& status, 348 const net::URLRequestStatus& status,
287 int response_code, 349 int response_code,
288 const net::ResponseCookies& cookies, 350 const net::ResponseCookies& cookies,
289 const std::string& data) { 351 const std::string& data) {
290 scoped_ptr<const URLFetcher> delete_ptr(source); 352 scoped_ptr<const URLFetcher> delete_ptr(source);
291 DCHECK(translate_script_request_pending_); 353 DCHECK(translate_script_request_pending_ || language_list_request_pending_);
292 translate_script_request_pending_ = false; 354 // We quickly recognize that we are handling a translate script request
355 // if we don't have a language_list_request_pending_. Otherwise we do the
356 // more expensive check of confirming we got the kTranslateScriptURL in the
357 // rare case where we would have both requests pending at the same time.
358 bool translate_script_request = !language_list_request_pending_ ||
359 url == GURL(kTranslateScriptURL);
360 // Here we make sure that if we didn't get the translate_script_request,
361 // we actually got a language_list_request.
362 DCHECK(translate_script_request || url == GURL(kLanguageListFetchURL));
363 if (translate_script_request)
364 translate_script_request_pending_ = false;
365 else
366 language_list_request_pending_ = false;
367
293 bool error = 368 bool error =
294 (status.status() != net::URLRequestStatus::SUCCESS || 369 (status.status() != net::URLRequestStatus::SUCCESS ||
295 response_code != 200); 370 response_code != 200);
296 371
297 if (!error) { 372 if (translate_script_request) {
298 base::StringPiece str = ResourceBundle::GetSharedInstance(). 373 if (!error) {
299 GetRawDataResource(IDR_TRANSLATE_JS); 374 base::StringPiece str = ResourceBundle::GetSharedInstance().
300 DCHECK(translate_script_.empty()); 375 GetRawDataResource(IDR_TRANSLATE_JS);
301 str.CopyToString(&translate_script_); 376 DCHECK(translate_script_.empty());
302 translate_script_ += "\n" + data; 377 str.CopyToString(&translate_script_);
303 // We'll expire the cached script after some time, to make sure long running 378 translate_script_ += "\n" + data;
304 // browsers still get fixes that might get pushed with newer scripts. 379 // We'll expire the cached script after some time, to make sure long
305 MessageLoop::current()->PostDelayedTask(FROM_HERE, 380 // running browsers still get fixes that might get pushed with newer
306 method_factory_.NewRunnableMethod( 381 // scripts.
307 &TranslateManager::ClearTranslateScript), 382 MessageLoop::current()->PostDelayedTask(FROM_HERE,
308 translate_script_expiration_delay_); 383 method_factory_.NewRunnableMethod(
384 &TranslateManager::ClearTranslateScript),
385 translate_script_expiration_delay_);
386 }
387 // Process any pending requests.
388 std::vector<PendingRequest>::const_iterator iter;
389 for (iter = pending_requests_.begin(); iter != pending_requests_.end();
390 ++iter) {
391 const PendingRequest& request = *iter;
392 TabContents* tab = tab_util::GetTabContentsByID(request.render_process_id,
393 request.render_view_id);
394 if (!tab) {
395 // The tab went away while we were retrieving the script.
396 continue;
397 }
398 NavigationEntry* entry = tab->controller().GetActiveEntry();
399 if (!entry || entry->page_id() != request.page_id) {
400 // We navigated away from the page the translation was triggered on.
401 continue;
402 }
403
404 if (error) {
405 ShowInfoBar(tab, TranslateInfoBarDelegate::CreateErrorDelegate(
406 TranslateErrors::NETWORK, tab,
407 request.source_lang, request.target_lang));
408 } else {
409 // Translate the page.
410 DoTranslatePage(tab, translate_script_,
411 request.source_lang, request.target_lang);
412 }
413 }
414 pending_requests_.clear();
415 } else { // if (translate_script_request)
416 if (!error)
417 SetSupportedLanguages(data);
418 else
419 VLOG(1) << "Failed to Fetch languages from: " << kLanguageListFetchURL;
309 } 420 }
310
311 // Process any pending requests.
312 std::vector<PendingRequest>::const_iterator iter;
313 for (iter = pending_requests_.begin(); iter != pending_requests_.end();
314 ++iter) {
315 const PendingRequest& request = *iter;
316 TabContents* tab = tab_util::GetTabContentsByID(request.render_process_id,
317 request.render_view_id);
318 if (!tab) {
319 // The tab went away while we were retrieving the script.
320 continue;
321 }
322 NavigationEntry* entry = tab->controller().GetActiveEntry();
323 if (!entry || entry->page_id() != request.page_id) {
324 // We navigated away from the page the translation was triggered on.
325 continue;
326 }
327
328 if (error) {
329 ShowInfoBar(tab, TranslateInfoBarDelegate::CreateErrorDelegate(
330 TranslateErrors::NETWORK, tab,
331 request.source_lang, request.target_lang));
332 } else {
333 // Translate the page.
334 DoTranslatePage(tab, translate_script_,
335 request.source_lang, request.target_lang);
336 }
337 }
338 pending_requests_.clear();
339 } 421 }
340 422
341 // static 423 // static
342 bool TranslateManager::IsShowingTranslateInfobar(TabContents* tab) { 424 bool TranslateManager::IsShowingTranslateInfobar(TabContents* tab) {
343 return GetTranslateInfoBarDelegate(tab) != NULL; 425 return GetTranslateInfoBarDelegate(tab) != NULL;
344 } 426 }
345 427
346 TranslateManager::TranslateManager() 428 TranslateManager::TranslateManager()
347 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), 429 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
348 translate_script_expiration_delay_(kTranslateScriptExpirationDelayMS), 430 translate_script_expiration_delay_(kTranslateScriptExpirationDelayMS),
349 translate_script_request_pending_(false) { 431 translate_script_request_pending_(false),
432 language_list_request_pending_(false) {
350 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, 433 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
351 NotificationService::AllSources()); 434 NotificationService::AllSources());
352 notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, 435 notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
353 NotificationService::AllSources()); 436 NotificationService::AllSources());
354 notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, 437 notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED,
355 NotificationService::AllSources()); 438 NotificationService::AllSources());
356 } 439 }
357 440
358 void TranslateManager::InitiateTranslation(TabContents* tab, 441 void TranslateManager::InitiateTranslation(TabContents* tab,
359 const std::string& page_lang) { 442 const std::string& page_lang) {
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 // black-listed. 695 // black-listed.
613 // TODO(jungshik): Once we determine that it's safe to remove English from 696 // TODO(jungshik): Once we determine that it's safe to remove English from
614 // the default Accept-Language values for most locales, remove this 697 // the default Accept-Language values for most locales, remove this
615 // special-casing. 698 // special-casing.
616 if (accept_lang != "en" || is_ui_english) 699 if (accept_lang != "en" || is_ui_english)
617 accept_langs_set.insert(accept_lang); 700 accept_langs_set.insert(accept_lang);
618 } 701 }
619 accept_languages_[prefs] = accept_langs_set; 702 accept_languages_[prefs] = accept_langs_set;
620 } 703 }
621 704
705 void TranslateManager::FetchLanguageListFromTranslateServer(
706 PrefService* prefs) {
707 if (language_list_request_pending_)
708 return;
709
710 // We don't want to do this when translate is disabled.
711 DCHECK(prefs != NULL);
712 if (CommandLine::ForCurrentProcess()->HasSwitch(
713 switches::kDisableTranslate) ||
714 (prefs != NULL && !prefs->GetBoolean(prefs::kEnableTranslate))) {
715 return;
716 }
717
718 language_list_request_pending_ = true;
719 URLFetcher* fetcher = URLFetcher::Create(1, GURL(kLanguageListFetchURL),
720 URLFetcher::GET, this);
721 fetcher->set_request_context(Profile::GetDefaultRequestContext());
722 fetcher->set_max_retries(kMaxRetryLanguageListFetch);
723 fetcher->Start();
724 }
725
622 void TranslateManager::RequestTranslateScript() { 726 void TranslateManager::RequestTranslateScript() {
623 if (translate_script_request_pending_) 727 if (translate_script_request_pending_)
624 return; 728 return;
625 729
626 translate_script_request_pending_ = true; 730 translate_script_request_pending_ = true;
627 URLFetcher* fetcher = URLFetcher::Create(0, GURL(kTranslateScriptURL), 731 URLFetcher* fetcher = URLFetcher::Create(0, GURL(kTranslateScriptURL),
628 URLFetcher::GET, this); 732 URLFetcher::GET, this);
629 fetcher->set_request_context(Profile::GetDefaultRequestContext()); 733 fetcher->set_request_context(Profile::GetDefaultRequestContext());
630 fetcher->set_extra_request_headers(kTranslateScriptHeader); 734 fetcher->set_extra_request_headers(kTranslateScriptHeader);
631 fetcher->Start(); 735 fetcher->Start();
(...skipping 26 matching lines...) Expand all
658 TabContentsWrapper* wrapper = 762 TabContentsWrapper* wrapper =
659 TabContentsWrapper::GetCurrentWrapperForContents(tab); 763 TabContentsWrapper::GetCurrentWrapperForContents(tab);
660 for (size_t i = 0; i < wrapper->infobar_count(); ++i) { 764 for (size_t i = 0; i < wrapper->infobar_count(); ++i) {
661 TranslateInfoBarDelegate* delegate = 765 TranslateInfoBarDelegate* delegate =
662 wrapper->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate(); 766 wrapper->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate();
663 if (delegate) 767 if (delegate)
664 return delegate; 768 return delegate;
665 } 769 }
666 return NULL; 770 return NULL;
667 } 771 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698