| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/translate/translate_manager.h" |
| |
| #include "base/command_line.h" |
| #include "base/compiler_specific.h" |
| #include "base/memory/singleton.h" |
| #include "base/metrics/histogram.h" |
| #include "base/string_split.h" |
| #include "base/string_util.h" |
| #include "chrome/browser/autofill/autofill_manager.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/tab_contents/language_state.h" |
| #include "chrome/browser/tab_contents/tab_util.h" |
| #include "chrome/browser/tabs/tab_strip_model.h" |
| #include "chrome/browser/translate/page_translated_details.h" |
| #include "chrome/browser/translate/translate_infobar_delegate.h" |
| #include "chrome/browser/translate/translate_tab_helper.h" |
| #include "chrome/browser/translate/translate_prefs.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/render_messages.h" |
| #include "chrome/common/translate_errors.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/browser/renderer_host/render_process_host.h" |
| #include "content/browser/renderer_host/render_view_host.h" |
| #include "content/browser/tab_contents/navigation_controller.h" |
| #include "content/browser/tab_contents/navigation_entry.h" |
| #include "content/browser/tab_contents/tab_contents.h" |
| #include "content/common/notification_details.h" |
| #include "content/common/notification_service.h" |
| #include "content/common/notification_source.h" |
| #include "content/common/notification_type.h" |
| #include "grit/browser_resources.h" |
| #include "net/base/escape.h" |
| #include "net/url_request/url_request_status.h" |
| #include "ui/base/resource/resource_bundle.h" |
| |
| namespace { |
| |
| // Mapping from a locale name to a language code name. |
| // Locale names not included are translated as is. |
| struct LocaleToCLDLanguage { |
| const char* locale_language; // Language Chrome locale is in. |
| const char* cld_language; // Language the CLD reports. |
| }; |
| LocaleToCLDLanguage kLocaleToCLDLanguages[] = { |
| { "en-GB", "en" }, |
| { "en-US", "en" }, |
| { "es-419", "es" }, |
| { "pt-BR", "pt" }, |
| { "pt-PT", "pt" }, |
| }; |
| |
| // The list of languages the Google translation server supports. |
| // For information, here is the list of languages that Chrome can be run in |
| // but that the translation server does not support: |
| // am Amharic |
| // bn Bengali |
| // gu Gujarati |
| // kn Kannada |
| // ml Malayalam |
| // mr Marathi |
| // ta Tamil |
| // te Telugu |
| const char* kSupportedLanguages[] = { |
| "af", // Afrikaans |
| "az", // Azerbaijani |
| "sq", // Albanian |
| "ar", // Arabic |
| "hy", // Armenian |
| "eu", // Basque |
| "be", // Belarusian |
| "bg", // Bulgarian |
| "ca", // Catalan |
| "zh-CN", // Chinese (Simplified) |
| "zh-TW", // Chinese (Traditional) |
| "hr", // Croatian |
| "cs", // Czech |
| "da", // Danish |
| "nl", // Dutch |
| "en", // English |
| "et", // Estonian |
| "fi", // Finnish |
| "fil", // Filipino |
| "fr", // French |
| "gl", // Galician |
| "de", // German |
| "el", // Greek |
| "ht", // Haitian Creole |
| "he", // Hebrew |
| "hi", // Hindi |
| "hu", // Hungarian |
| "is", // Icelandic |
| "id", // Indonesian |
| "it", // Italian |
| "ga", // Irish |
| "ja", // Japanese |
| "ka", // Georgian |
| "ko", // Korean |
| "lv", // Latvian |
| "lt", // Lithuanian |
| "mk", // Macedonian |
| "ms", // Malay |
| "mt", // Maltese |
| "nb", // Norwegian |
| "fa", // Persian |
| "pl", // Polish |
| "pt", // Portuguese |
| "ro", // Romanian |
| "ru", // Russian |
| "sr", // Serbian |
| "sk", // Slovak |
| "sl", // Slovenian |
| "es", // Spanish |
| "sw", // Swahili |
| "sv", // Swedish |
| "th", // Thai |
| "tr", // Turkish |
| "uk", // Ukrainian |
| "ur", // Urdu |
| "vi", // Vietnamese |
| "cy", // Welsh |
| "yi", // Yiddish |
| }; |
| |
| const char* const kTranslateScriptURL = |
| "http://translate.google.com/translate_a/element.js?" |
| "cb=cr.googleTranslate.onTranslateElementLoad"; |
| const char* const kTranslateScriptHeader = |
| "Google-Translate-Element-Mode: library"; |
| const char* const kReportLanguageDetectionErrorURL = |
| "http://translate.google.com/translate_error"; |
| |
| const int kTranslateScriptExpirationDelayMS = 24 * 60 * 60 * 1000; // 1 day. |
| |
| } // namespace |
| |
| // static |
| base::LazyInstance<std::set<std::string> > |
| TranslateManager::supported_languages_(base::LINKER_INITIALIZED); |
| |
| TranslateManager::~TranslateManager() { |
| } |
| |
| // static |
| TranslateManager* TranslateManager::GetInstance() { |
| return Singleton<TranslateManager>::get(); |
| } |
| |
| // static |
| bool TranslateManager::IsTranslatableURL(const GURL& url) { |
| // A URLs is translatable unless it is one of the following: |
| // - an internal URL (chrome:// and others) |
| // - the devtools (which is considered UI) |
| // - an FTP page (as FTP pages tend to have long lists of filenames that may |
| // confuse the CLD) |
| return !url.SchemeIs(chrome::kChromeUIScheme) && |
| !url.SchemeIs(chrome::kChromeDevToolsScheme) && |
| !url.SchemeIs(chrome::kFtpScheme); |
| } |
| |
| // static |
| void TranslateManager::GetSupportedLanguages( |
| std::vector<std::string>* languages) { |
| DCHECK(languages && languages->empty()); |
| for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i) |
| languages->push_back(kSupportedLanguages[i]); |
| } |
| |
| // static |
| std::string TranslateManager::GetLanguageCode( |
| const std::string& chrome_locale) { |
| for (size_t i = 0; i < arraysize(kLocaleToCLDLanguages); ++i) { |
| if (chrome_locale == kLocaleToCLDLanguages[i].locale_language) |
| return kLocaleToCLDLanguages[i].cld_language; |
| } |
| return chrome_locale; |
| } |
| |
| // static |
| bool TranslateManager::IsSupportedLanguage(const std::string& page_language) { |
| if (supported_languages_.Pointer()->empty()) { |
| for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i) |
| supported_languages_.Pointer()->insert(kSupportedLanguages[i]); |
| } |
| return supported_languages_.Pointer()->find(page_language) != |
| supported_languages_.Pointer()->end(); |
| } |
| |
| void TranslateManager::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type.value) { |
| case NotificationType::NAV_ENTRY_COMMITTED: { |
| NavigationController* controller = |
| Source<NavigationController>(source).ptr(); |
| NavigationController::LoadCommittedDetails* load_details = |
| Details<NavigationController::LoadCommittedDetails>(details).ptr(); |
| NavigationEntry* entry = controller->GetActiveEntry(); |
| if (!entry) { |
| NOTREACHED(); |
| return; |
| } |
| |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents( |
| controller->tab_contents()); |
| if (!wrapper || !wrapper->translate_tab_helper()) |
| return; |
| |
| TranslateTabHelper* helper = wrapper->translate_tab_helper(); |
| if (!load_details->is_main_frame && |
| helper->language_state().translation_declined()) { |
| // Some sites (such as Google map) may trigger sub-frame navigations |
| // when the user interacts with the page. We don't want to show a new |
| // infobar if the user already dismissed one in that case. |
| return; |
| } |
| if (entry->transition_type() != PageTransition::RELOAD && |
| load_details->type != NavigationType::SAME_PAGE) { |
| return; |
| } |
| // When doing a page reload, we don't get a TAB_LANGUAGE_DETERMINED |
| // notification. So we need to explictly initiate the translation. |
| // Note that we delay it as the TranslateManager gets this notification |
| // before the TabContents and the TabContents processing might remove the |
| // current infobars. Since InitTranslation might add an infobar, it must |
| // be done after that. |
| MessageLoop::current()->PostTask(FROM_HERE, |
| method_factory_.NewRunnableMethod( |
| &TranslateManager::InitiateTranslationPosted, |
| controller->tab_contents()->render_view_host()->process()->id(), |
| controller->tab_contents()->render_view_host()->routing_id(), |
| helper->language_state().original_language())); |
| break; |
| } |
| case NotificationType::TAB_LANGUAGE_DETERMINED: { |
| TabContents* tab = Source<TabContents>(source).ptr(); |
| // We may get this notifications multiple times. Make sure to translate |
| // only once. |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(tab); |
| LanguageState& language_state = |
| wrapper->translate_tab_helper()->language_state(); |
| if (language_state.page_translatable() && |
| !language_state.translation_pending() && |
| !language_state.translation_declined() && |
| !language_state.IsPageTranslated()) { |
| std::string language = *(Details<std::string>(details).ptr()); |
| InitiateTranslation(tab, language); |
| } |
| break; |
| } |
| case NotificationType::PAGE_TRANSLATED: { |
| // Only add translate infobar if it doesn't exist; if it already exists, |
| // just update the state, the actual infobar would have received the same |
| // notification and update the visual display accordingly. |
| TabContents* tab = Source<TabContents>(source).ptr(); |
| PageTranslatedDetails* page_translated_details = |
| Details<PageTranslatedDetails>(details).ptr(); |
| PageTranslated(tab, page_translated_details); |
| break; |
| } |
| case NotificationType::PROFILE_DESTROYED: { |
| Profile* profile = Source<Profile>(source).ptr(); |
| notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, |
| source); |
| size_t count = accept_languages_.erase(profile->GetPrefs()); |
| // We should know about this profile since we are listening for |
| // notifications on it. |
| DCHECK(count > 0); |
| pref_change_registrar_.Remove(prefs::kAcceptLanguages, this); |
| break; |
| } |
| case NotificationType::PREF_CHANGED: { |
| DCHECK(*Details<std::string>(details).ptr() == prefs::kAcceptLanguages); |
| PrefService* prefs = Source<PrefService>(source).ptr(); |
| InitAcceptLanguages(prefs); |
| break; |
| } |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void TranslateManager::OnURLFetchComplete(const URLFetcher* source, |
| const GURL& url, |
| const net::URLRequestStatus& status, |
| int response_code, |
| const ResponseCookies& cookies, |
| const std::string& data) { |
| scoped_ptr<const URLFetcher> delete_ptr(source); |
| DCHECK(translate_script_request_pending_); |
| translate_script_request_pending_ = false; |
| bool error = |
| (status.status() != net::URLRequestStatus::SUCCESS || |
| response_code != 200); |
| |
| if (!error) { |
| base::StringPiece str = ResourceBundle::GetSharedInstance(). |
| GetRawDataResource(IDR_TRANSLATE_JS); |
| DCHECK(translate_script_.empty()); |
| str.CopyToString(&translate_script_); |
| translate_script_ += "\n" + data; |
| // We'll expire the cached script after some time, to make sure long running |
| // browsers still get fixes that might get pushed with newer scripts. |
| MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| method_factory_.NewRunnableMethod( |
| &TranslateManager::ClearTranslateScript), |
| translate_script_expiration_delay_); |
| } |
| |
| // Process any pending requests. |
| std::vector<PendingRequest>::const_iterator iter; |
| for (iter = pending_requests_.begin(); iter != pending_requests_.end(); |
| ++iter) { |
| const PendingRequest& request = *iter; |
| TabContents* tab = tab_util::GetTabContentsByID(request.render_process_id, |
| request.render_view_id); |
| if (!tab) { |
| // The tab went away while we were retrieving the script. |
| continue; |
| } |
| NavigationEntry* entry = tab->controller().GetActiveEntry(); |
| if (!entry || entry->page_id() != request.page_id) { |
| // We navigated away from the page the translation was triggered on. |
| continue; |
| } |
| |
| if (error) { |
| ShowInfoBar(tab, TranslateInfoBarDelegate::CreateErrorDelegate( |
| TranslateErrors::NETWORK, tab, |
| request.source_lang, request.target_lang)); |
| } else { |
| // Translate the page. |
| DoTranslatePage(tab, translate_script_, |
| request.source_lang, request.target_lang); |
| } |
| } |
| pending_requests_.clear(); |
| } |
| |
| // static |
| bool TranslateManager::IsShowingTranslateInfobar(TabContents* tab) { |
| return GetTranslateInfoBarDelegate(tab) != NULL; |
| } |
| |
| TranslateManager::TranslateManager() |
| : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), |
| translate_script_expiration_delay_(kTranslateScriptExpirationDelayMS), |
| translate_script_request_pending_(false) { |
| notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, |
| NotificationService::AllSources()); |
| notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, |
| NotificationService::AllSources()); |
| notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, |
| NotificationService::AllSources()); |
| } |
| |
| void TranslateManager::InitiateTranslation(TabContents* tab, |
| const std::string& page_lang) { |
| PrefService* prefs = tab->profile()->GetOriginalProfile()->GetPrefs(); |
| if (!prefs->GetBoolean(prefs::kEnableTranslate)) |
| return; |
| |
| pref_change_registrar_.Init(prefs); |
| |
| // Allow disabling of translate from the command line to assist with |
| // automated browser testing. |
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableTranslate)) |
| return; |
| |
| NavigationEntry* entry = tab->controller().GetActiveEntry(); |
| if (!entry) { |
| // This can happen for popups created with window.open(""). |
| return; |
| } |
| |
| // If there is already a translate infobar showing, don't show another one. |
| if (GetTranslateInfoBarDelegate(tab)) |
| return; |
| |
| std::string target_lang = GetTargetLanguage(); |
| // Nothing to do if either the language Chrome is in or the language of the |
| // page is not supported by the translation server. |
| if (target_lang.empty() || !IsSupportedLanguage(page_lang)) { |
| return; |
| } |
| |
| // We don't want to translate: |
| // - any Chrome specific page (New Tab Page, Download, History... pages). |
| // - similar languages (ex: en-US to en). |
| // - any user black-listed URLs or user selected language combination. |
| // - any language the user configured as accepted languages. |
| if (!IsTranslatableURL(entry->url()) || page_lang == target_lang || |
| !TranslatePrefs::CanTranslate(prefs, page_lang, entry->url()) || |
| IsAcceptLanguage(tab, page_lang)) { |
| return; |
| } |
| |
| // If the user has previously selected "always translate" for this language we |
| // automatically translate. Note that in incognito mode we disable that |
| // feature; the user will get an infobar, so they can control whether the |
| // page's text is sent to the translate server. |
| std::string auto_target_lang; |
| if (!tab->profile()->IsOffTheRecord() && |
| TranslatePrefs::ShouldAutoTranslate(prefs, page_lang, |
| &auto_target_lang)) { |
| TranslatePage(tab, page_lang, auto_target_lang); |
| return; |
| } |
| |
| TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab)->translate_tab_helper(); |
| std::string auto_translate_to = helper->language_state().AutoTranslateTo(); |
| if (!auto_translate_to.empty()) { |
| // This page was navigated through a click from a translated page. |
| TranslatePage(tab, page_lang, auto_translate_to); |
| return; |
| } |
| |
| // Prompts the user if he/she wants the page translated. |
| tab->AddInfoBar(TranslateInfoBarDelegate::CreateDelegate( |
| TranslateInfoBarDelegate::BEFORE_TRANSLATE, tab, page_lang, target_lang)); |
| } |
| |
| void TranslateManager::InitiateTranslationPosted( |
| int process_id, int render_id, const std::string& page_lang) { |
| // The tab might have been closed. |
| TabContents* tab = tab_util::GetTabContentsByID(process_id, render_id); |
| if (!tab) |
| return; |
| |
| TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab)->translate_tab_helper(); |
| if (helper->language_state().translation_pending()) |
| return; |
| |
| InitiateTranslation(tab, page_lang); |
| } |
| |
| void TranslateManager::TranslatePage(TabContents* tab_contents, |
| const std::string& source_lang, |
| const std::string& target_lang) { |
| NavigationEntry* entry = tab_contents->controller().GetActiveEntry(); |
| if (!entry) { |
| NOTREACHED(); |
| return; |
| } |
| |
| TranslateInfoBarDelegate* infobar = TranslateInfoBarDelegate::CreateDelegate( |
| TranslateInfoBarDelegate::TRANSLATING, tab_contents, |
| source_lang, target_lang); |
| if (!infobar) { |
| // This means the source or target languages are not supported, which should |
| // not happen as we won't show a translate infobar or have the translate |
| // context menu activated in such cases. |
| NOTREACHED(); |
| return; |
| } |
| ShowInfoBar(tab_contents, infobar); |
| |
| if (!translate_script_.empty()) { |
| DoTranslatePage(tab_contents, translate_script_, source_lang, target_lang); |
| return; |
| } |
| |
| // The script is not available yet. Queue that request and query for the |
| // script. Once it is downloaded we'll do the translate. |
| RenderViewHost* rvh = tab_contents->render_view_host(); |
| PendingRequest request; |
| request.render_process_id = rvh->process()->id(); |
| request.render_view_id = rvh->routing_id(); |
| request.page_id = entry->page_id(); |
| request.source_lang = source_lang; |
| request.target_lang = target_lang; |
| pending_requests_.push_back(request); |
| RequestTranslateScript(); |
| } |
| |
| void TranslateManager::RevertTranslation(TabContents* tab_contents) { |
| NavigationEntry* entry = tab_contents->controller().GetActiveEntry(); |
| if (!entry) { |
| NOTREACHED(); |
| return; |
| } |
| tab_contents->render_view_host()->Send(new ViewMsg_RevertTranslation( |
| tab_contents->render_view_host()->routing_id(), entry->page_id())); |
| |
| TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab_contents)->translate_tab_helper(); |
| helper->language_state().set_current_language( |
| helper->language_state().original_language()); |
| } |
| |
| void TranslateManager::ReportLanguageDetectionError(TabContents* tab_contents) { |
| UMA_HISTOGRAM_COUNTS("Translate.ReportLanguageDetectionError", 1); |
| GURL page_url = tab_contents->controller().GetActiveEntry()->url(); |
| std::string report_error_url(kReportLanguageDetectionErrorURL); |
| report_error_url += "?client=cr&action=langidc&u="; |
| report_error_url += EscapeUrlEncodedData(page_url.spec()); |
| report_error_url += "&sl="; |
| |
| TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab_contents)->translate_tab_helper(); |
| report_error_url += helper->language_state().original_language(); |
| report_error_url += "&hl="; |
| report_error_url += |
| GetLanguageCode(g_browser_process->GetApplicationLocale()); |
| // Open that URL in a new tab so that the user can tell us more. |
| Browser* browser = BrowserList::GetLastActive(); |
| if (!browser) { |
| NOTREACHED(); |
| return; |
| } |
| browser->AddSelectedTabWithURL(GURL(report_error_url), |
| PageTransition::AUTO_BOOKMARK); |
| } |
| |
| void TranslateManager::DoTranslatePage(TabContents* tab, |
| const std::string& translate_script, |
| const std::string& source_lang, |
| const std::string& target_lang) { |
| NavigationEntry* entry = tab->controller().GetActiveEntry(); |
| if (!entry) { |
| NOTREACHED(); |
| return; |
| } |
| |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(tab); |
| |
| wrapper->translate_tab_helper()->language_state().set_translation_pending( |
| true); |
| tab->render_view_host()->Send(new ViewMsg_TranslatePage( |
| tab->render_view_host()->routing_id(), entry->page_id(), translate_script, |
| source_lang, target_lang)); |
| |
| // Ideally we'd have a better way to uniquely identify form control elements, |
| // but we don't have that yet. So before start translation, we clear the |
| // current form and re-parse it in AutofillManager first to get the new |
| // labels. |
| if (wrapper) |
| wrapper->autofill_manager()->Reset(); |
| } |
| |
| void TranslateManager::PageTranslated(TabContents* tab, |
| PageTranslatedDetails* details) { |
| // Create the new infobar to display. |
| TranslateInfoBarDelegate* infobar; |
| if (details->error_type != TranslateErrors::NONE) { |
| infobar = TranslateInfoBarDelegate::CreateErrorDelegate(details->error_type, |
| tab, details->source_language, details->target_language); |
| } else if (!IsSupportedLanguage(details->source_language)) { |
| // TODO(jcivelli): http://crbug.com/9390 We should change the "after |
| // translate" infobar to support unknown as the original |
| // language. |
| UMA_HISTOGRAM_COUNTS("Translate.ServerReportedUnsupportedLanguage", 1); |
| infobar = TranslateInfoBarDelegate::CreateErrorDelegate( |
| TranslateErrors::UNSUPPORTED_LANGUAGE, tab, |
| details->source_language, details->target_language); |
| } else { |
| infobar = TranslateInfoBarDelegate::CreateDelegate( |
| TranslateInfoBarDelegate::AFTER_TRANSLATE, tab, |
| details->source_language, details->target_language); |
| } |
| ShowInfoBar(tab, infobar); |
| } |
| |
| bool TranslateManager::IsAcceptLanguage(TabContents* tab, |
| const std::string& language) { |
| PrefService* pref_service = tab->profile()->GetOriginalProfile()->GetPrefs(); |
| PrefServiceLanguagesMap::const_iterator iter = |
| accept_languages_.find(pref_service); |
| if (iter == accept_languages_.end()) { |
| InitAcceptLanguages(pref_service); |
| // Listen for this profile going away, in which case we would need to clear |
| // the accepted languages for the profile. |
| notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, |
| Source<Profile>(tab->profile())); |
| // Also start listening for changes in the accept languages. |
| pref_change_registrar_.Add(prefs::kAcceptLanguages, this); |
| |
| iter = accept_languages_.find(pref_service); |
| } |
| |
| return iter->second.count(language) != 0; |
| } |
| |
| void TranslateManager::InitAcceptLanguages(PrefService* prefs) { |
| // We have been asked for this profile, build the languages. |
| std::string accept_langs_str = prefs->GetString(prefs::kAcceptLanguages); |
| std::vector<std::string> accept_langs_list; |
| LanguageSet accept_langs_set; |
| base::SplitString(accept_langs_str, ',', &accept_langs_list); |
| std::vector<std::string>::const_iterator iter; |
| std::string ui_lang = |
| GetLanguageCode(g_browser_process->GetApplicationLocale()); |
| bool is_ui_english = StartsWithASCII(ui_lang, "en-", false); |
| for (iter = accept_langs_list.begin(); |
| iter != accept_langs_list.end(); ++iter) { |
| // Get rid of the locale extension if any (ex: en-US -> en), but for Chinese |
| // for which the CLD reports zh-CN and zh-TW. |
| std::string accept_lang(*iter); |
| size_t index = iter->find("-"); |
| if (index != std::string::npos && *iter != "zh-CN" && *iter != "zh-TW") |
| accept_lang = iter->substr(0, index); |
| // Special-case English until we resolve bug 36182 properly. |
| // Add English only if the UI language is not English. This will annoy |
| // users of non-English Chrome who can comprehend English until English is |
| // black-listed. |
| // TODO(jungshik): Once we determine that it's safe to remove English from |
| // the default Accept-Language values for most locales, remove this |
| // special-casing. |
| if (accept_lang != "en" || is_ui_english) |
| accept_langs_set.insert(accept_lang); |
| } |
| accept_languages_[prefs] = accept_langs_set; |
| } |
| |
| void TranslateManager::RequestTranslateScript() { |
| if (translate_script_request_pending_) |
| return; |
| |
| translate_script_request_pending_ = true; |
| URLFetcher* fetcher = URLFetcher::Create(0, GURL(kTranslateScriptURL), |
| URLFetcher::GET, this); |
| fetcher->set_request_context(Profile::GetDefaultRequestContext()); |
| fetcher->set_extra_request_headers(kTranslateScriptHeader); |
| fetcher->Start(); |
| } |
| |
| void TranslateManager::ShowInfoBar(TabContents* tab, |
| TranslateInfoBarDelegate* infobar) { |
| TranslateInfoBarDelegate* old_infobar = GetTranslateInfoBarDelegate(tab); |
| infobar->UpdateBackgroundAnimation(old_infobar); |
| if (old_infobar) { |
| // There already is a translate infobar, simply replace it. |
| tab->ReplaceInfoBar(old_infobar, infobar); |
| } else { |
| tab->AddInfoBar(infobar); |
| } |
| } |
| |
| // static |
| std::string TranslateManager::GetTargetLanguage() { |
| std::string target_lang = |
| GetLanguageCode(g_browser_process->GetApplicationLocale()); |
| return IsSupportedLanguage(target_lang) ? target_lang : std::string(); |
| } |
| |
| // static |
| TranslateInfoBarDelegate* TranslateManager::GetTranslateInfoBarDelegate( |
| TabContents* tab) { |
| for (size_t i = 0; i < tab->infobar_count(); ++i) { |
| TranslateInfoBarDelegate* delegate = |
| tab->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate(); |
| if (delegate) |
| return delegate; |
| } |
| return NULL; |
| } |