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

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
« no previous file with comments | « chrome/browser/translate/translate_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL.
132 const char* const kLaguangeListCallbackName = "sl(";
Jay Civelli 2011/06/16 07:11:13 Typo: kLaguange
MAD 2011/06/16 14:22:17 Done.
133 const size_t kLaguangeListCallbackNameLength =
134 strlen(kLaguangeListCallbackName);
135 const char* const kTargetLanguagesKey = "tl";
136 const int kMaxRetryLanguageListFetch = 5;
128 const int kTranslateScriptExpirationDelayMS = 24 * 60 * 60 * 1000; // 1 day. 137 const int kTranslateScriptExpirationDelayMS = 24 * 60 * 60 * 1000; // 1 day.
129 138
130 } // namespace 139 } // namespace
131 140
132 // static 141 // static
133 base::LazyInstance<std::set<std::string> > 142 base::LazyInstance<std::set<std::string> >
134 TranslateManager::supported_languages_(base::LINKER_INITIALIZED); 143 TranslateManager::supported_languages_(base::LINKER_INITIALIZED);
135 144
136 TranslateManager::~TranslateManager() { 145 TranslateManager::~TranslateManager() {
137 } 146 }
138 147
139 // static 148 // static
140 TranslateManager* TranslateManager::GetInstance() { 149 TranslateManager* TranslateManager::GetInstance() {
141 return Singleton<TranslateManager>::get(); 150 return Singleton<TranslateManager>::get();
142 } 151 }
143 152
144 // static 153 // static
145 bool TranslateManager::IsTranslatableURL(const GURL& url) { 154 bool TranslateManager::IsTranslatableURL(const GURL& url) {
146 // A URLs is translatable unless it is one of the following: 155 // A URLs is translatable unless it is one of the following:
147 // - an internal URL (chrome:// and others) 156 // - an internal URL (chrome:// and others)
148 // - the devtools (which is considered UI) 157 // - the devtools (which is considered UI)
149 // - an FTP page (as FTP pages tend to have long lists of filenames that may 158 // - an FTP page (as FTP pages tend to have long lists of filenames that may
150 // confuse the CLD) 159 // confuse the CLD)
151 return !url.SchemeIs(chrome::kChromeUIScheme) && 160 return !url.SchemeIs(chrome::kChromeUIScheme) &&
152 !url.SchemeIs(chrome::kChromeDevToolsScheme) && 161 !url.SchemeIs(chrome::kChromeDevToolsScheme) &&
153 !url.SchemeIs(chrome::kFtpScheme); 162 !url.SchemeIs(chrome::kFtpScheme);
154 } 163 }
155 164
156 // static 165 // static
166 void TranslateManager::SetSupportedLanguages(const std::string& language_list) {
167 // The format is:
168 // sl({'sl': {'XX': 'LanguageName', ...}, 'tl': {'XX': 'LanguageName', ...}})
169 // Where "sl(" is set in kLaguangeListCallbackName
170 // and 'tl' is kTargetLanguagesKey
171 if (!StartsWithASCII(language_list, kLaguangeListCallbackName, false) ||
172 !EndsWith(language_list, ")", false)) {
173 // We don't DCHECK here since this can happen in ui_tests, even though the
174 // the BrowserMain function won't call us with parameters.ui_task is NULL
175 // some tests don't set it, so we must bail here.
176 return;
177 }
178 std::string languages_json = language_list.substr(
179 kLaguangeListCallbackNameLength,
180 language_list.size() - kLaguangeListCallbackNameLength - 1);
181 // JSON doesn't support single quotes though this is what is used on the
182 // translate server so we must replace them with double quotes.
183 ReplaceSubstringsAfterOffset(&languages_json, 0, "'", "\"");
184 scoped_ptr<Value> json_value(base::JSONReader::Read(languages_json, true));
185 DCHECK(json_value != NULL && json_value->IsType(Value::TYPE_DICTIONARY));
186 if (json_value == NULL || !json_value->IsType(Value::TYPE_DICTIONARY))
Jay Civelli 2011/06/16 07:11:13 May be instead of repeating the condition in the D
MAD 2011/06/16 14:22:17 Done.
187 return;
188 // The first level dictionary contains two sub-dict, one for source languages
189 // and the other for target languages, we want to use the target languages.
190 DictionaryValue* language_dict =
191 static_cast<DictionaryValue*>(json_value.get());
192 DCHECK(language_dict->HasKey(kTargetLanguagesKey));
Jay Civelli 2011/06/16 07:11:13 Couldn't you replace these lines up 203 with a cal
MAD 2011/06/16 14:22:17 Done. Thanks, I forgot about this shortcut...
193 Value* target_languages_value = NULL;
194 if (!language_dict->Get(kTargetLanguagesKey, &target_languages_value))
195 return;
196 DCHECK(target_languages_value != NULL &&
197 target_languages_value->IsType(Value::TYPE_DICTIONARY));
198 if (target_languages_value == NULL ||
199 !target_languages_value->IsType(Value::TYPE_DICTIONARY)) {
200 return;
201 }
202 DictionaryValue* target_languages =
203 static_cast<DictionaryValue*>(target_languages_value);
204 // Now we can clear our current state...
205 std::set<std::string>* supported_languages = supported_languages_.Pointer();
206 supported_languages->clear();
207 // ... and replace it with the values we just fetched from the server.
208 DictionaryValue::key_iterator iter = target_languages->begin_keys();
209 for (; iter != target_languages->end_keys(); ++iter)
210 supported_languages_.Pointer()->insert(*iter);
211 }
212
213 // static
214 void TranslateManager::InitSupportedLanguages() {
215 // If our list of supported languages have not been set yet, we default
216 // to our hard coded list of languages in kSupportedLanguages.
217 if (supported_languages_.Pointer()->empty()) {
218 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i)
219 supported_languages_.Pointer()->insert(kSupportedLanguages[i]);
220 }
221 }
222
223 // static
157 void TranslateManager::GetSupportedLanguages( 224 void TranslateManager::GetSupportedLanguages(
158 std::vector<std::string>* languages) { 225 std::vector<std::string>* languages) {
159 DCHECK(languages && languages->empty()); 226 DCHECK(languages && languages->empty());
160 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i) 227 InitSupportedLanguages();
161 languages->push_back(kSupportedLanguages[i]); 228 std::set<std::string>* supported_languages = supported_languages_.Pointer();
229 std::set<std::string>::const_iterator iter = supported_languages->begin();
230 for (; iter != supported_languages->end(); ++iter)
231 languages->push_back(*iter);
162 } 232 }
163 233
164 // static 234 // static
165 std::string TranslateManager::GetLanguageCode( 235 std::string TranslateManager::GetLanguageCode(
166 const std::string& chrome_locale) { 236 const std::string& chrome_locale) {
167 // Only remove the country code for country specific languages we don't 237 // Only remove the country code for country specific languages we don't
168 // support specifically yet. 238 // support specifically yet.
169 if (IsSupportedLanguage(chrome_locale)) 239 if (IsSupportedLanguage(chrome_locale))
170 return chrome_locale; 240 return chrome_locale;
171 241
172 size_t hypen_index = chrome_locale.find('-'); 242 size_t hypen_index = chrome_locale.find('-');
173 if (hypen_index == std::string::npos) 243 if (hypen_index == std::string::npos)
174 return chrome_locale; 244 return chrome_locale;
175 return chrome_locale.substr(0, hypen_index); 245 return chrome_locale.substr(0, hypen_index);
176 } 246 }
177 247
178 // static 248 // static
179 bool TranslateManager::IsSupportedLanguage(const std::string& page_language) { 249 bool TranslateManager::IsSupportedLanguage(const std::string& page_language) {
180 std::set<std::string>* supported_languages = supported_languages_.Pointer(); 250 InitSupportedLanguages();
181 if (supported_languages->empty()) { 251 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 } 252 }
187 253
188 void TranslateManager::Observe(NotificationType type, 254 void TranslateManager::Observe(NotificationType type,
189 const NotificationSource& source, 255 const NotificationSource& source,
190 const NotificationDetails& details) { 256 const NotificationDetails& details) {
191 switch (type.value) { 257 switch (type.value) {
192 case NotificationType::NAV_ENTRY_COMMITTED: { 258 case NotificationType::NAV_ENTRY_COMMITTED: {
193 NavigationController* controller = 259 NavigationController* controller =
194 Source<NavigationController>(source).ptr(); 260 Source<NavigationController>(source).ptr();
195 content::LoadCommittedDetails* load_details = 261 content::LoadCommittedDetails* load_details =
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 } 347 }
282 } 348 }
283 349
284 void TranslateManager::OnURLFetchComplete(const URLFetcher* source, 350 void TranslateManager::OnURLFetchComplete(const URLFetcher* source,
285 const GURL& url, 351 const GURL& url,
286 const net::URLRequestStatus& status, 352 const net::URLRequestStatus& status,
287 int response_code, 353 int response_code,
288 const net::ResponseCookies& cookies, 354 const net::ResponseCookies& cookies,
289 const std::string& data) { 355 const std::string& data) {
290 scoped_ptr<const URLFetcher> delete_ptr(source); 356 scoped_ptr<const URLFetcher> delete_ptr(source);
291 DCHECK(translate_script_request_pending_); 357 DCHECK(translate_script_request_pending_ || language_list_request_pending_);
292 translate_script_request_pending_ = false; 358 // We quickly recognize that we are handling a translate script request
359 // if we don't have a language_list_request_pending_. Otherwise we do the
360 // more expensive check of confirming we got the kTranslateScriptURL in the
361 // rare case where we would have both requests pending at the same time.
362 bool translate_script_request = !language_list_request_pending_ ||
363 url == GURL(kTranslateScriptURL);
364 // Here we make sure that if we didn't get the translate_script_request,
365 // we actually got a language_list_request.
366 DCHECK(translate_script_request || url == GURL(kLanguageListFetchURL));
367 if (translate_script_request)
368 translate_script_request_pending_ = false;
369 else
370 language_list_request_pending_ = false;
371
293 bool error = 372 bool error =
294 (status.status() != net::URLRequestStatus::SUCCESS || 373 (status.status() != net::URLRequestStatus::SUCCESS ||
295 response_code != 200); 374 response_code != 200);
296 375
297 if (!error) { 376 if (translate_script_request) {
298 base::StringPiece str = ResourceBundle::GetSharedInstance(). 377 if (!error) {
299 GetRawDataResource(IDR_TRANSLATE_JS); 378 base::StringPiece str = ResourceBundle::GetSharedInstance().
300 DCHECK(translate_script_.empty()); 379 GetRawDataResource(IDR_TRANSLATE_JS);
301 str.CopyToString(&translate_script_); 380 DCHECK(translate_script_.empty());
302 translate_script_ += "\n" + data; 381 str.CopyToString(&translate_script_);
303 // We'll expire the cached script after some time, to make sure long running 382 translate_script_ += "\n" + data;
304 // browsers still get fixes that might get pushed with newer scripts. 383 // We'll expire the cached script after some time, to make sure long
305 MessageLoop::current()->PostDelayedTask(FROM_HERE, 384 // running browsers still get fixes that might get pushed with newer
306 method_factory_.NewRunnableMethod( 385 // scripts.
307 &TranslateManager::ClearTranslateScript), 386 MessageLoop::current()->PostDelayedTask(FROM_HERE,
308 translate_script_expiration_delay_); 387 method_factory_.NewRunnableMethod(
388 &TranslateManager::ClearTranslateScript),
389 translate_script_expiration_delay_);
390 }
391 // Process any pending requests.
392 std::vector<PendingRequest>::const_iterator iter;
393 for (iter = pending_requests_.begin(); iter != pending_requests_.end();
394 ++iter) {
395 const PendingRequest& request = *iter;
396 TabContents* tab = tab_util::GetTabContentsByID(request.render_process_id,
397 request.render_view_id);
398 if (!tab) {
399 // The tab went away while we were retrieving the script.
400 continue;
401 }
402 NavigationEntry* entry = tab->controller().GetActiveEntry();
403 if (!entry || entry->page_id() != request.page_id) {
404 // We navigated away from the page the translation was triggered on.
405 continue;
406 }
407
408 if (error) {
409 ShowInfoBar(tab, TranslateInfoBarDelegate::CreateErrorDelegate(
410 TranslateErrors::NETWORK, tab,
411 request.source_lang, request.target_lang));
412 } else {
413 // Translate the page.
414 DoTranslatePage(tab, translate_script_,
415 request.source_lang, request.target_lang);
416 }
417 }
418 pending_requests_.clear();
419 } else { // if (translate_script_request)
420 if (!error)
421 SetSupportedLanguages(data);
422 else
423 VLOG(1) << "Failed to Fetch languages from: " << kLanguageListFetchURL;
309 } 424 }
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 } 425 }
340 426
341 // static 427 // static
342 bool TranslateManager::IsShowingTranslateInfobar(TabContents* tab) { 428 bool TranslateManager::IsShowingTranslateInfobar(TabContents* tab) {
343 return GetTranslateInfoBarDelegate(tab) != NULL; 429 return GetTranslateInfoBarDelegate(tab) != NULL;
344 } 430 }
345 431
346 TranslateManager::TranslateManager() 432 TranslateManager::TranslateManager()
347 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), 433 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
348 translate_script_expiration_delay_(kTranslateScriptExpirationDelayMS), 434 translate_script_expiration_delay_(kTranslateScriptExpirationDelayMS),
349 translate_script_request_pending_(false) { 435 translate_script_request_pending_(false),
436 language_list_request_pending_(false) {
350 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, 437 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
351 NotificationService::AllSources()); 438 NotificationService::AllSources());
352 notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, 439 notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
353 NotificationService::AllSources()); 440 NotificationService::AllSources());
354 notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, 441 notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED,
355 NotificationService::AllSources()); 442 NotificationService::AllSources());
356 } 443 }
357 444
358 void TranslateManager::InitiateTranslation(TabContents* tab, 445 void TranslateManager::InitiateTranslation(TabContents* tab,
359 const std::string& page_lang) { 446 const std::string& page_lang) {
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 // black-listed. 699 // black-listed.
613 // TODO(jungshik): Once we determine that it's safe to remove English from 700 // TODO(jungshik): Once we determine that it's safe to remove English from
614 // the default Accept-Language values for most locales, remove this 701 // the default Accept-Language values for most locales, remove this
615 // special-casing. 702 // special-casing.
616 if (accept_lang != "en" || is_ui_english) 703 if (accept_lang != "en" || is_ui_english)
617 accept_langs_set.insert(accept_lang); 704 accept_langs_set.insert(accept_lang);
618 } 705 }
619 accept_languages_[prefs] = accept_langs_set; 706 accept_languages_[prefs] = accept_langs_set;
620 } 707 }
621 708
709 void TranslateManager::FetchLanguageListFromTranslateServer(
710 PrefService* prefs) {
711 if (language_list_request_pending_)
712 return;
713
714 // We don't want to do this when translate is disabled.
715 DCHECK(prefs != NULL);
716 if (CommandLine::ForCurrentProcess()->HasSwitch(
717 switches::kDisableTranslate) ||
718 (prefs != NULL && !prefs->GetBoolean(prefs::kEnableTranslate))) {
719 return;
720 }
721
722 language_list_request_pending_ = true;
723 URLFetcher* fetcher = URLFetcher::Create(0, GURL(kLanguageListFetchURL),
724 URLFetcher::GET, this);
725 fetcher->set_request_context(Profile::GetDefaultRequestContext());
726 fetcher->set_max_retries(kMaxRetryLanguageListFetch);
727 fetcher->Start();
728 }
729
622 void TranslateManager::RequestTranslateScript() { 730 void TranslateManager::RequestTranslateScript() {
623 if (translate_script_request_pending_) 731 if (translate_script_request_pending_)
624 return; 732 return;
625 733
626 translate_script_request_pending_ = true; 734 translate_script_request_pending_ = true;
627 URLFetcher* fetcher = URLFetcher::Create(0, GURL(kTranslateScriptURL), 735 URLFetcher* fetcher = URLFetcher::Create(0, GURL(kTranslateScriptURL),
628 URLFetcher::GET, this); 736 URLFetcher::GET, this);
629 fetcher->set_request_context(Profile::GetDefaultRequestContext()); 737 fetcher->set_request_context(Profile::GetDefaultRequestContext());
630 fetcher->set_extra_request_headers(kTranslateScriptHeader); 738 fetcher->set_extra_request_headers(kTranslateScriptHeader);
631 fetcher->Start(); 739 fetcher->Start();
(...skipping 26 matching lines...) Expand all
658 TabContentsWrapper* wrapper = 766 TabContentsWrapper* wrapper =
659 TabContentsWrapper::GetCurrentWrapperForContents(tab); 767 TabContentsWrapper::GetCurrentWrapperForContents(tab);
660 for (size_t i = 0; i < wrapper->infobar_count(); ++i) { 768 for (size_t i = 0; i < wrapper->infobar_count(); ++i) {
661 TranslateInfoBarDelegate* delegate = 769 TranslateInfoBarDelegate* delegate =
662 wrapper->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate(); 770 wrapper->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate();
663 if (delegate) 771 if (delegate)
664 return delegate; 772 return delegate;
665 } 773 }
666 return NULL; 774 return NULL;
667 } 775 }
OLDNEW
« no previous file with comments | « chrome/browser/translate/translate_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698