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 24 const size_t TranslateInfoBarDelegate::kNoIndex = static_cast<size_t>(-1); 25 26 // static 27 TranslateInfoBarDelegate* 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 49 TranslateInfoBarDelegate* 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 58 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() { 59 } 60 61 std::string TranslateInfoBarDelegate::GetLanguageCodeAt(size_t index) const { 62 DCHECK_LT(index, GetLanguageCount()); 63 return languages_[index].first; 64 } 65 66 string16 TranslateInfoBarDelegate::GetLanguageDisplayableNameAt( 67 size_t index) const { 68 DCHECK_LT(index, GetLanguageCount()); 69 return languages_[index].second; 70 } 71 72 std::string TranslateInfoBarDelegate::GetOriginalLanguageCode() const { 73 return (original_language_index() == kNoIndex) ? 74 chrome::kUnknownLanguageCode : 75 GetLanguageCodeAt(original_language_index()); 76 } 77 78 std::string TranslateInfoBarDelegate::GetTargetLanguageCode() const { 79 return GetLanguageCodeAt(target_language_index()); 80 } 81 82 void 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 91 void 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 100 void 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 112 void TranslateInfoBarDelegate::RevertTranslation() { 113 TranslateManager::GetInstance()->RevertTranslation(tab_contents_); 114 tab_contents_->RemoveInfoBar(this); 115 } 116 117 void TranslateInfoBarDelegate::ReportLanguageDetectionError() { 118 TranslateManager::GetInstance()->ReportLanguageDetectionError(tab_contents_); 119 } 120 121 void 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 138 bool TranslateInfoBarDelegate::IsLanguageBlacklisted() { 139 return prefs_.IsLanguageBlacklisted(GetOriginalLanguageCode()); 140 } 141 142 void 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 152 bool TranslateInfoBarDelegate::IsSiteBlacklisted() { 153 std::string host = GetPageHost(); 154 return !host.empty() && prefs_.IsSiteBlacklisted(host); 155 } 156 157 void 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 170 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() { 171 return prefs_.IsLanguagePairWhitelisted(GetOriginalLanguageCode(), 172 GetTargetLanguageCode()); 173 } 174 175 void 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 184 void 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 192 void 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 199 string16 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 231 string16 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 243 void 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 254 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() { 255 return !GetMessageInfoBarButtonText().empty(); 256 } 257 258 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateButton() { 259 DCHECK_EQ(BEFORE_TRANSLATE, type_); 260 return !tab_contents()->profile()->IsOffTheRecord() && 261 (prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3); 262 } 263 264 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateButton() { 265 DCHECK_EQ(BEFORE_TRANSLATE, type_); 266 return !tab_contents()->profile()->IsOffTheRecord() && 267 (prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3); 268 } 269 270 void 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 279 string16 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 286 void 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 306 TranslateInfoBarDelegate::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 353 void 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 362 void TranslateInfoBarDelegate::InfoBarClosed() { 363 delete this; 364 } 365 366 SkBitmap* TranslateInfoBarDelegate::GetIcon() const { 367 return ResourceBundle::GetSharedInstance().GetBitmapNamed( 368 IDR_INFOBAR_TRANSLATE); 369 } 370 371 InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const { 372 return PAGE_ACTION_TYPE; 373 } 374 375 TranslateInfoBarDelegate* 376 TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() { 377 return this; 378 } 379 380 std::string TranslateInfoBarDelegate::GetPageHost() { 381 NavigationEntry* entry = tab_contents_->controller().GetActiveEntry(); 382 return entry ? entry->url().HostNoBrackets() : std::string(); 383 } 384