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 3// found in the LICENSE file. 4 5#include "chrome/browser/translate/translate_infobar_delegate.h" 6 7#include <algorithm> 8 9#include "base/metrics/histogram.h" 10#include "chrome/browser/browser_process.h" 11#include "chrome/browser/profiles/profile.h" 12#include "chrome/browser/translate/translate_infobar_view.h" 13#include "chrome/browser/translate/translate_manager.h" 14#include "chrome/browser/translate/translate_tab_helper.h" 15#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 16#include "chrome/common/chrome_constants.h" 17#include "content/browser/tab_contents/tab_contents.h" 18#include "grit/generated_resources.h" 19#include "grit/theme_resources.h" 20#include "ui/base/l10n/l10n_util.h" 21#include "ui/base/resource/resource_bundle.h" 22 23// static 24const size_t TranslateInfoBarDelegate::kNoIndex = static_cast<size_t>(-1); 25 26// static 27TranslateInfoBarDelegate* TranslateInfoBarDelegate::CreateDelegate( 28 Type type, 29 TabContents* tab_contents, 30 const std::string& original_language, 31 const std::string& target_language) { 32 DCHECK_NE(TRANSLATION_ERROR, type); 33 // The original language can only be "unknown" for the "translating" 34 // infobar, which is the case when the user started a translation from the 35 // context menu. 36 DCHECK(type == TRANSLATING || 37 original_language != chrome::kUnknownLanguageCode); 38 if ((original_language != chrome::kUnknownLanguageCode && 39 !TranslateManager::IsSupportedLanguage(original_language)) || 40 !TranslateManager::IsSupportedLanguage(target_language)) 41 return NULL; 42 TranslateInfoBarDelegate* delegate = 43 new TranslateInfoBarDelegate(type, TranslateErrors::NONE, tab_contents, 44 original_language, target_language); 45 DCHECK_NE(kNoIndex, delegate->target_language_index()); 46 return delegate; 47} 48 49TranslateInfoBarDelegate* TranslateInfoBarDelegate::CreateErrorDelegate( 50 TranslateErrors::Type error, 51 TabContents* tab_contents, 52 const std::string& original_language, 53 const std::string& target_language) { 54 return new TranslateInfoBarDelegate(TRANSLATION_ERROR, error, tab_contents, 55 original_language, target_language); 56} 57 58TranslateInfoBarDelegate::~TranslateInfoBarDelegate() { 59} 60 61std::string TranslateInfoBarDelegate::GetLanguageCodeAt(size_t index) const { 62 DCHECK_LT(index, GetLanguageCount()); 63 return languages_[index].first; 64} 65 66string16 TranslateInfoBarDelegate::GetLanguageDisplayableNameAt( 67 size_t index) const { 68 DCHECK_LT(index, GetLanguageCount()); 69 return languages_[index].second; 70} 71 72std::string TranslateInfoBarDelegate::GetOriginalLanguageCode() const { 73 return (original_language_index() == kNoIndex) ? 74 chrome::kUnknownLanguageCode : 75 GetLanguageCodeAt(original_language_index()); 76} 77 78std::string TranslateInfoBarDelegate::GetTargetLanguageCode() const { 79 return GetLanguageCodeAt(target_language_index()); 80} 81 82void TranslateInfoBarDelegate::SetOriginalLanguage(size_t language_index) { 83 DCHECK_LT(language_index, GetLanguageCount()); 84 original_language_index_ = language_index; 85 if (infobar_view_) 86 infobar_view_->OriginalLanguageChanged(); 87 if (type_ == AFTER_TRANSLATE) 88 Translate(); 89} 90 91void TranslateInfoBarDelegate::SetTargetLanguage(size_t language_index) { 92 DCHECK_LT(language_index, GetLanguageCount()); 93 target_language_index_ = language_index; 94 if (infobar_view_) 95 infobar_view_->TargetLanguageChanged(); 96 if (type_ == AFTER_TRANSLATE) 97 Translate(); 98} 99 100void TranslateInfoBarDelegate::Translate() { 101 const std::string& original_language_code = GetOriginalLanguageCode(); 102 if (!tab_contents()->profile()->IsOffTheRecord()) { 103 prefs_.ResetTranslationDeniedCount(original_language_code); 104 prefs_.IncrementTranslationAcceptedCount(original_language_code); 105 } 106 107 TranslateManager::GetInstance()->TranslatePage(tab_contents_, 108 GetLanguageCodeAt(original_language_index()), 109 GetLanguageCodeAt(target_language_index())); 110} 111 112void TranslateInfoBarDelegate::RevertTranslation() { 113 TranslateManager::GetInstance()->RevertTranslation(tab_contents_); 114 tab_contents_->RemoveInfoBar(this); 115} 116 117void TranslateInfoBarDelegate::ReportLanguageDetectionError() { 118 TranslateManager::GetInstance()->ReportLanguageDetectionError(tab_contents_); 119} 120 121void TranslateInfoBarDelegate::TranslationDeclined() { 122 const std::string& original_language_code = GetOriginalLanguageCode(); 123 if (!tab_contents()->profile()->IsOffTheRecord()) { 124 prefs_.ResetTranslationAcceptedCount(original_language_code); 125 prefs_.IncrementTranslationDeniedCount(original_language_code); 126 } 127 128 // Remember that the user declined the translation so as to prevent showing a 129 // translate infobar for that page again. (TranslateManager initiates 130 // translations when getting a LANGUAGE_DETERMINED from the page, which 131 // happens when a load stops. That could happen multiple times, including 132 // after the user already declined the translation.) 133 TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents( 134 tab_contents_)->translate_tab_helper(); 135 helper->language_state().set_translation_declined(true); 136} 137 138bool TranslateInfoBarDelegate::IsLanguageBlacklisted() { 139 return prefs_.IsLanguageBlacklisted(GetOriginalLanguageCode()); 140} 141 142void TranslateInfoBarDelegate::ToggleLanguageBlacklist() { 143 const std::string& original_lang = GetOriginalLanguageCode(); 144 if (prefs_.IsLanguageBlacklisted(original_lang)) { 145 prefs_.RemoveLanguageFromBlacklist(original_lang); 146 } else { 147 prefs_.BlacklistLanguage(original_lang); 148 tab_contents_->RemoveInfoBar(this); 149 } 150} 151 152bool TranslateInfoBarDelegate::IsSiteBlacklisted() { 153 std::string host = GetPageHost(); 154 return !host.empty() && prefs_.IsSiteBlacklisted(host); 155} 156 157void TranslateInfoBarDelegate::ToggleSiteBlacklist() { 158 std::string host = GetPageHost(); 159 if (host.empty()) 160 return; 161 162 if (prefs_.IsSiteBlacklisted(host)) { 163 prefs_.RemoveSiteFromBlacklist(host); 164 } else { 165 prefs_.BlacklistSite(host); 166 tab_contents_->RemoveInfoBar(this); 167 } 168} 169 170bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() { 171 return prefs_.IsLanguagePairWhitelisted(GetOriginalLanguageCode(), 172 GetTargetLanguageCode()); 173} 174 175void TranslateInfoBarDelegate::ToggleAlwaysTranslate() { 176 const std::string& original_lang = GetOriginalLanguageCode(); 177 const std::string& target_lang = GetTargetLanguageCode(); 178 if (prefs_.IsLanguagePairWhitelisted(original_lang, target_lang)) 179 prefs_.RemoveLanguagePairFromWhitelist(original_lang, target_lang); 180 else 181 prefs_.WhitelistLanguagePair(original_lang, target_lang); 182} 183 184void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() { 185 const std::string& original_lang = GetOriginalLanguageCode(); 186 const std::string& target_lang = GetTargetLanguageCode(); 187 DCHECK(!prefs_.IsLanguagePairWhitelisted(original_lang, target_lang)); 188 prefs_.WhitelistLanguagePair(original_lang, target_lang); 189 Translate(); 190} 191 192void TranslateInfoBarDelegate::NeverTranslatePageLanguage() { 193 std::string original_lang = GetOriginalLanguageCode(); 194 DCHECK(!prefs_.IsLanguageBlacklisted(original_lang)); 195 prefs_.BlacklistLanguage(original_lang); 196 tab_contents_->RemoveInfoBar(this); 197} 198 199string16 TranslateInfoBarDelegate::GetMessageInfoBarText() { 200 if (type_ == TRANSLATING) { 201 return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO, 202 GetLanguageDisplayableNameAt(target_language_index_)); 203 } 204 205 DCHECK_EQ(TRANSLATION_ERROR, type_); 206 switch (error_) { 207 case TranslateErrors::NETWORK: 208 return l10n_util::GetStringUTF16( 209 IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT); 210 case TranslateErrors::INITIALIZATION_ERROR: 211 case TranslateErrors::TRANSLATION_ERROR: 212 return l10n_util::GetStringUTF16( 213 IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE); 214 case TranslateErrors::UNKNOWN_LANGUAGE: 215 return l10n_util::GetStringUTF16( 216 IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE); 217 case TranslateErrors::UNSUPPORTED_LANGUAGE: 218 return l10n_util::GetStringFUTF16( 219 IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE, 220 GetLanguageDisplayableNameAt(target_language_index_)); 221 case TranslateErrors::IDENTICAL_LANGUAGES: 222 return l10n_util::GetStringFUTF16( 223 IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE, 224 GetLanguageDisplayableNameAt(target_language_index_)); 225 default: 226 NOTREACHED(); 227 return string16(); 228 } 229} 230 231string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() { 232 if (type_ != TRANSLATION_ERROR) { 233 DCHECK_EQ(TRANSLATING, type_); 234 } else if ((error_ != TranslateErrors::IDENTICAL_LANGUAGES) && 235 (error_ != TranslateErrors::UNKNOWN_LANGUAGE)) { 236 return l10n_util::GetStringUTF16( 237 (error_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ? 238 IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY); 239 } 240 return string16(); 241} 242 243void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() { 244 DCHECK_EQ(TRANSLATION_ERROR, type_); 245 if (error_ == TranslateErrors::UNSUPPORTED_LANGUAGE) { 246 RevertTranslation(); 247 return; 248 } 249 // This is the "Try again..." case. 250 TranslateManager::GetInstance()->TranslatePage(tab_contents_, 251 GetOriginalLanguageCode(), GetTargetLanguageCode()); 252} 253 254bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() { 255 return !GetMessageInfoBarButtonText().empty(); 256} 257 258bool TranslateInfoBarDelegate::ShouldShowNeverTranslateButton() { 259 DCHECK_EQ(BEFORE_TRANSLATE, type_); 260 return !tab_contents()->profile()->IsOffTheRecord() && 261 (prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3); 262} 263 264bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateButton() { 265 DCHECK_EQ(BEFORE_TRANSLATE, type_); 266 return !tab_contents()->profile()->IsOffTheRecord() && 267 (prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3); 268} 269 270void TranslateInfoBarDelegate::UpdateBackgroundAnimation( 271 TranslateInfoBarDelegate* previous_infobar) { 272 if (!previous_infobar || previous_infobar->IsError() == IsError()) 273 background_animation_ = NONE; 274 else 275 background_animation_ = IsError() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL; 276} 277 278// static 279string16 TranslateInfoBarDelegate::GetLanguageDisplayableName( 280 const std::string& language_code) { 281 return l10n_util::GetDisplayNameForLocale( 282 language_code, g_browser_process->GetApplicationLocale(), true); 283} 284 285// static 286void TranslateInfoBarDelegate::GetAfterTranslateStrings( 287 std::vector<string16>* strings, bool* swap_languages) { 288 DCHECK(strings); 289 DCHECK(swap_languages); 290 291 std::vector<size_t> offsets; 292 string16 text = 293 l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, 294 string16(), string16(), &offsets); 295 DCHECK_EQ(2U, offsets.size()); 296 297 *swap_languages = (offsets[0] > offsets[1]); 298 if (*swap_languages) 299 std::swap(offsets[0], offsets[1]); 300 301 strings->push_back(text.substr(0, offsets[0])); 302 strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0])); 303 strings->push_back(text.substr(offsets[1])); 304} 305 306TranslateInfoBarDelegate::TranslateInfoBarDelegate( 307 Type type, 308 TranslateErrors::Type error, 309 TabContents* tab_contents, 310 const std::string& original_language, 311 const std::string& target_language) 312 : InfoBarDelegate(tab_contents), 313 type_(type), 314 background_animation_(NONE), 315 tab_contents_(tab_contents), 316 original_language_index_(kNoIndex), 317 initial_original_language_index_(kNoIndex), 318 target_language_index_(kNoIndex), 319 error_(error), 320 infobar_view_(NULL), 321 prefs_(tab_contents_->profile()->GetPrefs()) { 322 DCHECK_NE((type_ == TRANSLATION_ERROR), (error == TranslateErrors::NONE)); 323 324 std::vector<std::string> language_codes; 325 TranslateManager::GetSupportedLanguages(&language_codes); 326 327 languages_.reserve(language_codes.size()); 328 for (std::vector<std::string>::const_iterator iter = language_codes.begin(); 329 iter != language_codes.end(); ++iter) { 330 std::string language_code = *iter; 331 332 string16 language_name = GetLanguageDisplayableName(language_code); 333 // Insert the language in languages_ in alphabetical order. 334 std::vector<LanguageNamePair>::iterator iter2; 335 for (iter2 = languages_.begin(); iter2 != languages_.end(); ++iter2) { 336 if (language_name.compare(iter2->second) < 0) 337 break; 338 } 339 languages_.insert(iter2, LanguageNamePair(language_code, language_name)); 340 } 341 for (std::vector<LanguageNamePair>::const_iterator iter = languages_.begin(); 342 iter != languages_.end(); ++iter) { 343 std::string language_code = iter->first; 344 if (language_code == original_language) { 345 original_language_index_ = iter - languages_.begin(); 346 initial_original_language_index_ = original_language_index_; 347 } 348 if (language_code == target_language) 349 target_language_index_ = iter - languages_.begin(); 350 } 351} 352 353void TranslateInfoBarDelegate::InfoBarDismissed() { 354 if (type_ != BEFORE_TRANSLATE) 355 return; 356 357 // The user closed the infobar without clicking the translate button. 358 TranslationDeclined(); 359 UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslateCloseInfobar", 1); 360} 361 362void TranslateInfoBarDelegate::InfoBarClosed() { 363 delete this; 364} 365 366SkBitmap* TranslateInfoBarDelegate::GetIcon() const { 367 return ResourceBundle::GetSharedInstance().GetBitmapNamed( 368 IDR_INFOBAR_TRANSLATE); 369} 370 371InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const { 372 return PAGE_ACTION_TYPE; 373} 374 375TranslateInfoBarDelegate* 376 TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() { 377 return this; 378} 379 380std::string TranslateInfoBarDelegate::GetPageHost() { 381 NavigationEntry* entry = tab_contents_->controller().GetActiveEntry(); 382 return entry ? entry->url().HostNoBrackets() : std::string(); 383} 384