Home | History | Annotate | Download | only in translate
      1 // Copyright (c) 2012 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/i18n/string_compare.h"
     10 #include "base/metrics/histogram.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "chrome/browser/browser_process.h"
     13 #include "chrome/browser/infobars/infobar.h"
     14 #include "chrome/browser/infobars/infobar_service.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/translate/translate_accept_languages.h"
     17 #include "chrome/browser/translate/translate_manager.h"
     18 #include "chrome/browser/translate/translate_tab_helper.h"
     19 #include "components/translate/common/translate_constants.h"
     20 #include "content/public/browser/navigation_details.h"
     21 #include "content/public/browser/navigation_entry.h"
     22 #include "content/public/browser/web_contents.h"
     23 #include "grit/generated_resources.h"
     24 #include "grit/theme_resources.h"
     25 #include "third_party/icu/source/i18n/unicode/coll.h"
     26 #include "ui/base/l10n/l10n_util.h"
     27 
     28 
     29 const size_t TranslateInfoBarDelegate::kNoIndex = TranslateUIDelegate::NO_INDEX;
     30 
     31 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
     32 }
     33 
     34 // static
     35 void TranslateInfoBarDelegate::Create(
     36     bool replace_existing_infobar,
     37     content::WebContents* web_contents,
     38     Type infobar_type,
     39     const std::string& original_language,
     40     const std::string& target_language,
     41     TranslateErrors::Type error_type,
     42     PrefService* prefs,
     43     const ShortcutConfiguration& shortcut_config) {
     44   // Check preconditions.
     45   if (infobar_type != TRANSLATION_ERROR) {
     46     DCHECK(TranslateManager::IsSupportedLanguage(target_language));
     47     if (!TranslateManager::IsSupportedLanguage(original_language)) {
     48       // The original language can only be "unknown" for the "translating"
     49       // infobar, which is the case when the user started a translation from the
     50       // context menu.
     51       DCHECK(infobar_type == TRANSLATING || infobar_type == AFTER_TRANSLATE);
     52       DCHECK_EQ(translate::kUnknownLanguageCode, original_language);
     53     }
     54   }
     55 
     56   // Do not create the after translate infobar if we are auto translating.
     57   if ((infobar_type == TranslateInfoBarDelegate::AFTER_TRANSLATE) ||
     58       (infobar_type == TranslateInfoBarDelegate::TRANSLATING)) {
     59     TranslateTabHelper* translate_tab_helper =
     60         TranslateTabHelper::FromWebContents(web_contents);
     61     if (!translate_tab_helper ||
     62         translate_tab_helper->language_state().InTranslateNavigation())
     63       return;
     64   }
     65 
     66   // Find any existing translate infobar delegate.
     67   InfoBar* old_infobar = NULL;
     68   InfoBarService* infobar_service =
     69       InfoBarService::FromWebContents(web_contents);
     70   TranslateInfoBarDelegate* old_delegate = NULL;
     71   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
     72     old_infobar = infobar_service->infobar_at(i);
     73     old_delegate = old_infobar->delegate()->AsTranslateInfoBarDelegate();
     74     if (old_delegate) {
     75       if (!replace_existing_infobar)
     76         return;
     77       break;
     78     }
     79   }
     80 
     81   // Add the new delegate.
     82   scoped_ptr<InfoBar> infobar(CreateInfoBar(
     83       scoped_ptr<TranslateInfoBarDelegate>(new TranslateInfoBarDelegate(
     84           web_contents, infobar_type, old_delegate, original_language,
     85           target_language, error_type, prefs, shortcut_config))));
     86   if (old_delegate)
     87     infobar_service->ReplaceInfoBar(old_infobar, infobar.Pass());
     88   else
     89     infobar_service->AddInfoBar(infobar.Pass());
     90 }
     91 
     92 
     93 void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
     94     size_t language_index) {
     95   ui_delegate_.UpdateOriginalLanguageIndex(language_index);
     96 }
     97 
     98 void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
     99     size_t language_index) {
    100   ui_delegate_.UpdateTargetLanguageIndex(language_index);
    101 }
    102 
    103 void TranslateInfoBarDelegate::Translate() {
    104   ui_delegate_.Translate();
    105 }
    106 
    107 void TranslateInfoBarDelegate::RevertTranslation() {
    108   ui_delegate_.RevertTranslation();
    109   infobar()->RemoveSelf();
    110 }
    111 
    112 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
    113   TranslateManager::GetInstance()->ReportLanguageDetectionError(
    114       web_contents());
    115 }
    116 
    117 void TranslateInfoBarDelegate::TranslationDeclined() {
    118   ui_delegate_.TranslationDeclined(false);
    119 }
    120 
    121 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
    122   Profile* profile =
    123       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
    124   Profile* original_profile = profile->GetOriginalProfile();
    125   return TranslatePrefs::CanTranslateLanguage(original_profile,
    126                                               original_language_code());
    127 }
    128 
    129 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
    130   if (ui_delegate_.IsLanguageBlocked()) {
    131     ui_delegate_.SetLanguageBlocked(false);
    132   } else {
    133     ui_delegate_.SetLanguageBlocked(true);
    134     infobar()->RemoveSelf();
    135   }
    136 }
    137 
    138 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
    139   return ui_delegate_.IsSiteBlacklisted();
    140 }
    141 
    142 void TranslateInfoBarDelegate::ToggleSiteBlacklist() {
    143   if (ui_delegate_.IsSiteBlacklisted()) {
    144     ui_delegate_.SetSiteBlacklist(false);
    145   } else {
    146     ui_delegate_.SetSiteBlacklist(true);
    147     infobar()->RemoveSelf();
    148   }
    149 }
    150 
    151 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
    152   return ui_delegate_.ShouldAlwaysTranslate();
    153 }
    154 
    155 void TranslateInfoBarDelegate::ToggleAlwaysTranslate() {
    156   ui_delegate_.SetAlwaysTranslate(!ui_delegate_.ShouldAlwaysTranslate());
    157 }
    158 
    159 void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() {
    160   DCHECK(!ui_delegate_.ShouldAlwaysTranslate());
    161   ui_delegate_.SetAlwaysTranslate(true);
    162   Translate();
    163 }
    164 
    165 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
    166   DCHECK(!ui_delegate_.IsLanguageBlocked());
    167   ui_delegate_.SetLanguageBlocked(true);
    168     infobar()->RemoveSelf();
    169 }
    170 
    171 base::string16 TranslateInfoBarDelegate::GetMessageInfoBarText() {
    172   if (infobar_type_ == TRANSLATING) {
    173     base::string16 target_language_name =
    174         language_name_at(target_language_index());
    175     return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
    176                                       target_language_name);
    177   }
    178 
    179   DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
    180   UMA_HISTOGRAM_ENUMERATION("Translate.ShowErrorInfobar",
    181                             error_type_,
    182                             TranslateErrors::TRANSLATE_ERROR_MAX);
    183   ui_delegate_.OnErrorShown(error_type_);
    184   switch (error_type_) {
    185     case TranslateErrors::NETWORK:
    186       return l10n_util::GetStringUTF16(
    187           IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT);
    188     case TranslateErrors::INITIALIZATION_ERROR:
    189     case TranslateErrors::TRANSLATION_ERROR:
    190       return l10n_util::GetStringUTF16(
    191           IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE);
    192     case TranslateErrors::UNKNOWN_LANGUAGE:
    193       return l10n_util::GetStringUTF16(
    194           IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE);
    195     case TranslateErrors::UNSUPPORTED_LANGUAGE:
    196       return l10n_util::GetStringFUTF16(
    197           IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE,
    198           language_name_at(target_language_index()));
    199     case TranslateErrors::IDENTICAL_LANGUAGES:
    200       return l10n_util::GetStringFUTF16(
    201           IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
    202           language_name_at(target_language_index()));
    203     default:
    204       NOTREACHED();
    205       return base::string16();
    206   }
    207 }
    208 
    209 base::string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() {
    210   if (infobar_type_ != TRANSLATION_ERROR) {
    211     DCHECK_EQ(TRANSLATING, infobar_type_);
    212   } else if ((error_type_ != TranslateErrors::IDENTICAL_LANGUAGES) &&
    213              (error_type_ != TranslateErrors::UNKNOWN_LANGUAGE)) {
    214     return l10n_util::GetStringUTF16(
    215         (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ?
    216         IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY);
    217   }
    218   return base::string16();
    219 }
    220 
    221 void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
    222   DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
    223   if (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) {
    224     RevertTranslation();
    225     return;
    226   }
    227   // This is the "Try again..." case.
    228   TranslateManager::GetInstance()->TranslatePage(
    229       web_contents(), original_language_code(), target_language_code());
    230 }
    231 
    232 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
    233   return !GetMessageInfoBarButtonText().empty();
    234 }
    235 
    236 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateShortcut() {
    237   DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
    238   return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
    239       (prefs_.GetTranslationDeniedCount(original_language_code()) >=
    240           shortcut_config_.never_translate_min_count);
    241 }
    242 
    243 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() {
    244   DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
    245   return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
    246       (prefs_.GetTranslationAcceptedCount(original_language_code()) >=
    247           shortcut_config_.always_translate_min_count);
    248 }
    249 
    250 // static
    251 base::string16 TranslateInfoBarDelegate::GetLanguageDisplayableName(
    252     const std::string& language_code) {
    253   return l10n_util::GetDisplayNameForLocale(
    254       language_code, g_browser_process->GetApplicationLocale(), true);
    255 }
    256 
    257 // static
    258 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
    259     std::vector<base::string16>* strings,
    260     bool* swap_languages,
    261     bool autodetermined_source_language) {
    262   DCHECK(strings);
    263 
    264   if (autodetermined_source_language) {
    265     size_t offset;
    266     base::string16 text = l10n_util::GetStringFUTF16(
    267         IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE,
    268         base::string16(),
    269         &offset);
    270 
    271     strings->push_back(text.substr(0, offset));
    272     strings->push_back(text.substr(offset));
    273     return;
    274   }
    275   DCHECK(swap_languages);
    276 
    277   std::vector<size_t> offsets;
    278   base::string16 text = l10n_util::GetStringFUTF16(
    279       IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, base::string16(), base::string16(),
    280       &offsets);
    281   DCHECK_EQ(2U, offsets.size());
    282 
    283   *swap_languages = (offsets[0] > offsets[1]);
    284   if (*swap_languages)
    285     std::swap(offsets[0], offsets[1]);
    286 
    287   strings->push_back(text.substr(0, offsets[0]));
    288   strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0]));
    289   strings->push_back(text.substr(offsets[1]));
    290 }
    291 
    292 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
    293     content::WebContents* web_contents,
    294     Type infobar_type,
    295     TranslateInfoBarDelegate* old_delegate,
    296     const std::string& original_language,
    297     const std::string& target_language,
    298     TranslateErrors::Type error_type,
    299     PrefService* prefs,
    300     ShortcutConfiguration shortcut_config)
    301     : InfoBarDelegate(),
    302       infobar_type_(infobar_type),
    303       background_animation_(NONE),
    304       ui_delegate_(web_contents, original_language, target_language),
    305       error_type_(error_type),
    306       prefs_(prefs),
    307       shortcut_config_(shortcut_config) {
    308   DCHECK_NE((infobar_type_ == TRANSLATION_ERROR),
    309             (error_type_ == TranslateErrors::NONE));
    310 
    311   if (old_delegate && (old_delegate->is_error() != is_error()))
    312     background_animation_ = is_error() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL;
    313 }
    314 
    315 // TranslateInfoBarDelegate::CreateInfoBar() is implemented in platform-specific
    316 // files.
    317 
    318 void TranslateInfoBarDelegate::InfoBarDismissed() {
    319   if (infobar_type_ != BEFORE_TRANSLATE)
    320     return;
    321 
    322   // The user closed the infobar without clicking the translate button.
    323   TranslationDeclined();
    324   UMA_HISTOGRAM_BOOLEAN("Translate.DeclineTranslateCloseInfobar", true);
    325 }
    326 
    327 int TranslateInfoBarDelegate::GetIconID() const {
    328   return IDR_INFOBAR_TRANSLATE;
    329 }
    330 
    331 InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const {
    332   return PAGE_ACTION_TYPE;
    333 }
    334 
    335 bool TranslateInfoBarDelegate::ShouldExpire(
    336     const content::LoadCommittedDetails& details) const {
    337   // Note: we allow closing this infobar even if the main frame navigation
    338   // was programmatic and not initiated by the user - crbug.com/70261 .
    339   if (!details.is_navigation_to_different_page() && !details.is_main_frame)
    340     return false;
    341 
    342   return InfoBarDelegate::ShouldExpireInternal(details);
    343 }
    344 
    345 TranslateInfoBarDelegate*
    346     TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {
    347   return this;
    348 }
    349