• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
CreateDelegate(Type type,TabContents * tab_contents,const std::string & original_language,const std::string & target_language)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 
CreateErrorDelegate(TranslateErrors::Type error,TabContents * tab_contents,const std::string & original_language,const std::string & target_language)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 
~TranslateInfoBarDelegate()58 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
59 }
60 
GetLanguageCodeAt(size_t index) const61 std::string TranslateInfoBarDelegate::GetLanguageCodeAt(size_t index) const {
62   DCHECK_LT(index, GetLanguageCount());
63   return languages_[index].first;
64 }
65 
GetLanguageDisplayableNameAt(size_t index) const66 string16 TranslateInfoBarDelegate::GetLanguageDisplayableNameAt(
67     size_t index) const {
68   DCHECK_LT(index, GetLanguageCount());
69   return languages_[index].second;
70 }
71 
GetOriginalLanguageCode() const72 std::string TranslateInfoBarDelegate::GetOriginalLanguageCode() const {
73   return (original_language_index() == kNoIndex) ?
74       chrome::kUnknownLanguageCode :
75       GetLanguageCodeAt(original_language_index());
76 }
77 
GetTargetLanguageCode() const78 std::string TranslateInfoBarDelegate::GetTargetLanguageCode() const {
79   return GetLanguageCodeAt(target_language_index());
80 }
81 
SetOriginalLanguage(size_t language_index)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 
SetTargetLanguage(size_t language_index)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 
Translate()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 
RevertTranslation()112 void TranslateInfoBarDelegate::RevertTranslation() {
113   TranslateManager::GetInstance()->RevertTranslation(tab_contents_);
114   tab_contents_->RemoveInfoBar(this);
115 }
116 
ReportLanguageDetectionError()117 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
118   TranslateManager::GetInstance()->ReportLanguageDetectionError(tab_contents_);
119 }
120 
TranslationDeclined()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 
IsLanguageBlacklisted()138 bool TranslateInfoBarDelegate::IsLanguageBlacklisted() {
139   return prefs_.IsLanguageBlacklisted(GetOriginalLanguageCode());
140 }
141 
ToggleLanguageBlacklist()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 
IsSiteBlacklisted()152 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
153   std::string host = GetPageHost();
154   return !host.empty() && prefs_.IsSiteBlacklisted(host);
155 }
156 
ToggleSiteBlacklist()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 
ShouldAlwaysTranslate()170 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
171   return prefs_.IsLanguagePairWhitelisted(GetOriginalLanguageCode(),
172                                           GetTargetLanguageCode());
173 }
174 
ToggleAlwaysTranslate()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 
AlwaysTranslatePageLanguage()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 
NeverTranslatePageLanguage()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 
GetMessageInfoBarText()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 
GetMessageInfoBarButtonText()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 
MessageInfoBarButtonPressed()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 
ShouldShowMessageInfoBarButton()254 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
255   return !GetMessageInfoBarButtonText().empty();
256 }
257 
ShouldShowNeverTranslateButton()258 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateButton() {
259   DCHECK_EQ(BEFORE_TRANSLATE, type_);
260   return !tab_contents()->profile()->IsOffTheRecord() &&
261       (prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3);
262 }
263 
ShouldShowAlwaysTranslateButton()264 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateButton() {
265   DCHECK_EQ(BEFORE_TRANSLATE, type_);
266   return !tab_contents()->profile()->IsOffTheRecord() &&
267       (prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3);
268 }
269 
UpdateBackgroundAnimation(TranslateInfoBarDelegate * previous_infobar)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
GetLanguageDisplayableName(const std::string & language_code)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
GetAfterTranslateStrings(std::vector<string16> * strings,bool * swap_languages)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 
TranslateInfoBarDelegate(Type type,TranslateErrors::Type error,TabContents * tab_contents,const std::string & original_language,const std::string & target_language)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 
InfoBarDismissed()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 
InfoBarClosed()362 void TranslateInfoBarDelegate::InfoBarClosed() {
363   delete this;
364 }
365 
GetIcon() const366 SkBitmap* TranslateInfoBarDelegate::GetIcon() const {
367   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
368       IDR_INFOBAR_TRANSLATE);
369 }
370 
GetInfoBarType() const371 InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const {
372   return PAGE_ACTION_TYPE;
373 }
374 
375 TranslateInfoBarDelegate*
AsTranslateInfoBarDelegate()376     TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {
377   return this;
378 }
379 
GetPageHost()380 std::string TranslateInfoBarDelegate::GetPageHost() {
381   NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
382   return entry ? entry->url().HostNoBrackets() : std::string();
383 }
384