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/ios/browser/language_detection_controller.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_member.h"
13 #include "base/time/time.h"
14 #include "components/translate/core/common/translate_pref_names.h"
15 #include "components/translate/core/language_detection/language_detection_util.h"
16 #import "components/translate/ios/browser/js_language_detection_manager.h"
17 #include "ios/web/public/string_util.h"
18 #include "ios/web/public/url_scheme_util.h"
19 #include "ios/web/public/web_state/web_state.h"
24 // Name for the UMA metric used to track text extraction time.
25 const char kTranslateCaptureText[] = "Translate.CaptureText";
26 // Prefix for the language detection javascript commands. Must be kept in sync
27 // with language_detection.js.
28 const char kCommandPrefix[] = "languageDetection";
31 LanguageDetectionController::LanguageDetectionController(
32 web::WebState* web_state,
33 JsLanguageDetectionManager* manager,
35 : web::WebStateObserver(web_state),
36 js_manager_([manager retain]),
37 weak_method_factory_(this) {
38 DCHECK(web::WebStateObserver::web_state());
40 translate_enabled_.Init(prefs::kEnableTranslate, prefs);
41 web_state->AddScriptCommandCallback(
42 base::Bind(&LanguageDetectionController::OnTextCaptured,
43 base::Unretained(this)),
47 LanguageDetectionController::~LanguageDetectionController() {
50 scoped_ptr<LanguageDetectionController::CallbackList::Subscription>
51 LanguageDetectionController::RegisterLanguageDetectionCallback(
52 const Callback& callback) {
53 return language_detection_callbacks_.Add(callback);
56 void LanguageDetectionController::StartLanguageDetection() {
57 if (!translate_enabled_.GetValue())
58 return; // Translate disabled in preferences.
60 const GURL& url = web_state()->GetVisibleURL();
61 if (!web::UrlHasWebScheme(url) || !web_state()->ContentIsHTML())
64 [js_manager_ startLanguageDetection];
67 bool LanguageDetectionController::OnTextCaptured(
68 const base::DictionaryValue& command,
71 std::string textCapturedCommand;
72 if (!command.GetString("command", &textCapturedCommand) ||
73 textCapturedCommand != "languageDetection.textCaptured" ||
74 !command.HasKey("translationAllowed")) {
78 bool translation_allowed = false;
79 command.GetBoolean("translationAllowed", &translation_allowed);
80 if (!translation_allowed) {
81 // Translation not allowed by the page. Done processing.
84 if (!command.HasKey("captureTextTime") || !command.HasKey("htmlLang") ||
85 !command.HasKey("httpContentLanguage")) {
90 int capture_text_time = 0;
91 command.GetInteger("captureTextTime", &capture_text_time);
92 UMA_HISTOGRAM_TIMES(kTranslateCaptureText,
93 base::TimeDelta::FromMillisecondsD(capture_text_time));
94 std::string html_lang;
95 command.GetString("htmlLang", &html_lang);
96 std::string http_content_language;
97 command.GetString("httpContentLanguage", &http_content_language);
98 // If there is no language defined in httpEquiv, use the HTTP header.
99 if (http_content_language.empty())
100 http_content_language = web_state()->GetContentLanguageHeader();
102 [js_manager_ retrieveBufferedTextContent:
103 base::Bind(&LanguageDetectionController::OnTextRetrieved,
104 weak_method_factory_.GetWeakPtr(),
105 http_content_language, html_lang)];
109 void LanguageDetectionController::OnTextRetrieved(
110 const std::string& http_content_language,
111 const std::string& html_lang,
112 const base::string16& text_content) {
113 std::string language = translate::DeterminePageLanguage(
114 http_content_language, html_lang,
115 web::GetStringByClippingLastWord(text_content,
116 language_detection::kMaxIndexChars),
117 nullptr /* cld_language */, nullptr /* is_cld_reliable */);
118 if (language.empty())
119 return; // No language detected.
121 DetectionDetails details;
122 details.content_language = http_content_language;
123 details.html_root_language = html_lang;
124 details.adopted_language = language;
125 language_detection_callbacks_.Notify(details);
128 // web::WebStateObserver implementation:
130 void LanguageDetectionController::PageLoaded(
131 web::PageLoadCompletionStatus load_completion_status) {
132 if (load_completion_status == web::PageLoadCompletionStatus::SUCCESS)
133 StartLanguageDetection();
136 void LanguageDetectionController::UrlHashChanged() {
137 StartLanguageDetection();
140 void LanguageDetectionController::HistoryStateChanged() {
141 StartLanguageDetection();
144 void LanguageDetectionController::WebStateDestroyed() {
145 web_state()->RemoveScriptCommandCallback(kCommandPrefix);
148 } // namespace translate