1 // Copyright 2014 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.
5 #include "components/translate/core/browser/translate_infobar_delegate.h"
9 #include "base/i18n/string_compare.h"
10 #include "base/metrics/histogram.h"
11 #include "components/infobars/core/infobar.h"
12 #include "components/infobars/core/infobar_manager.h"
13 #include "components/translate/core/browser/language_state.h"
14 #include "components/translate/core/browser/translate_accept_languages.h"
15 #include "components/translate/core/browser/translate_client.h"
16 #include "components/translate/core/browser/translate_download_manager.h"
17 #include "components/translate/core/browser/translate_driver.h"
18 #include "components/translate/core/browser/translate_manager.h"
19 #include "components/translate/core/common/translate_constants.h"
20 #include "grit/components_strings.h"
21 #include "ui/base/l10n/l10n_util.h"
27 // Counts used to decide whether infobars should be shown.
28 // Android and iOS implementations do not offer a drop down (for space reasons),
29 // so we are more aggressive about showing the shortcut to never translate.
30 // The "Always Translate" option is always shown on iOS and Android.
31 #if defined(OS_ANDROID)
32 const int kAlwaysTranslateMinCount
= 1;
33 const int kNeverTranslateMinCount
= 1;
35 // The iOS implementation, like the Android implementation, shows the "Never
36 // translate" infobar after two denials. There is an offset of one because on
37 // Android the last event is not counted.
38 const int kAlwaysTranslateMinCount
= 1;
39 const int kNeverTranslateMinCount
= 2;
41 const int kAlwaysTranslateMinCount
= 3;
42 const int kNeverTranslateMinCount
= 3;
47 const size_t TranslateInfoBarDelegate::kNoIndex
= TranslateUIDelegate::kNoIndex
;
49 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
53 void TranslateInfoBarDelegate::Create(
54 bool replace_existing_infobar
,
55 const base::WeakPtr
<TranslateManager
>& translate_manager
,
56 infobars::InfoBarManager
* infobar_manager
,
57 bool is_off_the_record
,
58 translate::TranslateStep step
,
59 const std::string
& original_language
,
60 const std::string
& target_language
,
61 TranslateErrors::Type error_type
,
62 bool triggered_from_menu
) {
63 DCHECK(translate_manager
);
64 DCHECK(infobar_manager
);
66 // Check preconditions.
67 if (step
!= translate::TRANSLATE_STEP_TRANSLATE_ERROR
) {
68 DCHECK(TranslateDownloadManager::IsSupportedLanguage(target_language
));
69 if (!TranslateDownloadManager::IsSupportedLanguage(original_language
)) {
70 // The original language can only be "unknown" for the "translating"
71 // infobar, which is the case when the user started a translation from the
73 DCHECK(step
== translate::TRANSLATE_STEP_TRANSLATING
||
74 step
== translate::TRANSLATE_STEP_AFTER_TRANSLATE
);
75 DCHECK_EQ(translate::kUnknownLanguageCode
, original_language
);
79 // Do not create the after translate infobar if we are auto translating.
80 TranslateClient
* translate_client
= translate_manager
->translate_client();
81 if (((step
== translate::TRANSLATE_STEP_AFTER_TRANSLATE
) ||
82 (step
== translate::TRANSLATE_STEP_TRANSLATING
)) &&
83 translate_manager
->GetLanguageState().InTranslateNavigation()) {
87 // Find any existing translate infobar delegate.
88 infobars::InfoBar
* old_infobar
= NULL
;
89 TranslateInfoBarDelegate
* old_delegate
= NULL
;
90 for (size_t i
= 0; i
< infobar_manager
->infobar_count(); ++i
) {
91 old_infobar
= infobar_manager
->infobar_at(i
);
92 old_delegate
= old_infobar
->delegate()->AsTranslateInfoBarDelegate();
94 if (!replace_existing_infobar
)
100 // Add the new delegate.
101 scoped_ptr
<infobars::InfoBar
> infobar(translate_client
->CreateInfoBar(
102 scoped_ptr
<TranslateInfoBarDelegate
>(new TranslateInfoBarDelegate(
103 translate_manager
, is_off_the_record
, step
, old_delegate
,
104 original_language
, target_language
, error_type
,
105 triggered_from_menu
))));
107 infobar_manager
->ReplaceInfoBar(old_infobar
, infobar
.Pass());
109 infobar_manager
->AddInfoBar(infobar
.Pass());
112 void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
113 size_t language_index
) {
114 ui_delegate_
.UpdateOriginalLanguageIndex(language_index
);
117 void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
118 size_t language_index
) {
119 ui_delegate_
.UpdateTargetLanguageIndex(language_index
);
122 void TranslateInfoBarDelegate::Translate() {
123 ui_delegate_
.Translate();
126 void TranslateInfoBarDelegate::RevertTranslation() {
127 ui_delegate_
.RevertTranslation();
128 infobar()->RemoveSelf();
131 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
132 if (translate_manager_
)
133 translate_manager_
->ReportLanguageDetectionError();
136 void TranslateInfoBarDelegate::TranslationDeclined() {
137 ui_delegate_
.TranslationDeclined(false);
140 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
141 TranslateClient
* client
= translate_manager_
->translate_client();
142 scoped_ptr
<TranslatePrefs
> translate_prefs(client
->GetTranslatePrefs());
143 TranslateAcceptLanguages
* accept_languages
=
144 client
->GetTranslateAcceptLanguages();
145 return translate_prefs
->CanTranslateLanguage(accept_languages
,
146 original_language_code());
149 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
150 if (ui_delegate_
.IsLanguageBlocked()) {
151 ui_delegate_
.SetLanguageBlocked(false);
153 ui_delegate_
.SetLanguageBlocked(true);
154 infobar()->RemoveSelf();
158 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
159 return ui_delegate_
.IsSiteBlacklisted();
162 void TranslateInfoBarDelegate::ToggleSiteBlacklist() {
163 if (ui_delegate_
.IsSiteBlacklisted()) {
164 ui_delegate_
.SetSiteBlacklist(false);
166 ui_delegate_
.SetSiteBlacklist(true);
167 infobar()->RemoveSelf();
171 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
172 return ui_delegate_
.ShouldAlwaysTranslate();
175 void TranslateInfoBarDelegate::ToggleAlwaysTranslate() {
176 ui_delegate_
.SetAlwaysTranslate(!ui_delegate_
.ShouldAlwaysTranslate());
179 void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() {
180 DCHECK(!ui_delegate_
.ShouldAlwaysTranslate());
181 ui_delegate_
.SetAlwaysTranslate(true);
185 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
186 DCHECK(!ui_delegate_
.IsLanguageBlocked());
187 ui_delegate_
.SetLanguageBlocked(true);
188 infobar()->RemoveSelf();
191 base::string16
TranslateInfoBarDelegate::GetMessageInfoBarText() {
192 if (step_
== translate::TRANSLATE_STEP_TRANSLATING
) {
193 base::string16 target_language_name
=
194 language_name_at(target_language_index());
195 return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO
,
196 target_language_name
);
199 DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR
, step_
);
200 UMA_HISTOGRAM_ENUMERATION("Translate.ShowErrorInfobar",
202 TranslateErrors::TRANSLATE_ERROR_MAX
);
203 ui_delegate_
.OnErrorShown(error_type_
);
204 switch (error_type_
) {
205 case TranslateErrors::NETWORK
:
206 return l10n_util::GetStringUTF16(
207 IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT
);
208 case TranslateErrors::INITIALIZATION_ERROR
:
209 case TranslateErrors::TRANSLATION_ERROR
:
210 return l10n_util::GetStringUTF16(
211 IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE
);
212 case TranslateErrors::UNKNOWN_LANGUAGE
:
213 return l10n_util::GetStringUTF16(
214 IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE
);
215 case TranslateErrors::UNSUPPORTED_LANGUAGE
:
216 return l10n_util::GetStringFUTF16(
217 IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE
,
218 language_name_at(target_language_index()));
219 case TranslateErrors::IDENTICAL_LANGUAGES
:
220 return l10n_util::GetStringFUTF16(
221 IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE
,
222 language_name_at(target_language_index()));
225 return base::string16();
229 base::string16
TranslateInfoBarDelegate::GetMessageInfoBarButtonText() {
230 if (step_
!= translate::TRANSLATE_STEP_TRANSLATE_ERROR
) {
231 DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATING
, step_
);
232 } else if ((error_type_
!= TranslateErrors::IDENTICAL_LANGUAGES
) &&
233 (error_type_
!= TranslateErrors::UNKNOWN_LANGUAGE
)) {
234 return l10n_util::GetStringUTF16(
235 (error_type_
== TranslateErrors::UNSUPPORTED_LANGUAGE
) ?
236 IDS_TRANSLATE_INFOBAR_REVERT
: IDS_TRANSLATE_INFOBAR_RETRY
);
238 return base::string16();
241 void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
242 DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR
, step_
);
243 if (error_type_
== TranslateErrors::UNSUPPORTED_LANGUAGE
) {
247 // This is the "Try again..." case.
248 DCHECK(translate_manager_
);
249 translate_manager_
->TranslatePage(
250 original_language_code(), target_language_code(), false);
253 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
254 return !GetMessageInfoBarButtonText().empty();
257 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateShortcut() {
258 DCHECK_EQ(translate::TRANSLATE_STEP_BEFORE_TRANSLATE
, step_
);
259 return !is_off_the_record_
&&
260 (prefs_
->GetTranslationDeniedCount(original_language_code()) >=
261 kNeverTranslateMinCount
);
264 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() {
265 DCHECK_EQ(translate::TRANSLATE_STEP_BEFORE_TRANSLATE
, step_
);
266 return !is_off_the_record_
&&
267 (prefs_
->GetTranslationAcceptedCount(original_language_code()) >=
268 kAlwaysTranslateMinCount
);
272 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
273 std::vector
<base::string16
>* strings
,
274 bool* swap_languages
,
275 bool autodetermined_source_language
) {
278 if (autodetermined_source_language
) {
280 base::string16 text
= l10n_util::GetStringFUTF16(
281 IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE
,
285 strings
->push_back(text
.substr(0, offset
));
286 strings
->push_back(text
.substr(offset
));
289 DCHECK(swap_languages
);
291 std::vector
<size_t> offsets
;
292 base::string16 text
= l10n_util::GetStringFUTF16(
293 IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE
, base::string16(), base::string16(),
295 DCHECK_EQ(2U, offsets
.size());
297 *swap_languages
= (offsets
[0] > offsets
[1]);
299 std::swap(offsets
[0], offsets
[1]);
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]));
306 TranslateDriver
* TranslateInfoBarDelegate::GetTranslateDriver() {
307 if (!translate_manager_
)
310 return translate_manager_
->translate_client()->GetTranslateDriver();
313 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
314 const base::WeakPtr
<TranslateManager
>& translate_manager
,
315 bool is_off_the_record
,
316 translate::TranslateStep step
,
317 TranslateInfoBarDelegate
* old_delegate
,
318 const std::string
& original_language
,
319 const std::string
& target_language
,
320 TranslateErrors::Type error_type
,
321 bool triggered_from_menu
)
322 : infobars::InfoBarDelegate(),
323 is_off_the_record_(is_off_the_record
),
325 background_animation_(NONE
),
326 ui_delegate_(translate_manager
, original_language
, target_language
),
327 translate_manager_(translate_manager
),
328 error_type_(error_type
),
329 prefs_(translate_manager
->translate_client()->GetTranslatePrefs()),
330 triggered_from_menu_(triggered_from_menu
) {
331 DCHECK_NE((step_
== translate::TRANSLATE_STEP_TRANSLATE_ERROR
),
332 (error_type_
== TranslateErrors::NONE
));
333 DCHECK(translate_manager_
);
335 if (old_delegate
&& (old_delegate
->is_error() != is_error()))
336 background_animation_
= is_error() ? NORMAL_TO_ERROR
: ERROR_TO_NORMAL
;
339 void TranslateInfoBarDelegate::InfoBarDismissed() {
340 if (step_
!= translate::TRANSLATE_STEP_BEFORE_TRANSLATE
)
343 // The user closed the infobar without clicking the translate button.
344 TranslationDeclined();
345 UMA_HISTOGRAM_BOOLEAN("Translate.DeclineTranslateCloseInfobar", true);
348 int TranslateInfoBarDelegate::GetIconID() const {
349 return translate_manager_
->translate_client()->GetInfobarIconID();
352 infobars::InfoBarDelegate::Type
TranslateInfoBarDelegate::GetInfoBarType()
354 return PAGE_ACTION_TYPE
;
357 bool TranslateInfoBarDelegate::ShouldExpire(
358 const NavigationDetails
& details
) const {
359 // Note: we allow closing this infobar even if the main frame navigation
360 // was programmatic and not initiated by the user - crbug.com/70261 .
361 if (!details
.is_navigation_to_different_page
&& !details
.is_main_frame
)
364 return infobars::InfoBarDelegate::ShouldExpireInternal(details
);
367 TranslateInfoBarDelegate
*
368 TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {
372 } // namespace translate