Home | History | Annotate | Download | only in translate
      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