blob: a05badb8559e63fd463713c40c4218597cef0ca3 [file] [log] [blame]
[email protected]02798a982012-01-27 00:45:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]85d252e2010-04-06 22:21:022// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Doug Arnett2fd6cf22020-01-27 19:18:405#include "components/translate/content/renderer/translate_agent.h"
[email protected]85d252e2010-04-06 22:21:026
Scott Littlef130e8e82020-08-07 16:01:377#include <stddef.h>
Jan Wilken Dörriead587c32021-03-11 14:09:278#include <string>
tzik9a17d7af2017-05-09 14:21:589#include <utility>
10
[email protected]81c9c662011-10-12 04:27:0111#include "base/bind.h"
Hans Wennborgdf87046c2020-04-28 11:06:2412#include "base/check_op.h"
[email protected]85d252e2010-04-06 22:21:0213#include "base/compiler_specific.h"
Jon Nappera7dc1b002017-06-26 01:01:2114#include "base/json/string_escape.h"
skyostilb0daa012015-06-02 19:03:4815#include "base/location.h"
asvitkinea0f05db2015-06-16 21:45:4616#include "base/metrics/histogram_macros.h"
Hans Wennborgdf87046c2020-04-28 11:06:2417#include "base/notreached.h"
skyostilb0daa012015-06-02 19:03:4818#include "base/single_thread_task_runner.h"
[email protected]cbde0d92013-06-14 11:37:0419#include "base/strings/string_util.h"
[email protected]abfd1492013-06-07 21:23:2620#include "base/strings/utf_string_conversions.h"
Karandeep Bhatia4a8b4352020-07-16 06:57:1321#include "components/translate/content/renderer/isolated_world_util.h"
[email protected]eba93c92014-01-07 17:34:1722#include "components/translate/core/common/translate_constants.h"
23#include "components/translate/core/common/translate_metrics.h"
24#include "components/translate/core/common/translate_util.h"
Michael Crouse11e2a152020-12-12 20:50:3425#include "components/translate/core/language_detection/language_detection_model.h"
[email protected]bfa4c82a2014-05-13 23:45:0226#include "components/translate/core/language_detection/language_detection_util.h"
[email protected]9ce237042014-07-17 18:09:5627#include "content/public/common/content_constants.h"
drogerf1da1802014-09-17 14:54:0528#include "content/public/common/url_constants.h"
dglazkov24814772015-09-25 22:27:4729#include "content/public/renderer/render_frame.h"
[email protected]9ce237042014-07-17 18:09:5630#include "content/public/renderer/render_thread.h"
Mario Sanchez Prada8cbe4aa2019-12-03 10:00:2031#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
Blink Reformata30d4232018-04-07 15:31:0632#include "third_party/blink/public/web/web_document.h"
33#include "third_party/blink/public/web/web_language_detection_details.h"
34#include "third_party/blink/public/web/web_local_frame.h"
35#include "third_party/blink/public/web/web_script_source.h"
[email protected]afa9cd922013-07-30 06:12:1936#include "url/gurl.h"
mcrouse0d096d32021-02-11 01:58:4637#include "url/url_constants.h"
[email protected]4d51d5bf2010-07-26 18:48:2638#include "v8/include/v8.h"
[email protected]85d252e2010-04-06 22:21:0239
[email protected]a1221aea2013-11-07 01:31:3040using blink::WebDocument;
Doug Arnett2fd6cf22020-01-27 19:18:4041using blink::WebLanguageDetectionDetails;
dglazkov24814772015-09-25 22:27:4742using blink::WebLocalFrame;
[email protected]a1221aea2013-11-07 01:31:3043using blink::WebScriptSource;
[email protected]a1221aea2013-11-07 01:31:3044using blink::WebString;
45using blink::WebVector;
[email protected]85d252e2010-04-06 22:21:0246
[email protected]ff9b1c12013-02-07 11:40:1347namespace {
48
[email protected]02798a982012-01-27 00:45:3349// The delay in milliseconds that we'll wait before checking to see if the
[email protected]85d252e2010-04-06 22:21:0250// translate library injected in the page is ready.
[email protected]ff9b1c12013-02-07 11:40:1351const int kTranslateInitCheckDelayMs = 150;
[email protected]85d252e2010-04-06 22:21:0252
53// The maximum number of times we'll check to see if the translate library
54// injected in the page is ready.
[email protected]ff9b1c12013-02-07 11:40:1355const int kMaxTranslateInitCheckAttempts = 5;
[email protected]85d252e2010-04-06 22:21:0256
57// The delay we wait in milliseconds before checking whether the translation has
58// finished.
[email protected]ff9b1c12013-02-07 11:40:1359const int kTranslateStatusCheckDelayMs = 400;
[email protected]85d252e2010-04-06 22:21:0260
[email protected]d64b07b2010-04-20 22:14:0661// Language name passed to the Translate element for it to detect the language.
[email protected]33281252013-04-15 14:46:4962const char kAutoDetectionLanguage[] = "auto";
Michael Crouse11e2a152020-12-12 20:50:3463
mcrousee29a9f12021-02-17 19:06:2964// The current CLD model version.
65constexpr char kCLDModelVersion[] = "CLD3";
66
Michael Crouse11e2a152020-12-12 20:50:3467// Returns the language detection model that is shared across the RenderFrames
68// in the renderer.
69translate::LanguageDetectionModel& GetLanguageDetectionModel() {
70 static base::NoDestructor<translate::LanguageDetectionModel> instance;
71 return *instance;
72}
73
[email protected]ff9b1c12013-02-07 11:40:1374} // namespace
[email protected]d64b07b2010-04-20 22:14:0675
drogerf1da1802014-09-17 14:54:0576namespace translate {
[email protected]e5a7a2a2014-03-27 16:16:0377
[email protected]85d252e2010-04-06 22:21:0278////////////////////////////////////////////////////////////////////////////////
Doug Arnett2fd6cf22020-01-27 19:18:4079// TranslateAgent, public:
80TranslateAgent::TranslateAgent(content::RenderFrame* render_frame,
81 int world_id,
82 const std::string& extension_scheme)
dglazkov24814772015-09-25 22:27:4783 : content::RenderFrameObserver(render_frame),
drogerf1da1802014-09-17 14:54:0584 world_id_(world_id),
Julie Jeongeun Kim9b734c52019-09-25 16:19:5685 extension_scheme_(extension_scheme) {
Karolina Soltysc7fbc032018-10-25 10:10:0886 translate_task_runner_ = this->render_frame()->GetTaskRunner(
87 blink::TaskType::kInternalTranslation);
mcrouse0d096d32021-02-11 01:58:4688
89 if (translate::IsTFLiteLanguageDetectionEnabled()) {
90 translate::LanguageDetectionModel& language_detection_model =
91 GetLanguageDetectionModel();
92 if (!language_detection_model.IsAvailable()) {
93 // TODO(crbug.com/1160948): Consider tracking if another agent associated
94 // with the same LanguageDetectionModel has already requested a model be
95 // provided by the translate host.
96 GetTranslateHandler()->GetLanguageDetectionModel(
97 base::BindOnce(&TranslateAgent::UpdateLanguageDetectionModel,
98 weak_pointer_factory_.GetWeakPtr()));
99 }
100 }
Karolina Soltysc7fbc032018-10-25 10:10:08101}
[email protected]85d252e2010-04-06 22:21:02102
Doug Arnett2fd6cf22020-01-27 19:18:40103TranslateAgent::~TranslateAgent() {}
[email protected]601858c02010-09-01 17:08:20104
Doug Arnett2fd6cf22020-01-27 19:18:40105void TranslateAgent::PrepareForUrl(const GURL& url) {
leon.hanb07801312016-08-12 11:47:57106 // Navigated to a new url, reset current page translation.
107 ResetPage();
[email protected]e5a7a2a2014-03-27 16:16:03108}
109
Jan Wilken Dörriefa241ba2021-03-11 17:57:01110void TranslateAgent::PageCaptured(const std::u16string& contents) {
[email protected]256897732012-10-16 19:35:05111 // Get the document language as set by WebKit from the http-equiv
112 // meta tag for "content-language". This may or may not also
113 // have a value derived from the actual Content-Language HTTP
114 // header. The two actually have different meanings (despite the
115 // original intent of http-equiv to be an equivalent) with the former
116 // being the language of the document and the latter being the
117 // language of the intended audience (a distinction really only
mcrouse0d096d32021-02-11 01:58:46118 // relevant for things like language textbooks). This distinction
[email protected]256897732012-10-16 19:35:05119 // shouldn't affect translation.
dglazkov24814772015-09-25 22:27:47120 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
leon.han3134fc62016-08-10 07:25:58121 if (!main_frame)
[email protected]effa54c2013-05-28 11:14:23122 return;
[email protected]e5a7a2a2014-03-27 16:16:03123
Blink Reformat1c4d759e2017-04-09 16:34:54124 WebDocument document = main_frame->GetDocument();
adithyas5e615282017-01-17 21:27:01125 WebLanguageDetectionDetails web_detection_details =
Blink Reformat1c4d759e2017-04-09 16:34:54126 WebLanguageDetectionDetails::CollectLanguageDetectionDetails(document);
127 std::string content_language = web_detection_details.content_language.Utf8();
128 std::string html_lang = web_detection_details.html_language.Utf8();
Michael Crouse11e2a152020-12-12 20:50:34129 std::string model_detected_language;
Michael Crouse30c287a12020-12-14 23:26:01130 bool is_model_reliable = false;
mcrousee29a9f12021-02-17 19:06:29131 std::string detection_model_version;
132 float model_reliability_score = 0.0;
Michael Crouse11e2a152020-12-12 20:50:34133
134 std::string language;
135 if (translate::IsTFLiteLanguageDetectionEnabled()) {
mcrouse0d096d32021-02-11 01:58:46136 if (!document.Url().ProtocolIs(url::kHttpsScheme) &&
137 !document.Url().ProtocolIs(url::kHttpScheme)) {
138 // TFLite-based language detection only supports HTTP/HTTPS pages.
139 // Others should be ignored, for example the New Tab Page.
140 return;
141 }
Michael Crouse11e2a152020-12-12 20:50:34142 translate::LanguageDetectionModel& language_detection_model =
143 GetLanguageDetectionModel();
144 bool is_available = language_detection_model.IsAvailable();
145 language = is_available ? language_detection_model.DeterminePageLanguage(
146 content_language, html_lang, contents,
mcrousee29a9f12021-02-17 19:06:29147 &model_detected_language, &is_model_reliable,
148 model_reliability_score)
Michael Crouse11e2a152020-12-12 20:50:34149 : translate::kUnknownLanguageCode;
mcrouseca5021c2021-02-19 00:34:14150 UMA_HISTOGRAM_BOOLEAN(
Michael Crouse11e2a152020-12-12 20:50:34151 "LanguageDetection.TFLiteModel.WasModelAvailableForDetection",
152 is_available);
mcrousee29a9f12021-02-17 19:06:29153 detection_model_version = language_detection_model.GetModelVersion();
Michael Crouse11e2a152020-12-12 20:50:34154 } else {
mcrousee29a9f12021-02-17 19:06:29155 language = DeterminePageLanguage(
156 content_language, html_lang, contents, &model_detected_language,
157 &is_model_reliable, model_reliability_score);
158 detection_model_version = kCLDModelVersion;
Michael Crouse11e2a152020-12-12 20:50:34159 }
[email protected]27eff892013-05-21 16:40:52160
161 if (language.empty())
162 return;
[email protected]93b9d692011-04-13 00:44:31163
[email protected]0f6afb42013-05-17 03:44:47164 language_determined_time_ = base::TimeTicks::Now();
165
Michael Crouse11e2a152020-12-12 20:50:34166 // TODO(crbug.com/1157983): Update the language detection details struct to be
167 // model agnostic.
drogerf1da1802014-09-17 14:54:05168 LanguageDetectionDetails details;
[email protected]27eff892013-05-21 16:40:52169 details.time = base::Time::Now();
adithyas5e615282017-01-17 21:27:01170 details.url = web_detection_details.url;
[email protected]27eff892013-05-21 16:40:52171 details.content_language = content_language;
Michael Crouse0ebf0d52020-12-14 23:29:31172 details.model_detected_language = model_detected_language;
173 details.is_model_reliable = is_model_reliable;
Blink Reformat1c4d759e2017-04-09 16:34:54174 details.has_notranslate = web_detection_details.has_no_translate_meta;
[email protected]20efbf2f2013-05-31 06:42:37175 details.html_root_language = html_lang;
[email protected]27eff892013-05-21 16:40:52176 details.adopted_language = language;
mcrousee29a9f12021-02-17 19:06:29177 details.model_reliability_score = model_reliability_score;
178 details.detection_model_version = detection_model_version;
[email protected]27eff892013-05-21 16:40:52179
[email protected]d861d972013-05-30 06:02:31180 // TODO(hajimehoshi): If this affects performance, it should be set only if
181 // translate-internals tab exists.
182 details.contents = contents;
183
leon.han3134fc62016-08-10 07:25:58184 // For the same render frame with the same url, each time when its texts are
185 // captured, it should be treated as a new page to do translation.
leon.hanb07801312016-08-12 11:47:57186 ResetPage();
Michael Martis088a00a2018-04-12 09:33:05187 GetTranslateHandler()->RegisterPage(
Julie Jeongeun Kim9b734c52019-09-25 16:19:56188 receiver_.BindNewPipeAndPassRemote(
189 main_frame->GetTaskRunner(blink::TaskType::kInternalTranslation)),
190 details, !details.has_notranslate && !language.empty());
[email protected]93b9d692011-04-13 00:44:31191}
192
Doug Arnett2fd6cf22020-01-27 19:18:40193void TranslateAgent::CancelPendingTranslation() {
[email protected]81c9c662011-10-12 04:27:01194 weak_method_factory_.InvalidateWeakPtrs();
leon.han3134fc62016-08-10 07:25:58195 // Make sure to send the cancelled response back.
196 if (translate_callback_pending_) {
tzik9a17d7af2017-05-09 14:21:58197 std::move(translate_callback_pending_)
198 .Run(true, source_lang_, target_lang_, TranslateErrors::NONE);
leon.han3134fc62016-08-10 07:25:58199 }
[email protected]d64b07b2010-04-20 22:14:06200 source_lang_.clear();
201 target_lang_.clear();
202}
203
[email protected]85d252e2010-04-06 22:21:02204////////////////////////////////////////////////////////////////////////////////
Doug Arnett2fd6cf22020-01-27 19:18:40205// TranslateAgent, protected:
206bool TranslateAgent::IsTranslateLibAvailable() {
[email protected]0dfc0e52013-04-15 14:53:00207 return ExecuteScriptAndGetBoolResult(
[email protected]85d252e2010-04-06 22:21:02208 "typeof cr != 'undefined' && typeof cr.googleTranslate != 'undefined' && "
Doug Arnett2fd6cf22020-01-27 19:18:40209 "typeof cr.googleTranslate.translate == 'function'",
210 false);
[email protected]85d252e2010-04-06 22:21:02211}
212
Doug Arnett2fd6cf22020-01-27 19:18:40213bool TranslateAgent::IsTranslateLibReady() {
[email protected]0dfc0e52013-04-15 14:53:00214 return ExecuteScriptAndGetBoolResult("cr.googleTranslate.libReady", false);
[email protected]85d252e2010-04-06 22:21:02215}
216
Doug Arnett2fd6cf22020-01-27 19:18:40217bool TranslateAgent::HasTranslationFinished() {
[email protected]0dfc0e52013-04-15 14:53:00218 return ExecuteScriptAndGetBoolResult("cr.googleTranslate.finished", true);
[email protected]85d252e2010-04-06 22:21:02219}
220
Doug Arnett2fd6cf22020-01-27 19:18:40221bool TranslateAgent::HasTranslationFailed() {
[email protected]0dfc0e52013-04-15 14:53:00222 return ExecuteScriptAndGetBoolResult("cr.googleTranslate.error", true);
[email protected]85d252e2010-04-06 22:21:02223}
224
Doug Arnett2fd6cf22020-01-27 19:18:40225int64_t TranslateAgent::GetErrorCode() {
gajendra.n5bcb90a2017-07-05 09:02:52226 int64_t error_code =
227 ExecuteScriptAndGetIntegerResult("cr.googleTranslate.errorCode");
228 DCHECK_LT(error_code, static_cast<int>(TranslateErrors::TRANSLATE_ERROR_MAX));
229 return error_code;
230}
231
Doug Arnett2fd6cf22020-01-27 19:18:40232bool TranslateAgent::StartTranslation() {
Jon Nappera7dc1b002017-06-26 01:01:21233 return ExecuteScriptAndGetBoolResult(
234 BuildTranslationScript(source_lang_, target_lang_), false);
[email protected]85d252e2010-04-06 22:21:02235}
236
Doug Arnett2fd6cf22020-01-27 19:18:40237std::string TranslateAgent::GetOriginalPageLanguage() {
[email protected]0dfc0e52013-04-15 14:53:00238 return ExecuteScriptAndGetStringResult("cr.googleTranslate.sourceLang");
[email protected]d64b07b2010-04-20 22:14:06239}
240
Doug Arnettc1436ac2020-04-08 03:10:05241base::TimeDelta TranslateAgent::AdjustDelay(int delay_in_milliseconds) {
242 // Just converts |delay_in_milliseconds| without any modification in practical
243 // cases. Tests will override this function to return modified value.
244 return base::TimeDelta::FromMilliseconds(delay_in_milliseconds);
[email protected]e4be2dd2010-12-14 00:44:39245}
246
Doug Arnett2fd6cf22020-01-27 19:18:40247void TranslateAgent::ExecuteScript(const std::string& script) {
dglazkov24814772015-09-25 22:27:47248 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]afa9cd922013-07-30 06:12:19249 if (!main_frame)
250 return;
251
Blink Reformat1c4d759e2017-04-09 16:34:54252 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Dave Tapuska306a72402021-04-09 14:20:02253 main_frame->ExecuteScriptInIsolatedWorld(
254 world_id_, source, blink::BackForwardCacheAware::kAllow);
[email protected]e0be00992013-04-26 13:15:29255}
256
Doug Arnett2fd6cf22020-01-27 19:18:40257bool TranslateAgent::ExecuteScriptAndGetBoolResult(const std::string& script,
258 bool fallback) {
dglazkov24814772015-09-25 22:27:47259 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]e0be00992013-04-26 13:15:29260 if (!main_frame)
261 return fallback;
262
[email protected]dc3d06e2013-09-06 12:21:03263 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
Blink Reformat1c4d759e2017-04-09 16:34:54264 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06265 v8::Local<v8::Value> result =
Dave Tapuska306a72402021-04-09 14:20:02266 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(
267 world_id_, source, blink::BackForwardCacheAware::kAllow);
Hiroshige Hayashizakie1352e62018-05-14 23:03:06268 if (result.IsEmpty() || !result->IsBoolean()) {
[email protected]e0be00992013-04-26 13:15:29269 NOTREACHED();
270 return fallback;
271 }
272
Ross McIlroy1c8eb142018-08-01 15:12:07273 return result.As<v8::Boolean>()->Value();
[email protected]e0be00992013-04-26 13:15:29274}
275
Doug Arnett2fd6cf22020-01-27 19:18:40276std::string TranslateAgent::ExecuteScriptAndGetStringResult(
[email protected]e0be00992013-04-26 13:15:29277 const std::string& script) {
dglazkov24814772015-09-25 22:27:47278 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]e0be00992013-04-26 13:15:29279 if (!main_frame)
280 return std::string();
281
Dan Elphickc027e8ae2018-07-27 10:10:10282 v8::Isolate* isolate = v8::Isolate::GetCurrent();
283 v8::HandleScope handle_scope(isolate);
Blink Reformat1c4d759e2017-04-09 16:34:54284 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06285 v8::Local<v8::Value> result =
Dave Tapuska306a72402021-04-09 14:20:02286 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(
287 world_id_, source, blink::BackForwardCacheAware::kAllow);
Hiroshige Hayashizakie1352e62018-05-14 23:03:06288 if (result.IsEmpty() || !result->IsString()) {
[email protected]e0be00992013-04-26 13:15:29289 NOTREACHED();
290 return std::string();
291 }
292
Hiroshige Hayashizakie1352e62018-05-14 23:03:06293 v8::Local<v8::String> v8_str = result.As<v8::String>();
Scott Littlef130e8e82020-08-07 16:01:37294 int length = v8_str->Utf8Length(isolate);
295 if (length <= 0)
296 return std::string();
297
298 std::string str(static_cast<size_t>(length), '\0');
299 v8_str->WriteUtf8(isolate, &str[0], length);
300 return str;
[email protected]e0be00992013-04-26 13:15:29301}
302
Doug Arnett2fd6cf22020-01-27 19:18:40303double TranslateAgent::ExecuteScriptAndGetDoubleResult(
[email protected]e0be00992013-04-26 13:15:29304 const std::string& script) {
dglazkov24814772015-09-25 22:27:47305 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]e0be00992013-04-26 13:15:29306 if (!main_frame)
307 return 0.0;
308
[email protected]dc3d06e2013-09-06 12:21:03309 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
Blink Reformat1c4d759e2017-04-09 16:34:54310 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06311 v8::Local<v8::Value> result =
Dave Tapuska306a72402021-04-09 14:20:02312 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(
313 world_id_, source, blink::BackForwardCacheAware::kAllow);
Hiroshige Hayashizakie1352e62018-05-14 23:03:06314 if (result.IsEmpty() || !result->IsNumber()) {
[email protected]e0be00992013-04-26 13:15:29315 NOTREACHED();
316 return 0.0;
317 }
318
Ross McIlroy1c8eb142018-08-01 15:12:07319 return result.As<v8::Number>()->Value();
[email protected]e0be00992013-04-26 13:15:29320}
321
Doug Arnett2fd6cf22020-01-27 19:18:40322int64_t TranslateAgent::ExecuteScriptAndGetIntegerResult(
gajendra.n5bcb90a2017-07-05 09:02:52323 const std::string& script) {
324 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
325 if (!main_frame)
326 return 0;
327
328 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
gajendra.n5bcb90a2017-07-05 09:02:52329 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06330 v8::Local<v8::Value> result =
Dave Tapuska306a72402021-04-09 14:20:02331 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(
332 world_id_, source, blink::BackForwardCacheAware::kAllow);
Hiroshige Hayashizakie1352e62018-05-14 23:03:06333 if (result.IsEmpty() || !result->IsNumber()) {
gajendra.n5bcb90a2017-07-05 09:02:52334 NOTREACHED();
335 return 0;
336 }
337
Ross McIlroy1c8eb142018-08-01 15:12:07338 return result.As<v8::Integer>()->Value();
gajendra.n5bcb90a2017-07-05 09:02:52339}
340
Doug Arnett2fd6cf22020-01-27 19:18:40341// mojom::TranslateAgent implementations.
Doug Arnettc1436ac2020-04-08 03:10:05342void TranslateAgent::GetWebLanguageDetectionDetails(
343 GetWebLanguageDetectionDetailsCallback callback) {
344 NOTREACHED() << "This interface supported by PerFrameTranslateAgent";
345}
346
Doug Arnett2fd6cf22020-01-27 19:18:40347void TranslateAgent::TranslateFrame(const std::string& translate_script,
348 const std::string& source_lang,
349 const std::string& target_lang,
350 TranslateFrameCallback callback) {
dglazkov24814772015-09-25 22:27:47351 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
leon.han3134fc62016-08-10 07:25:58352 if (!main_frame) {
353 // Cancelled.
tzik9a17d7af2017-05-09 14:21:58354 std::move(callback).Run(true, source_lang, target_lang,
355 TranslateErrors::NONE);
[email protected]81273622011-02-02 03:56:13356 return; // We navigated away, nothing to do.
leon.han3134fc62016-08-10 07:25:58357 }
[email protected]81273622011-02-02 03:56:13358
[email protected]4a2387e2013-05-31 03:47:56359 // A similar translation is already under way, nothing to do.
leon.han3134fc62016-08-10 07:25:58360 if (translate_callback_pending_ && target_lang_ == target_lang) {
361 // This request is ignored.
tzik9a17d7af2017-05-09 14:21:58362 std::move(callback).Run(true, source_lang, target_lang,
363 TranslateErrors::NONE);
[email protected]81273622011-02-02 03:56:13364 return;
leon.han3134fc62016-08-10 07:25:58365 }
[email protected]81273622011-02-02 03:56:13366
367 // Any pending translation is now irrelevant.
368 CancelPendingTranslation();
369
370 // Set our states.
tzik9a17d7af2017-05-09 14:21:58371 translate_callback_pending_ = std::move(callback);
[email protected]4a2387e2013-05-31 03:47:56372
[email protected]81273622011-02-02 03:56:13373 // If the source language is undetermined, we'll let the translate element
374 // detect it.
drogerf1da1802014-09-17 14:54:05375 source_lang_ = (source_lang != kUnknownLanguageCode) ? source_lang
376 : kAutoDetectionLanguage;
[email protected]81273622011-02-02 03:56:13377 target_lang_ = target_lang;
378
drogerf1da1802014-09-17 14:54:05379 ReportUserActionDuration(language_determined_time_, base::TimeTicks::Now());
[email protected]0f6afb42013-05-17 03:44:47380
Blink Reformat1c4d759e2017-04-09 16:34:54381 GURL url(main_frame->GetDocument().Url());
drogerf1da1802014-09-17 14:54:05382 ReportPageScheme(url.scheme());
[email protected]595ec512013-05-23 16:40:30383
Karandeep Bhatia4a8b4352020-07-16 06:57:13384 // Set up v8 isolated world.
385 EnsureIsolatedWorldInitialized(world_id_);
[email protected]afa9cd922013-07-30 06:12:19386
[email protected]81273622011-02-02 03:56:13387 if (!IsTranslateLibAvailable()) {
388 // Evaluate the script to add the translation related method to the global
389 // context of the page.
390 ExecuteScript(translate_script);
391 DCHECK(IsTranslateLibAvailable());
392 }
393
leon.han3134fc62016-08-10 07:25:58394 TranslatePageImpl(0);
[email protected]81273622011-02-02 03:56:13395}
396
Doug Arnett2fd6cf22020-01-27 19:18:40397void TranslateAgent::RevertTranslation() {
[email protected]81273622011-02-02 03:56:13398 if (!IsTranslateLibAvailable()) {
399 NOTREACHED();
400 return;
401 }
402
[email protected]81273622011-02-02 03:56:13403 CancelPendingTranslation();
404
[email protected]0dfc0e52013-04-15 14:53:00405 ExecuteScript("cr.googleTranslate.revert()");
[email protected]81273622011-02-02 03:56:13406}
407
leon.han3134fc62016-08-10 07:25:58408////////////////////////////////////////////////////////////////////////////////
Doug Arnett2fd6cf22020-01-27 19:18:40409// TranslateAgent, private:
410void TranslateAgent::CheckTranslateStatus() {
[email protected]85d252e2010-04-06 22:21:02411 // First check if there was an error.
412 if (HasTranslationFailed()) {
gajendra.n5bcb90a2017-07-05 09:02:52413 NotifyBrowserTranslationFailed(
414 static_cast<translate::TranslateErrors::Type>(GetErrorCode()));
[email protected]85d252e2010-04-06 22:21:02415 return; // There was an error.
416 }
417
418 if (HasTranslationFinished()) {
[email protected]d64b07b2010-04-20 22:14:06419 std::string actual_source_lang;
420 // Translation was successfull, if it was auto, retrieve the source
421 // language the Translate Element detected.
422 if (source_lang_ == kAutoDetectionLanguage) {
423 actual_source_lang = GetOriginalPageLanguage();
424 if (actual_source_lang.empty()) {
drogerf1da1802014-09-17 14:54:05425 NotifyBrowserTranslationFailed(TranslateErrors::UNKNOWN_LANGUAGE);
[email protected]579317e2010-06-30 20:13:48426 return;
427 } else if (actual_source_lang == target_lang_) {
drogerf1da1802014-09-17 14:54:05428 NotifyBrowserTranslationFailed(TranslateErrors::IDENTICAL_LANGUAGES);
[email protected]d64b07b2010-04-20 22:14:06429 return;
430 }
431 } else {
432 actual_source_lang = source_lang_;
433 }
434
leon.han3134fc62016-08-10 07:25:58435 if (!translate_callback_pending_) {
[email protected]d64b07b2010-04-20 22:14:06436 NOTREACHED();
437 return;
438 }
439
[email protected]e0be00992013-04-26 13:15:29440 // Check JavaScript performance counters for UMA reports.
drogerf1da1802014-09-17 14:54:05441 ReportTimeToTranslate(
[email protected]3a2ea8f2013-05-13 18:40:15442 ExecuteScriptAndGetDoubleResult("cr.googleTranslate.translationTime"));
[email protected]e0be00992013-04-26 13:15:29443
[email protected]d64b07b2010-04-20 22:14:06444 // Notify the browser we are done.
tzik9a17d7af2017-05-09 14:21:58445 std::move(translate_callback_pending_)
446 .Run(false, actual_source_lang, target_lang_, TranslateErrors::NONE);
[email protected]85d252e2010-04-06 22:21:02447 return;
448 }
449
450 // The translation is still pending, check again later.
Karolina Soltysc7fbc032018-10-25 10:10:08451 translate_task_runner_->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15452 FROM_HERE,
Doug Arnett2fd6cf22020-01-27 19:18:40453 base::BindOnce(&TranslateAgent::CheckTranslateStatus,
tzik2bcf8e42018-07-31 11:22:15454 weak_method_factory_.GetWeakPtr()),
[email protected]0dfc0e52013-04-15 14:53:00455 AdjustDelay(kTranslateStatusCheckDelayMs));
[email protected]85d252e2010-04-06 22:21:02456}
457
Doug Arnett2fd6cf22020-01-27 19:18:40458void TranslateAgent::TranslatePageImpl(int count) {
[email protected]85d252e2010-04-06 22:21:02459 DCHECK_LT(count, kMaxTranslateInitCheckAttempts);
[email protected]85d252e2010-04-06 22:21:02460 if (!IsTranslateLibReady()) {
gajendra.n5bcb90a2017-07-05 09:02:52461 // There was an error during initialization of library.
462 TranslateErrors::Type error =
463 static_cast<translate::TranslateErrors::Type>(GetErrorCode());
464 if (error != TranslateErrors::NONE) {
465 NotifyBrowserTranslationFailed(error);
466 return;
467 }
468
[email protected]85d252e2010-04-06 22:21:02469 // The library is not ready, try again later, unless we have tried several
thestig259626c2015-11-23 20:18:11470 // times unsuccessfully already.
[email protected]85d252e2010-04-06 22:21:02471 if (++count >= kMaxTranslateInitCheckAttempts) {
gajendra.n5bcb90a2017-07-05 09:02:52472 NotifyBrowserTranslationFailed(TranslateErrors::TRANSLATION_TIMEOUT);
[email protected]85d252e2010-04-06 22:21:02473 return;
474 }
Hajime Hoshi701c6e12019-03-19 15:19:18475 translate_task_runner_->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15476 FROM_HERE,
Doug Arnett2fd6cf22020-01-27 19:18:40477 base::BindOnce(&TranslateAgent::TranslatePageImpl,
tzik2bcf8e42018-07-31 11:22:15478 weak_method_factory_.GetWeakPtr(), count),
[email protected]0dfc0e52013-04-15 14:53:00479 AdjustDelay(count * kTranslateInitCheckDelayMs));
[email protected]85d252e2010-04-06 22:21:02480 return;
481 }
482
[email protected]e0be00992013-04-26 13:15:29483 // The library is loaded, and ready for translation now.
484 // Check JavaScript performance counters for UMA reports.
drogerf1da1802014-09-17 14:54:05485 ReportTimeToBeReady(
[email protected]3a2ea8f2013-05-13 18:40:15486 ExecuteScriptAndGetDoubleResult("cr.googleTranslate.readyTime"));
drogerf1da1802014-09-17 14:54:05487 ReportTimeToLoad(
[email protected]3a2ea8f2013-05-13 18:40:15488 ExecuteScriptAndGetDoubleResult("cr.googleTranslate.loadTime"));
[email protected]e0be00992013-04-26 13:15:29489
[email protected]d64b07b2010-04-20 22:14:06490 if (!StartTranslation()) {
gajendra.n5bcb90a2017-07-05 09:02:52491 CheckTranslateStatus();
[email protected]85d252e2010-04-06 22:21:02492 return;
493 }
494 // Check the status of the translation.
Karolina Soltysc7fbc032018-10-25 10:10:08495 translate_task_runner_->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15496 FROM_HERE,
Doug Arnett2fd6cf22020-01-27 19:18:40497 base::BindOnce(&TranslateAgent::CheckTranslateStatus,
tzik2bcf8e42018-07-31 11:22:15498 weak_method_factory_.GetWeakPtr()),
[email protected]0dfc0e52013-04-15 14:53:00499 AdjustDelay(kTranslateStatusCheckDelayMs));
[email protected]85d252e2010-04-06 22:21:02500}
501
Doug Arnett2fd6cf22020-01-27 19:18:40502void TranslateAgent::NotifyBrowserTranslationFailed(
drogerf1da1802014-09-17 14:54:05503 TranslateErrors::Type error) {
leon.han3134fc62016-08-10 07:25:58504 DCHECK(translate_callback_pending_);
[email protected]85d252e2010-04-06 22:21:02505 // Notify the browser there was an error.
tzik9a17d7af2017-05-09 14:21:58506 std::move(translate_callback_pending_)
507 .Run(false, source_lang_, target_lang_, error);
leon.han3134fc62016-08-10 07:25:58508}
509
Julie Jeongeun Kimb1afbe52019-09-26 02:39:48510const mojo::Remote<mojom::ContentTranslateDriver>&
Doug Arnett2fd6cf22020-01-27 19:18:40511TranslateAgent::GetTranslateHandler() {
Michael Martis088a00a2018-04-12 09:33:05512 if (!translate_handler_) {
Mario Sanchez Prada8cbe4aa2019-12-03 10:00:20513 render_frame()->GetBrowserInterfaceBroker()->GetInterface(
Julie Jeongeun Kimb1afbe52019-09-26 02:39:48514 translate_handler_.BindNewPipeAndPassReceiver());
leon.han3134fc62016-08-10 07:25:58515 }
516
Michael Martis088a00a2018-04-12 09:33:05517 return translate_handler_;
[email protected]7faa53862010-06-16 00:09:13518}
[email protected]e5a7a2a2014-03-27 16:16:03519
Doug Arnett2fd6cf22020-01-27 19:18:40520void TranslateAgent::ResetPage() {
Julie Jeongeun Kim9b734c52019-09-25 16:19:56521 receiver_.reset();
leon.hanb07801312016-08-12 11:47:57522 translate_callback_pending_.Reset();
523 CancelPendingTranslation();
524}
525
Doug Arnett2fd6cf22020-01-27 19:18:40526void TranslateAgent::OnDestruct() {
xjz694b50a92016-06-07 21:49:37527 delete this;
528}
529
Jon Nappera7dc1b002017-06-26 01:01:21530/* static */
Doug Arnett2fd6cf22020-01-27 19:18:40531std::string TranslateAgent::BuildTranslationScript(
Jon Nappera7dc1b002017-06-26 01:01:21532 const std::string& source_lang,
533 const std::string& target_lang) {
534 return "cr.googleTranslate.translate(" +
535 base::GetQuotedJSONString(source_lang) + "," +
536 base::GetQuotedJSONString(target_lang) + ")";
537}
538
mcrouse0d096d32021-02-11 01:58:46539void TranslateAgent::UpdateLanguageDetectionModel(base::File model_file) {
540 translate::LanguageDetectionModel& language_detection_model =
541 GetLanguageDetectionModel();
542 language_detection_model.UpdateWithFile(std::move(model_file));
543}
544
drogerf1da1802014-09-17 14:54:05545} // namespace translate