OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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_manager2.h" |
| 6 |
| 7 #include "app/resource_bundle.h" |
| 8 #include "base/compiler_specific.h" |
| 9 #include "base/string_util.h" |
| 10 #include "chrome/browser/browser_process.h" |
| 11 #include "chrome/browser/pref_service.h" |
| 12 #include "chrome/browser/profile.h" |
| 13 #include "chrome/browser/renderer_host/render_process_host.h" |
| 14 #include "chrome/browser/renderer_host/render_view_host.h" |
| 15 #include "chrome/browser/tab_contents/language_state.h" |
| 16 #include "chrome/browser/tab_contents/navigation_controller.h" |
| 17 #include "chrome/browser/tab_contents/navigation_entry.h" |
| 18 #include "chrome/browser/tab_contents/tab_contents.h" |
| 19 #include "chrome/browser/tab_contents/tab_util.h" |
| 20 #include "chrome/browser/translate/page_translated_details.h" |
| 21 #include "chrome/browser/translate/translate_infobar_delegate2.h" |
| 22 #include "chrome/browser/translate/translate_prefs.h" |
| 23 #include "chrome/common/notification_details.h" |
| 24 #include "chrome/common/notification_service.h" |
| 25 #include "chrome/common/notification_source.h" |
| 26 #include "chrome/common/notification_type.h" |
| 27 #include "chrome/common/pref_names.h" |
| 28 #include "chrome/common/translate_errors.h" |
| 29 #include "grit/browser_resources.h" |
| 30 #include "net/url_request/url_request_status.h" |
| 31 |
| 32 namespace { |
| 33 |
| 34 // Mapping from a locale name to a language code name. |
| 35 // Locale names not included are translated as is. |
| 36 struct LocaleToCLDLanguage { |
| 37 const char* locale_language; // Language Chrome locale is in. |
| 38 const char* cld_language; // Language the CLD reports. |
| 39 }; |
| 40 LocaleToCLDLanguage kLocaleToCLDLanguages[] = { |
| 41 { "en-GB", "en" }, |
| 42 { "en-US", "en" }, |
| 43 { "es-419", "es" }, |
| 44 { "pt-BR", "pt" }, |
| 45 { "pt-PT", "pt" }, |
| 46 }; |
| 47 |
| 48 // The list of languages the Google translation server supports. |
| 49 // For information, here is the list of languages that Chrome can be run in |
| 50 // but that the translation server does not support: |
| 51 // am Amharic |
| 52 // bn Bengali |
| 53 // gu Gujarati |
| 54 // kn Kannada |
| 55 // ml Malayalam |
| 56 // mr Marathi |
| 57 // ta Tamil |
| 58 // te Telugu |
| 59 const char* kSupportedLanguages[] = { |
| 60 "af", // Afrikaans |
| 61 "sq", // Albanian |
| 62 "ar", // Arabic |
| 63 "be", // Belarusian |
| 64 "bg", // Bulgarian |
| 65 "ca", // Catalan |
| 66 "zh-CN", // Chinese (Simplified) |
| 67 "zh-TW", // Chinese (Traditional) |
| 68 "hr", // Croatian |
| 69 "cs", // Czech |
| 70 "da", // Danish |
| 71 "nl", // Dutch |
| 72 "en", // English |
| 73 "et", // Estonian |
| 74 "fi", // Finnish |
| 75 "fil", // Filipino |
| 76 "fr", // French |
| 77 "gl", // Galician |
| 78 "de", // German |
| 79 "el", // Greek |
| 80 "he", // Hebrew |
| 81 "hi", // Hindi |
| 82 "hu", // Hungarian |
| 83 "is", // Icelandic |
| 84 "id", // Indonesian |
| 85 "it", // Italian |
| 86 "ga", // Irish |
| 87 "ja", // Japanese |
| 88 "ko", // Korean |
| 89 "lv", // Latvian |
| 90 "lt", // Lithuanian |
| 91 "mk", // Macedonian |
| 92 "ms", // Malay |
| 93 "mt", // Maltese |
| 94 "nb", // Norwegian |
| 95 "fa", // Persian |
| 96 "pl", // Polish |
| 97 "pt", // Portuguese |
| 98 "ro", // Romanian |
| 99 "ru", // Russian |
| 100 "sr", // Serbian |
| 101 "sk", // Slovak |
| 102 "sl", // Slovenian |
| 103 "es", // Spanish |
| 104 "sw", // Swahili |
| 105 "sv", // Swedish |
| 106 "th", // Thai |
| 107 "tr", // Turkish |
| 108 "uk", // Ukrainian |
| 109 "vi", // Vietnamese |
| 110 "cy", // Welsh |
| 111 "yi", // Yiddish |
| 112 }; |
| 113 |
| 114 const char* const kTranslateScriptURL = |
| 115 "http://translate.google.com/translate_a/element.js?" |
| 116 "cb=cr.googleTranslate.onTranslateElementLoad"; |
| 117 const char* const kTranslateScriptHeader = |
| 118 "Google-Translate-Element-Mode: library"; |
| 119 |
| 120 } // namespace |
| 121 |
| 122 // static |
| 123 base::LazyInstance<std::set<std::string> > |
| 124 TranslateManager2::supported_languages_(base::LINKER_INITIALIZED); |
| 125 |
| 126 TranslateManager2::~TranslateManager2() { |
| 127 } |
| 128 |
| 129 // static |
| 130 bool TranslateManager2::IsTranslatableURL(const GURL& url) { |
| 131 return !url.SchemeIs("chrome"); |
| 132 } |
| 133 |
| 134 // static |
| 135 void TranslateManager2::GetSupportedLanguages( |
| 136 std::vector<std::string>* languages) { |
| 137 DCHECK(languages && languages->empty()); |
| 138 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i) |
| 139 languages->push_back(kSupportedLanguages[i]); |
| 140 } |
| 141 |
| 142 // static |
| 143 std::string TranslateManager2::GetLanguageCode( |
| 144 const std::string& chrome_locale) { |
| 145 for (size_t i = 0; i < arraysize(kLocaleToCLDLanguages); ++i) { |
| 146 if (chrome_locale == kLocaleToCLDLanguages[i].locale_language) |
| 147 return kLocaleToCLDLanguages[i].cld_language; |
| 148 } |
| 149 return chrome_locale; |
| 150 } |
| 151 |
| 152 // static |
| 153 bool TranslateManager2::IsSupportedLanguage(const std::string& page_language) { |
| 154 if (supported_languages_.Pointer()->empty()) { |
| 155 for (size_t i = 0; i < arraysize(kSupportedLanguages); ++i) |
| 156 supported_languages_.Pointer()->insert(kSupportedLanguages[i]); |
| 157 } |
| 158 return supported_languages_.Pointer()->find(page_language) != |
| 159 supported_languages_.Pointer()->end(); |
| 160 } |
| 161 |
| 162 void TranslateManager2::Observe(NotificationType type, |
| 163 const NotificationSource& source, |
| 164 const NotificationDetails& details) { |
| 165 switch (type.value) { |
| 166 case NotificationType::NAV_ENTRY_COMMITTED: { |
| 167 NavigationController* controller = |
| 168 Source<NavigationController>(source).ptr(); |
| 169 NavigationController::LoadCommittedDetails* load_details = |
| 170 Details<NavigationController::LoadCommittedDetails>(details).ptr(); |
| 171 NavigationEntry* entry = controller->GetActiveEntry(); |
| 172 if (!entry) { |
| 173 NOTREACHED(); |
| 174 return; |
| 175 } |
| 176 if (entry->transition_type() != PageTransition::RELOAD && |
| 177 load_details->type != NavigationType::SAME_PAGE) { |
| 178 return; |
| 179 } |
| 180 // When doing a page reload, we don't get a TAB_LANGUAGE_DETERMINED |
| 181 // notification. So we need to explictly initiate the translation. |
| 182 // Note that we delay it as the TranslateManager2 gets this notification |
| 183 // before the TabContents and the TabContents processing might remove the |
| 184 // current infobars. Since InitTranslation might add an infobar, it must |
| 185 // be done after that. |
| 186 MessageLoop::current()->PostTask(FROM_HERE, |
| 187 method_factory_.NewRunnableMethod( |
| 188 &TranslateManager2::InitiateTranslationPosted, |
| 189 controller->tab_contents()->render_view_host()->process()->id(), |
| 190 controller->tab_contents()->render_view_host()->routing_id(), |
| 191 controller->tab_contents()->language_state(). |
| 192 original_language())); |
| 193 break; |
| 194 } |
| 195 case NotificationType::TAB_LANGUAGE_DETERMINED: { |
| 196 TabContents* tab = Source<TabContents>(source).ptr(); |
| 197 // We may get this notifications multiple times. Make sure to translate |
| 198 // only once. |
| 199 LanguageState& language_state = tab->language_state(); |
| 200 if (!language_state.translation_pending() && |
| 201 !language_state.translation_declined() && |
| 202 !language_state.IsPageTranslated()) { |
| 203 std::string language = *(Details<std::string>(details).ptr()); |
| 204 InitiateTranslation(tab, language); |
| 205 } |
| 206 break; |
| 207 } |
| 208 case NotificationType::PAGE_TRANSLATED: { |
| 209 // Only add translate infobar if it doesn't exist; if it already exists, |
| 210 // just update the state, the actual infobar would have received the same |
| 211 // notification and update the visual display accordingly. |
| 212 TabContents* tab = Source<TabContents>(source).ptr(); |
| 213 PageTranslatedDetails* page_translated_details = |
| 214 Details<PageTranslatedDetails>(details).ptr(); |
| 215 PageTranslated(tab, page_translated_details); |
| 216 break; |
| 217 } |
| 218 case NotificationType::PROFILE_DESTROYED: { |
| 219 Profile* profile = Source<Profile>(source).ptr(); |
| 220 notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, |
| 221 source); |
| 222 size_t count = accept_languages_.erase(profile->GetPrefs()); |
| 223 // We should know about this profile since we are listening for |
| 224 // notifications on it. |
| 225 DCHECK(count > 0); |
| 226 profile->GetPrefs()->RemovePrefObserver(prefs::kAcceptLanguages, this); |
| 227 break; |
| 228 } |
| 229 case NotificationType::PREF_CHANGED: { |
| 230 DCHECK(*Details<std::wstring>(details).ptr() == prefs::kAcceptLanguages); |
| 231 PrefService* prefs = Source<PrefService>(source).ptr(); |
| 232 InitAcceptLanguages(prefs); |
| 233 break; |
| 234 } |
| 235 default: |
| 236 NOTREACHED(); |
| 237 } |
| 238 } |
| 239 |
| 240 void TranslateManager2::OnURLFetchComplete(const URLFetcher* source, |
| 241 const GURL& url, |
| 242 const URLRequestStatus& status, |
| 243 int response_code, |
| 244 const ResponseCookies& cookies, |
| 245 const std::string& data) { |
| 246 scoped_ptr<const URLFetcher> delete_ptr(source); |
| 247 DCHECK(translate_script_request_pending_); |
| 248 translate_script_request_pending_ = false; |
| 249 bool error = |
| 250 (status.status() != URLRequestStatus::SUCCESS || response_code != 200); |
| 251 |
| 252 if (!error) { |
| 253 base::StringPiece str = ResourceBundle::GetSharedInstance(). |
| 254 GetRawDataResource(IDR_TRANSLATE_JS); |
| 255 DCHECK(translate_script_.empty()); |
| 256 str.CopyToString(&translate_script_); |
| 257 translate_script_ += "\n" + data; |
| 258 } |
| 259 |
| 260 // Process any pending requests. |
| 261 std::vector<PendingRequest>::const_iterator iter; |
| 262 for (iter = pending_requests_.begin(); iter != pending_requests_.end(); |
| 263 ++iter) { |
| 264 const PendingRequest& request = *iter; |
| 265 TabContents* tab = tab_util::GetTabContentsByID(request.render_process_id, |
| 266 request.render_view_id); |
| 267 if (!tab) { |
| 268 // The tab went away while we were retrieving the script. |
| 269 continue; |
| 270 } |
| 271 NavigationEntry* entry = tab->controller().GetActiveEntry(); |
| 272 if (!entry || entry->page_id() != request.page_id) { |
| 273 // We navigated away from the page the translation was triggered on. |
| 274 continue; |
| 275 } |
| 276 |
| 277 if (error) { |
| 278 ShowInfoBar(tab, |
| 279 TranslateInfoBarDelegate2::CreateInstance( |
| 280 TranslateInfoBarDelegate2::TRANSLATION_ERROR, |
| 281 TranslateErrors::NETWORK, |
| 282 tab, request.source_lang, request.target_lang)); |
| 283 } else { |
| 284 // Translate the page. |
| 285 DoTranslatePage(tab, translate_script_, |
| 286 request.source_lang, request.target_lang); |
| 287 } |
| 288 } |
| 289 pending_requests_.clear(); |
| 290 } |
| 291 |
| 292 // static |
| 293 bool TranslateManager2::IsShowingTranslateInfobar(TabContents* tab) { |
| 294 return GetTranslateInfoBarDelegate2(tab) != NULL; |
| 295 } |
| 296 |
| 297 TranslateManager2::TranslateManager2() |
| 298 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), |
| 299 translate_script_request_pending_(false) { |
| 300 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, |
| 301 NotificationService::AllSources()); |
| 302 notification_registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, |
| 303 NotificationService::AllSources()); |
| 304 notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, |
| 305 NotificationService::AllSources()); |
| 306 } |
| 307 |
| 308 void TranslateManager2::InitiateTranslation(TabContents* tab, |
| 309 const std::string& page_lang) { |
| 310 PrefService* prefs = tab->profile()->GetPrefs(); |
| 311 if (!prefs->GetBoolean(prefs::kEnableTranslate)) |
| 312 return; |
| 313 |
| 314 NavigationEntry* entry = tab->controller().GetActiveEntry(); |
| 315 if (!entry) { |
| 316 // This can happen for popups created with window.open(""). |
| 317 return; |
| 318 } |
| 319 |
| 320 // If there is already a translate infobar showing, don't show another one. |
| 321 if (GetTranslateInfoBarDelegate2(tab)) |
| 322 return; |
| 323 |
| 324 std::string target_lang = GetTargetLanguage(); |
| 325 // Nothing to do if either the language Chrome is in or the language of the |
| 326 // page is not supported by the translation server. |
| 327 if (target_lang.empty() || !IsSupportedLanguage(page_lang)) { |
| 328 return; |
| 329 } |
| 330 |
| 331 // We don't want to translate: |
| 332 // - any Chrome specific page (New Tab Page, Download, History... pages). |
| 333 // - similar languages (ex: en-US to en). |
| 334 // - any user black-listed URLs or user selected language combination. |
| 335 // - any language the user configured as accepted languages. |
| 336 if (!IsTranslatableURL(entry->url()) || page_lang == target_lang || |
| 337 !TranslatePrefs::CanTranslate(prefs, page_lang, entry->url()) || |
| 338 IsAcceptLanguage(tab, page_lang)) { |
| 339 return; |
| 340 } |
| 341 |
| 342 // If the user has previously selected "always translate" for this language we |
| 343 // automatically translate. Note that in incognito mode we disable that |
| 344 // feature; the user will get an infobar, so they can control whether the |
| 345 // page's text is sent to the translate server. |
| 346 std::string auto_target_lang; |
| 347 if (!tab->profile()->IsOffTheRecord() && |
| 348 TranslatePrefs::ShouldAutoTranslate(prefs, page_lang, |
| 349 &auto_target_lang)) { |
| 350 TranslatePage(tab, page_lang, auto_target_lang); |
| 351 return; |
| 352 } |
| 353 |
| 354 std::string auto_translate_to = tab->language_state().AutoTranslateTo(); |
| 355 if (!auto_translate_to.empty()) { |
| 356 // This page was navigated through a click from a translated page. |
| 357 TranslatePage(tab, page_lang, auto_translate_to); |
| 358 return; |
| 359 } |
| 360 |
| 361 // Prompts the user if he/she wants the page translated. |
| 362 tab->AddInfoBar(TranslateInfoBarDelegate2::CreateInstance( |
| 363 TranslateInfoBarDelegate2::BEFORE_TRANSLATE, |
| 364 TranslateErrors::NONE, tab, page_lang, target_lang)); |
| 365 } |
| 366 |
| 367 void TranslateManager2::InitiateTranslationPosted( |
| 368 int process_id, int render_id, const std::string& page_lang) { |
| 369 // The tab might have been closed. |
| 370 TabContents* tab = tab_util::GetTabContentsByID(process_id, render_id); |
| 371 if (!tab || tab->language_state().translation_pending()) |
| 372 return; |
| 373 |
| 374 InitiateTranslation(tab, page_lang); |
| 375 } |
| 376 |
| 377 void TranslateManager2::TranslatePage(TabContents* tab_contents, |
| 378 const std::string& source_lang, |
| 379 const std::string& target_lang) { |
| 380 NavigationEntry* entry = tab_contents->controller().GetActiveEntry(); |
| 381 if (!entry) { |
| 382 NOTREACHED(); |
| 383 return; |
| 384 } |
| 385 if (!translate_script_.empty()) { |
| 386 DoTranslatePage(tab_contents, translate_script_, source_lang, target_lang); |
| 387 return; |
| 388 } |
| 389 |
| 390 // The script is not available yet. Queue that request and query for the |
| 391 // script. Once it is downloaded we'll do the translate. |
| 392 RenderViewHost* rvh = tab_contents->render_view_host(); |
| 393 PendingRequest request; |
| 394 request.render_process_id = rvh->process()->id(); |
| 395 request.render_view_id = rvh->routing_id(); |
| 396 request.page_id = entry->page_id(); |
| 397 request.source_lang = source_lang; |
| 398 request.target_lang = target_lang; |
| 399 pending_requests_.push_back(request); |
| 400 RequestTranslateScript(); |
| 401 } |
| 402 |
| 403 void TranslateManager2::RevertTranslation(TabContents* tab_contents) { |
| 404 NavigationEntry* entry = tab_contents->controller().GetActiveEntry(); |
| 405 if (!entry) { |
| 406 NOTREACHED(); |
| 407 return; |
| 408 } |
| 409 tab_contents->render_view_host()->RevertTranslation(entry->page_id()); |
| 410 tab_contents->language_state().set_current_language( |
| 411 tab_contents->language_state().original_language()); |
| 412 } |
| 413 |
| 414 void TranslateManager2::DoTranslatePage(TabContents* tab, |
| 415 const std::string& translate_script, |
| 416 const std::string& source_lang, |
| 417 const std::string& target_lang) { |
| 418 NavigationEntry* entry = tab->controller().GetActiveEntry(); |
| 419 if (!entry) { |
| 420 NOTREACHED(); |
| 421 return; |
| 422 } |
| 423 |
| 424 TranslateInfoBarDelegate2* infobar = GetTranslateInfoBarDelegate2(tab); |
| 425 if (infobar) { |
| 426 // We don't show the translating infobar if no translate infobar is already |
| 427 // showing (that is the case when the translation was triggered by the |
| 428 // "always translate" for example). |
| 429 infobar = TranslateInfoBarDelegate2::CreateInstance( |
| 430 TranslateInfoBarDelegate2::TRANSLATING, TranslateErrors::NONE, |
| 431 tab, source_lang, target_lang); |
| 432 ShowInfoBar(tab, infobar); |
| 433 } |
| 434 tab->language_state().set_translation_pending(true); |
| 435 tab->render_view_host()->TranslatePage(entry->page_id(), translate_script, |
| 436 source_lang, target_lang); |
| 437 } |
| 438 |
| 439 void TranslateManager2::PageTranslated(TabContents* tab, |
| 440 PageTranslatedDetails* details) { |
| 441 // Create the new infobar to display. |
| 442 TranslateInfoBarDelegate2* infobar; |
| 443 if (details->error_type != TranslateErrors::NONE) { |
| 444 infobar = TranslateInfoBarDelegate2::CreateInstance( |
| 445 TranslateInfoBarDelegate2::TRANSLATION_ERROR, details->error_type, |
| 446 tab, details->source_language, details->target_language); |
| 447 } else { |
| 448 infobar = TranslateInfoBarDelegate2::CreateInstance( |
| 449 TranslateInfoBarDelegate2::AFTER_TRANSLATE, TranslateErrors::NONE, |
| 450 tab, details->source_language, details->target_language); |
| 451 } |
| 452 ShowInfoBar(tab, infobar); |
| 453 } |
| 454 |
| 455 bool TranslateManager2::IsAcceptLanguage(TabContents* tab, |
| 456 const std::string& language) { |
| 457 PrefService* pref_service = tab->profile()->GetPrefs(); |
| 458 PrefServiceLanguagesMap::const_iterator iter = |
| 459 accept_languages_.find(pref_service); |
| 460 if (iter == accept_languages_.end()) { |
| 461 InitAcceptLanguages(pref_service); |
| 462 // Listen for this profile going away, in which case we would need to clear |
| 463 // the accepted languages for the profile. |
| 464 notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, |
| 465 Source<Profile>(tab->profile())); |
| 466 // Also start listening for changes in the accept languages. |
| 467 tab->profile()->GetPrefs()->AddPrefObserver(prefs::kAcceptLanguages, this); |
| 468 |
| 469 iter = accept_languages_.find(pref_service); |
| 470 } |
| 471 |
| 472 return iter->second.count(language) != 0; |
| 473 } |
| 474 |
| 475 void TranslateManager2::InitAcceptLanguages(PrefService* prefs) { |
| 476 // We have been asked for this profile, build the languages. |
| 477 std::wstring accept_langs_str = prefs->GetString(prefs::kAcceptLanguages); |
| 478 std::vector<std::string> accept_langs_list; |
| 479 LanguageSet accept_langs_set; |
| 480 SplitString(WideToASCII(accept_langs_str), ',', &accept_langs_list); |
| 481 std::vector<std::string>::const_iterator iter; |
| 482 std::string ui_lang = |
| 483 GetLanguageCode(g_browser_process->GetApplicationLocale()); |
| 484 bool is_ui_english = StartsWithASCII(ui_lang, "en-", false); |
| 485 for (iter = accept_langs_list.begin(); |
| 486 iter != accept_langs_list.end(); ++iter) { |
| 487 // Get rid of the locale extension if any (ex: en-US -> en), but for Chinese |
| 488 // for which the CLD reports zh-CN and zh-TW. |
| 489 std::string accept_lang(*iter); |
| 490 size_t index = iter->find("-"); |
| 491 if (index != std::string::npos && *iter != "zh-CN" && *iter != "zh-TW") |
| 492 accept_lang = iter->substr(0, index); |
| 493 // Special-case English until we resolve bug 36182 properly. |
| 494 // Add English only if the UI language is not English. This will annoy |
| 495 // users of non-English Chrome who can comprehend English until English is |
| 496 // black-listed. |
| 497 // TODO(jungshik): Once we determine that it's safe to remove English from |
| 498 // the default Accept-Language values for most locales, remove this |
| 499 // special-casing. |
| 500 if (accept_lang != "en" || is_ui_english) |
| 501 accept_langs_set.insert(accept_lang); |
| 502 } |
| 503 accept_languages_[prefs] = accept_langs_set; |
| 504 } |
| 505 |
| 506 void TranslateManager2::RequestTranslateScript() { |
| 507 if (translate_script_request_pending_) |
| 508 return; |
| 509 |
| 510 translate_script_request_pending_ = true; |
| 511 URLFetcher* fetcher = URLFetcher::Create(0, GURL(kTranslateScriptURL), |
| 512 URLFetcher::GET, this); |
| 513 fetcher->set_request_context(Profile::GetDefaultRequestContext()); |
| 514 fetcher->set_extra_request_headers(kTranslateScriptHeader); |
| 515 fetcher->Start(); |
| 516 } |
| 517 |
| 518 void TranslateManager2::ShowInfoBar(TabContents* tab, |
| 519 TranslateInfoBarDelegate2* infobar) { |
| 520 TranslateInfoBarDelegate2* old_infobar = GetTranslateInfoBarDelegate2(tab); |
| 521 infobar->UpdateBackgroundAnimation(old_infobar); |
| 522 if (old_infobar) { |
| 523 // There already is a translate infobar, simply replace it. |
| 524 tab->ReplaceInfoBar(old_infobar, infobar); |
| 525 } else { |
| 526 tab->AddInfoBar(infobar); |
| 527 } |
| 528 } |
| 529 |
| 530 // static |
| 531 std::string TranslateManager2::GetTargetLanguage() { |
| 532 std::string target_lang = |
| 533 GetLanguageCode(g_browser_process->GetApplicationLocale()); |
| 534 if (IsSupportedLanguage(target_lang)) |
| 535 return target_lang; |
| 536 return std::string(); |
| 537 } |
| 538 |
| 539 // static |
| 540 TranslateInfoBarDelegate2* TranslateManager2::GetTranslateInfoBarDelegate2( |
| 541 TabContents* tab) { |
| 542 for (int i = 0; i < tab->infobar_delegate_count(); ++i) { |
| 543 TranslateInfoBarDelegate2* delegate = |
| 544 tab->GetInfoBarDelegateAt(i)->AsTranslateInfoBarDelegate2(); |
| 545 if (delegate) |
| 546 return delegate; |
| 547 } |
| 548 return NULL; |
| 549 } |
OLD | NEW |