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.
5 #include "chrome/browser/translate/translate_infobar_delegate.h"
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/core/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"
29 const size_t TranslateInfoBarDelegate::kNoIndex
= TranslateUIDelegate::NO_INDEX
;
31 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
35 void TranslateInfoBarDelegate::Create(
36 bool replace_existing_infobar
,
37 content::WebContents
* web_contents
,
39 const std::string
& original_language
,
40 const std::string
& target_language
,
41 TranslateErrors::Type error_type
,
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
51 DCHECK(infobar_type
== TRANSLATING
|| infobar_type
== AFTER_TRANSLATE
);
52 DCHECK_EQ(translate::kUnknownLanguageCode
, original_language
);
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())
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();
75 if (!replace_existing_infobar
)
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
))));
87 infobar_service
->ReplaceInfoBar(old_infobar
, infobar
.Pass());
89 infobar_service
->AddInfoBar(infobar
.Pass());
93 void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
94 size_t language_index
) {
95 ui_delegate_
.UpdateOriginalLanguageIndex(language_index
);
98 void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
99 size_t language_index
) {
100 ui_delegate_
.UpdateTargetLanguageIndex(language_index
);
103 void TranslateInfoBarDelegate::Translate() {
104 ui_delegate_
.Translate();
107 void TranslateInfoBarDelegate::RevertTranslation() {
108 ui_delegate_
.RevertTranslation();
109 infobar()->RemoveSelf();
112 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
113 TranslateManager::GetInstance()->ReportLanguageDetectionError(
117 void TranslateInfoBarDelegate::TranslationDeclined() {
118 ui_delegate_
.TranslationDeclined(false);
121 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
123 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
124 Profile
* original_profile
= profile
->GetOriginalProfile();
125 return TranslatePrefs::CanTranslateLanguage(original_profile
,
126 original_language_code());
129 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
130 if (ui_delegate_
.IsLanguageBlocked()) {
131 ui_delegate_
.SetLanguageBlocked(false);
133 ui_delegate_
.SetLanguageBlocked(true);
134 infobar()->RemoveSelf();
138 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
139 return ui_delegate_
.IsSiteBlacklisted();
142 void TranslateInfoBarDelegate::ToggleSiteBlacklist() {
143 if (ui_delegate_
.IsSiteBlacklisted()) {
144 ui_delegate_
.SetSiteBlacklist(false);
146 ui_delegate_
.SetSiteBlacklist(true);
147 infobar()->RemoveSelf();
151 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
152 return ui_delegate_
.ShouldAlwaysTranslate();
155 void TranslateInfoBarDelegate::ToggleAlwaysTranslate() {
156 ui_delegate_
.SetAlwaysTranslate(!ui_delegate_
.ShouldAlwaysTranslate());
159 void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() {
160 DCHECK(!ui_delegate_
.ShouldAlwaysTranslate());
161 ui_delegate_
.SetAlwaysTranslate(true);
165 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
166 DCHECK(!ui_delegate_
.IsLanguageBlocked());
167 ui_delegate_
.SetLanguageBlocked(true);
168 infobar()->RemoveSelf();
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
);
179 DCHECK_EQ(TRANSLATION_ERROR
, infobar_type_
);
180 UMA_HISTOGRAM_ENUMERATION("Translate.ShowErrorInfobar",
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()));
205 return base::string16();
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
);
218 return base::string16();
221 void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
222 DCHECK_EQ(TRANSLATION_ERROR
, infobar_type_
);
223 if (error_type_
== TranslateErrors::UNSUPPORTED_LANGUAGE
) {
227 // This is the "Try again..." case.
228 TranslateManager::GetInstance()->TranslatePage(
229 web_contents(), original_language_code(), target_language_code());
232 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
233 return !GetMessageInfoBarButtonText().empty();
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
);
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
);
251 base::string16
TranslateInfoBarDelegate::GetLanguageDisplayableName(
252 const std::string
& language_code
) {
253 return l10n_util::GetDisplayNameForLocale(
254 language_code
, g_browser_process
->GetApplicationLocale(), true);
258 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
259 std::vector
<base::string16
>* strings
,
260 bool* swap_languages
,
261 bool autodetermined_source_language
) {
264 if (autodetermined_source_language
) {
266 base::string16 text
= l10n_util::GetStringFUTF16(
267 IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE
,
271 strings
->push_back(text
.substr(0, offset
));
272 strings
->push_back(text
.substr(offset
));
275 DCHECK(swap_languages
);
277 std::vector
<size_t> offsets
;
278 base::string16 text
= l10n_util::GetStringFUTF16(
279 IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE
, base::string16(), base::string16(),
281 DCHECK_EQ(2U, offsets
.size());
283 *swap_languages
= (offsets
[0] > offsets
[1]);
285 std::swap(offsets
[0], offsets
[1]);
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]));
292 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
293 content::WebContents
* web_contents
,
295 TranslateInfoBarDelegate
* old_delegate
,
296 const std::string
& original_language
,
297 const std::string
& target_language
,
298 TranslateErrors::Type error_type
,
300 ShortcutConfiguration shortcut_config
)
302 infobar_type_(infobar_type
),
303 background_animation_(NONE
),
304 ui_delegate_(web_contents
, original_language
, target_language
),
305 error_type_(error_type
),
307 shortcut_config_(shortcut_config
) {
308 DCHECK_NE((infobar_type_
== TRANSLATION_ERROR
),
309 (error_type_
== TranslateErrors::NONE
));
311 if (old_delegate
&& (old_delegate
->is_error() != is_error()))
312 background_animation_
= is_error() ? NORMAL_TO_ERROR
: ERROR_TO_NORMAL
;
315 // TranslateInfoBarDelegate::CreateInfoBar() is implemented in platform-specific
318 void TranslateInfoBarDelegate::InfoBarDismissed() {
319 if (infobar_type_
!= BEFORE_TRANSLATE
)
322 // The user closed the infobar without clicking the translate button.
323 TranslationDeclined();
324 UMA_HISTOGRAM_BOOLEAN("Translate.DeclineTranslateCloseInfobar", true);
327 int TranslateInfoBarDelegate::GetIconID() const {
328 return IDR_INFOBAR_TRANSLATE
;
331 InfoBarDelegate::Type
TranslateInfoBarDelegate::GetInfoBarType() const {
332 return PAGE_ACTION_TYPE
;
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
)
342 return InfoBarDelegate::ShouldExpireInternal(details
);
345 TranslateInfoBarDelegate
*
346 TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {