// 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_infobar_delegate.h" #include <algorithm> #include "base/metrics/histogram.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/translate/translate_infobar_view.h" #include "chrome/browser/translate/translate_manager.h" #include "chrome/browser/translate/translate_tab_helper.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/chrome_constants.h" #include "content/browser/tab_contents/tab_contents.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" // static const size_t TranslateInfoBarDelegate::kNoIndex = static_cast<size_t>(-1); // static TranslateInfoBarDelegate* TranslateInfoBarDelegate::CreateDelegate( Type type, TabContents* tab_contents, const std::string& original_language, const std::string& target_language) { DCHECK_NE(TRANSLATION_ERROR, type); // The original language can only be "unknown" for the "translating" // infobar, which is the case when the user started a translation from the // context menu. DCHECK(type == TRANSLATING || original_language != chrome::kUnknownLanguageCode); if ((original_language != chrome::kUnknownLanguageCode && !TranslateManager::IsSupportedLanguage(original_language)) || !TranslateManager::IsSupportedLanguage(target_language)) return NULL; TranslateInfoBarDelegate* delegate = new TranslateInfoBarDelegate(type, TranslateErrors::NONE, tab_contents, original_language, target_language); DCHECK_NE(kNoIndex, delegate->target_language_index()); return delegate; } TranslateInfoBarDelegate* TranslateInfoBarDelegate::CreateErrorDelegate( TranslateErrors::Type error, TabContents* tab_contents, const std::string& original_language, const std::string& target_language) { return new TranslateInfoBarDelegate(TRANSLATION_ERROR, error, tab_contents, original_language, target_language); } TranslateInfoBarDelegate::~TranslateInfoBarDelegate() { } std::string TranslateInfoBarDelegate::GetLanguageCodeAt(size_t index) const { DCHECK_LT(index, GetLanguageCount()); return languages_[index].first; } string16 TranslateInfoBarDelegate::GetLanguageDisplayableNameAt( size_t index) const { DCHECK_LT(index, GetLanguageCount()); return languages_[index].second; } std::string TranslateInfoBarDelegate::GetOriginalLanguageCode() const { return (original_language_index() == kNoIndex) ? chrome::kUnknownLanguageCode : GetLanguageCodeAt(original_language_index()); } std::string TranslateInfoBarDelegate::GetTargetLanguageCode() const { return GetLanguageCodeAt(target_language_index()); } void TranslateInfoBarDelegate::SetOriginalLanguage(size_t language_index) { DCHECK_LT(language_index, GetLanguageCount()); original_language_index_ = language_index; if (infobar_view_) infobar_view_->OriginalLanguageChanged(); if (type_ == AFTER_TRANSLATE) Translate(); } void TranslateInfoBarDelegate::SetTargetLanguage(size_t language_index) { DCHECK_LT(language_index, GetLanguageCount()); target_language_index_ = language_index; if (infobar_view_) infobar_view_->TargetLanguageChanged(); if (type_ == AFTER_TRANSLATE) Translate(); } void TranslateInfoBarDelegate::Translate() { const std::string& original_language_code = GetOriginalLanguageCode(); if (!tab_contents()->profile()->IsOffTheRecord()) { prefs_.ResetTranslationDeniedCount(original_language_code); prefs_.IncrementTranslationAcceptedCount(original_language_code); } TranslateManager::GetInstance()->TranslatePage(tab_contents_, GetLanguageCodeAt(original_language_index()), GetLanguageCodeAt(target_language_index())); } void TranslateInfoBarDelegate::RevertTranslation() { TranslateManager::GetInstance()->RevertTranslation(tab_contents_); tab_contents_->RemoveInfoBar(this); } void TranslateInfoBarDelegate::ReportLanguageDetectionError() { TranslateManager::GetInstance()->ReportLanguageDetectionError(tab_contents_); } void TranslateInfoBarDelegate::TranslationDeclined() { const std::string& original_language_code = GetOriginalLanguageCode(); if (!tab_contents()->profile()->IsOffTheRecord()) { prefs_.ResetTranslationAcceptedCount(original_language_code); prefs_.IncrementTranslationDeniedCount(original_language_code); } // Remember that the user declined the translation so as to prevent showing a // translate infobar for that page again. (TranslateManager initiates // translations when getting a LANGUAGE_DETERMINED from the page, which // happens when a load stops. That could happen multiple times, including // after the user already declined the translation.) TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents( tab_contents_)->translate_tab_helper(); helper->language_state().set_translation_declined(true); } bool TranslateInfoBarDelegate::IsLanguageBlacklisted() { return prefs_.IsLanguageBlacklisted(GetOriginalLanguageCode()); } void TranslateInfoBarDelegate::ToggleLanguageBlacklist() { const std::string& original_lang = GetOriginalLanguageCode(); if (prefs_.IsLanguageBlacklisted(original_lang)) { prefs_.RemoveLanguageFromBlacklist(original_lang); } else { prefs_.BlacklistLanguage(original_lang); tab_contents_->RemoveInfoBar(this); } } bool TranslateInfoBarDelegate::IsSiteBlacklisted() { std::string host = GetPageHost(); return !host.empty() && prefs_.IsSiteBlacklisted(host); } void TranslateInfoBarDelegate::ToggleSiteBlacklist() { std::string host = GetPageHost(); if (host.empty()) return; if (prefs_.IsSiteBlacklisted(host)) { prefs_.RemoveSiteFromBlacklist(host); } else { prefs_.BlacklistSite(host); tab_contents_->RemoveInfoBar(this); } } bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() { return prefs_.IsLanguagePairWhitelisted(GetOriginalLanguageCode(), GetTargetLanguageCode()); } void TranslateInfoBarDelegate::ToggleAlwaysTranslate() { const std::string& original_lang = GetOriginalLanguageCode(); const std::string& target_lang = GetTargetLanguageCode(); if (prefs_.IsLanguagePairWhitelisted(original_lang, target_lang)) prefs_.RemoveLanguagePairFromWhitelist(original_lang, target_lang); else prefs_.WhitelistLanguagePair(original_lang, target_lang); } void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() { const std::string& original_lang = GetOriginalLanguageCode(); const std::string& target_lang = GetTargetLanguageCode(); DCHECK(!prefs_.IsLanguagePairWhitelisted(original_lang, target_lang)); prefs_.WhitelistLanguagePair(original_lang, target_lang); Translate(); } void TranslateInfoBarDelegate::NeverTranslatePageLanguage() { std::string original_lang = GetOriginalLanguageCode(); DCHECK(!prefs_.IsLanguageBlacklisted(original_lang)); prefs_.BlacklistLanguage(original_lang); tab_contents_->RemoveInfoBar(this); } string16 TranslateInfoBarDelegate::GetMessageInfoBarText() { if (type_ == TRANSLATING) { return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO, GetLanguageDisplayableNameAt(target_language_index_)); } DCHECK_EQ(TRANSLATION_ERROR, type_); switch (error_) { case TranslateErrors::NETWORK: return l10n_util::GetStringUTF16( IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT); case TranslateErrors::INITIALIZATION_ERROR: case TranslateErrors::TRANSLATION_ERROR: return l10n_util::GetStringUTF16( IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE); case TranslateErrors::UNKNOWN_LANGUAGE: return l10n_util::GetStringUTF16( IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE); case TranslateErrors::UNSUPPORTED_LANGUAGE: return l10n_util::GetStringFUTF16( IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE, GetLanguageDisplayableNameAt(target_language_index_)); case TranslateErrors::IDENTICAL_LANGUAGES: return l10n_util::GetStringFUTF16( IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE, GetLanguageDisplayableNameAt(target_language_index_)); default: NOTREACHED(); return string16(); } } string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() { if (type_ != TRANSLATION_ERROR) { DCHECK_EQ(TRANSLATING, type_); } else if ((error_ != TranslateErrors::IDENTICAL_LANGUAGES) && (error_ != TranslateErrors::UNKNOWN_LANGUAGE)) { return l10n_util::GetStringUTF16( (error_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ? IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY); } return string16(); } void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() { DCHECK_EQ(TRANSLATION_ERROR, type_); if (error_ == TranslateErrors::UNSUPPORTED_LANGUAGE) { RevertTranslation(); return; } // This is the "Try again..." case. TranslateManager::GetInstance()->TranslatePage(tab_contents_, GetOriginalLanguageCode(), GetTargetLanguageCode()); } bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() { return !GetMessageInfoBarButtonText().empty(); } bool TranslateInfoBarDelegate::ShouldShowNeverTranslateButton() { DCHECK_EQ(BEFORE_TRANSLATE, type_); return !tab_contents()->profile()->IsOffTheRecord() && (prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3); } bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateButton() { DCHECK_EQ(BEFORE_TRANSLATE, type_); return !tab_contents()->profile()->IsOffTheRecord() && (prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3); } void TranslateInfoBarDelegate::UpdateBackgroundAnimation( TranslateInfoBarDelegate* previous_infobar) { if (!previous_infobar || previous_infobar->IsError() == IsError()) background_animation_ = NONE; else background_animation_ = IsError() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL; } // static string16 TranslateInfoBarDelegate::GetLanguageDisplayableName( const std::string& language_code) { return l10n_util::GetDisplayNameForLocale( language_code, g_browser_process->GetApplicationLocale(), true); } // static void TranslateInfoBarDelegate::GetAfterTranslateStrings( std::vector<string16>* strings, bool* swap_languages) { DCHECK(strings); DCHECK(swap_languages); std::vector<size_t> offsets; string16 text = l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, string16(), string16(), &offsets); DCHECK_EQ(2U, offsets.size()); *swap_languages = (offsets[0] > offsets[1]); if (*swap_languages) std::swap(offsets[0], offsets[1]); strings->push_back(text.substr(0, offsets[0])); strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0])); strings->push_back(text.substr(offsets[1])); } TranslateInfoBarDelegate::TranslateInfoBarDelegate( Type type, TranslateErrors::Type error, TabContents* tab_contents, const std::string& original_language, const std::string& target_language) : InfoBarDelegate(tab_contents), type_(type), background_animation_(NONE), tab_contents_(tab_contents), original_language_index_(kNoIndex), initial_original_language_index_(kNoIndex), target_language_index_(kNoIndex), error_(error), infobar_view_(NULL), prefs_(tab_contents_->profile()->GetPrefs()) { DCHECK_NE((type_ == TRANSLATION_ERROR), (error == TranslateErrors::NONE)); std::vector<std::string> language_codes; TranslateManager::GetSupportedLanguages(&language_codes); languages_.reserve(language_codes.size()); for (std::vector<std::string>::const_iterator iter = language_codes.begin(); iter != language_codes.end(); ++iter) { std::string language_code = *iter; string16 language_name = GetLanguageDisplayableName(language_code); // Insert the language in languages_ in alphabetical order. std::vector<LanguageNamePair>::iterator iter2; for (iter2 = languages_.begin(); iter2 != languages_.end(); ++iter2) { if (language_name.compare(iter2->second) < 0) break; } languages_.insert(iter2, LanguageNamePair(language_code, language_name)); } for (std::vector<LanguageNamePair>::const_iterator iter = languages_.begin(); iter != languages_.end(); ++iter) { std::string language_code = iter->first; if (language_code == original_language) { original_language_index_ = iter - languages_.begin(); initial_original_language_index_ = original_language_index_; } if (language_code == target_language) target_language_index_ = iter - languages_.begin(); } } void TranslateInfoBarDelegate::InfoBarDismissed() { if (type_ != BEFORE_TRANSLATE) return; // The user closed the infobar without clicking the translate button. TranslationDeclined(); UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslateCloseInfobar", 1); } void TranslateInfoBarDelegate::InfoBarClosed() { delete this; } SkBitmap* TranslateInfoBarDelegate::GetIcon() const { return ResourceBundle::GetSharedInstance().GetBitmapNamed( IDR_INFOBAR_TRANSLATE); } InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const { return PAGE_ACTION_TYPE; } TranslateInfoBarDelegate* TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() { return this; } std::string TranslateInfoBarDelegate::GetPageHost() { NavigationEntry* entry = tab_contents_->controller().GetActiveEntry(); return entry ? entry->url().HostNoBrackets() : std::string(); }