blob: c2e18c82a754af50ef558b141001617c8f6fc8bd [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
drogerf1da1802014-09-17 14:54:055#include "components/translate/content/renderer/translate_helper.h"
[email protected]85d252e2010-04-06 22:21:026
tzik9a17d7af2017-05-09 14:21:587#include <utility>
8
[email protected]81c9c662011-10-12 04:27:019#include "base/bind.h"
[email protected]85d252e2010-04-06 22:21:0210#include "base/compiler_specific.h"
Jon Nappera7dc1b002017-06-26 01:01:2111#include "base/json/string_escape.h"
skyostilb0daa012015-06-02 19:03:4812#include "base/location.h"
[email protected]b6825912012-03-09 23:09:1013#include "base/logging.h"
asvitkinea0f05db2015-06-16 21:45:4614#include "base/metrics/histogram_macros.h"
skyostilb0daa012015-06-02 19:03:4815#include "base/single_thread_task_runner.h"
[email protected]a19a16d82013-06-11 17:45:1216#include "base/strings/string16.h"
[email protected]cbde0d92013-06-14 11:37:0417#include "base/strings/string_util.h"
[email protected]abfd1492013-06-07 21:23:2618#include "base/strings/utf_string_conversions.h"
gab7966d312016-05-11 20:35:0119#include "base/threading/thread_task_runner_handle.h"
[email protected]eba93c92014-01-07 17:34:1720#include "components/translate/core/common/translate_constants.h"
21#include "components/translate/core/common/translate_metrics.h"
22#include "components/translate/core/common/translate_util.h"
[email protected]bfa4c82a2014-05-13 23:45:0223#include "components/translate/core/language_detection/language_detection_util.h"
[email protected]9ce237042014-07-17 18:09:5624#include "content/public/common/content_constants.h"
drogerf1da1802014-09-17 14:54:0525#include "content/public/common/url_constants.h"
dglazkov24814772015-09-25 22:27:4726#include "content/public/renderer/render_frame.h"
[email protected]9ce237042014-07-17 18:09:5627#include "content/public/renderer/render_thread.h"
rockot734fb662016-10-15 16:41:3028#include "services/service_manager/public/cpp/interface_provider.h"
Blink Reformata30d4232018-04-07 15:31:0629#include "third_party/blink/public/web/web_document.h"
30#include "third_party/blink/public/web/web_language_detection_details.h"
31#include "third_party/blink/public/web/web_local_frame.h"
32#include "third_party/blink/public/web/web_script_source.h"
[email protected]afa9cd922013-07-30 06:12:1933#include "url/gurl.h"
[email protected]4d51d5bf2010-07-26 18:48:2634#include "v8/include/v8.h"
[email protected]85d252e2010-04-06 22:21:0235
[email protected]a1221aea2013-11-07 01:31:3036using blink::WebDocument;
dglazkov24814772015-09-25 22:27:4737using blink::WebLocalFrame;
[email protected]a1221aea2013-11-07 01:31:3038using blink::WebScriptSource;
39using blink::WebSecurityOrigin;
40using blink::WebString;
41using blink::WebVector;
adithyas5e615282017-01-17 21:27:0142using blink::WebLanguageDetectionDetails;
[email protected]85d252e2010-04-06 22:21:0243
[email protected]ff9b1c12013-02-07 11:40:1344namespace {
45
[email protected]02798a982012-01-27 00:45:3346// The delay in milliseconds that we'll wait before checking to see if the
[email protected]85d252e2010-04-06 22:21:0247// translate library injected in the page is ready.
[email protected]ff9b1c12013-02-07 11:40:1348const int kTranslateInitCheckDelayMs = 150;
[email protected]85d252e2010-04-06 22:21:0249
50// The maximum number of times we'll check to see if the translate library
51// injected in the page is ready.
[email protected]ff9b1c12013-02-07 11:40:1352const int kMaxTranslateInitCheckAttempts = 5;
[email protected]85d252e2010-04-06 22:21:0253
54// The delay we wait in milliseconds before checking whether the translation has
55// finished.
[email protected]ff9b1c12013-02-07 11:40:1356const int kTranslateStatusCheckDelayMs = 400;
[email protected]85d252e2010-04-06 22:21:0257
[email protected]d64b07b2010-04-20 22:14:0658// Language name passed to the Translate element for it to detect the language.
[email protected]33281252013-04-15 14:46:4959const char kAutoDetectionLanguage[] = "auto";
[email protected]ff9b1c12013-02-07 11:40:1360
[email protected]afa9cd922013-07-30 06:12:1961// Isolated world sets following content-security-policy.
62const char kContentSecurityPolicy[] = "script-src 'self' 'unsafe-eval'";
63
[email protected]ff9b1c12013-02-07 11:40:1364} // namespace
[email protected]d64b07b2010-04-20 22:14:0665
drogerf1da1802014-09-17 14:54:0566namespace translate {
[email protected]e5a7a2a2014-03-27 16:16:0367
[email protected]85d252e2010-04-06 22:21:0268////////////////////////////////////////////////////////////////////////////////
69// TranslateHelper, public:
dglazkov24814772015-09-25 22:27:4770TranslateHelper::TranslateHelper(content::RenderFrame* render_frame,
drogerf1da1802014-09-17 14:54:0571 int world_id,
drogerf1da1802014-09-17 14:54:0572 const std::string& extension_scheme)
dglazkov24814772015-09-25 22:27:4773 : content::RenderFrameObserver(render_frame),
drogerf1da1802014-09-17 14:54:0574 world_id_(world_id),
drogerf1da1802014-09-17 14:54:0575 extension_scheme_(extension_scheme),
leon.han3134fc62016-08-10 07:25:5876 binding_(this),
dglazkov24814772015-09-25 22:27:4777 weak_method_factory_(this) {}
[email protected]85d252e2010-04-06 22:21:0278
[email protected]601858c02010-09-01 17:08:2079TranslateHelper::~TranslateHelper() {
80}
81
[email protected]e5a7a2a2014-03-27 16:16:0382void TranslateHelper::PrepareForUrl(const GURL& url) {
leon.hanb07801312016-08-12 11:47:5783 // Navigated to a new url, reset current page translation.
84 ResetPage();
[email protected]e5a7a2a2014-03-27 16:16:0385}
86
[email protected]ae7581992014-06-25 21:31:4487void TranslateHelper::PageCaptured(const base::string16& contents) {
[email protected]256897732012-10-16 19:35:0588 // Get the document language as set by WebKit from the http-equiv
89 // meta tag for "content-language". This may or may not also
90 // have a value derived from the actual Content-Language HTTP
91 // header. The two actually have different meanings (despite the
92 // original intent of http-equiv to be an equivalent) with the former
93 // being the language of the document and the latter being the
94 // language of the intended audience (a distinction really only
95 // relevant for things like langauge textbooks). This distinction
96 // shouldn't affect translation.
dglazkov24814772015-09-25 22:27:4797 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
leon.han3134fc62016-08-10 07:25:5898 if (!main_frame)
[email protected]effa54c2013-05-28 11:14:2399 return;
[email protected]e5a7a2a2014-03-27 16:16:03100
Blink Reformat1c4d759e2017-04-09 16:34:54101 WebDocument document = main_frame->GetDocument();
adithyas5e615282017-01-17 21:27:01102 WebLanguageDetectionDetails web_detection_details =
Blink Reformat1c4d759e2017-04-09 16:34:54103 WebLanguageDetectionDetails::CollectLanguageDetectionDetails(document);
104 std::string content_language = web_detection_details.content_language.Utf8();
105 std::string html_lang = web_detection_details.html_language.Utf8();
[email protected]27eff892013-05-21 16:40:52106 std::string cld_language;
107 bool is_cld_reliable;
drogerf1da1802014-09-17 14:54:05108 std::string language = DeterminePageLanguage(
[email protected]effa54c2013-05-28 11:14:23109 content_language, html_lang, contents, &cld_language, &is_cld_reliable);
[email protected]27eff892013-05-21 16:40:52110
111 if (language.empty())
112 return;
[email protected]93b9d692011-04-13 00:44:31113
[email protected]0f6afb42013-05-17 03:44:47114 language_determined_time_ = base::TimeTicks::Now();
115
drogerf1da1802014-09-17 14:54:05116 LanguageDetectionDetails details;
[email protected]27eff892013-05-21 16:40:52117 details.time = base::Time::Now();
adithyas5e615282017-01-17 21:27:01118 details.url = web_detection_details.url;
[email protected]27eff892013-05-21 16:40:52119 details.content_language = content_language;
120 details.cld_language = cld_language;
121 details.is_cld_reliable = is_cld_reliable;
Blink Reformat1c4d759e2017-04-09 16:34:54122 details.has_notranslate = web_detection_details.has_no_translate_meta;
[email protected]20efbf2f2013-05-31 06:42:37123 details.html_root_language = html_lang;
[email protected]27eff892013-05-21 16:40:52124 details.adopted_language = language;
125
[email protected]d861d972013-05-30 06:02:31126 // TODO(hajimehoshi): If this affects performance, it should be set only if
127 // translate-internals tab exists.
128 details.contents = contents;
129
leon.han3134fc62016-08-10 07:25:58130 // For the same render frame with the same url, each time when its texts are
131 // captured, it should be treated as a new page to do translation.
leon.hanb07801312016-08-12 11:47:57132 ResetPage();
Ken Rockot1caed9e2017-06-07 17:35:19133 mojom::PagePtr page;
134 binding_.Bind(mojo::MakeRequest(&page));
Michael Martis088a00a2018-04-12 09:33:05135 GetTranslateHandler()->RegisterPage(
Ken Rockot1caed9e2017-06-07 17:35:19136 std::move(page), details, !details.has_notranslate && !language.empty());
[email protected]93b9d692011-04-13 00:44:31137}
138
[email protected]d64b07b2010-04-20 22:14:06139void TranslateHelper::CancelPendingTranslation() {
[email protected]81c9c662011-10-12 04:27:01140 weak_method_factory_.InvalidateWeakPtrs();
leon.han3134fc62016-08-10 07:25:58141 // Make sure to send the cancelled response back.
142 if (translate_callback_pending_) {
tzik9a17d7af2017-05-09 14:21:58143 std::move(translate_callback_pending_)
144 .Run(true, source_lang_, target_lang_, TranslateErrors::NONE);
leon.han3134fc62016-08-10 07:25:58145 }
[email protected]d64b07b2010-04-20 22:14:06146 source_lang_.clear();
147 target_lang_.clear();
148}
149
[email protected]85d252e2010-04-06 22:21:02150////////////////////////////////////////////////////////////////////////////////
151// TranslateHelper, protected:
[email protected]85d252e2010-04-06 22:21:02152bool TranslateHelper::IsTranslateLibAvailable() {
[email protected]0dfc0e52013-04-15 14:53:00153 return ExecuteScriptAndGetBoolResult(
[email protected]85d252e2010-04-06 22:21:02154 "typeof cr != 'undefined' && typeof cr.googleTranslate != 'undefined' && "
[email protected]0dfc0e52013-04-15 14:53:00155 "typeof cr.googleTranslate.translate == 'function'", false);
[email protected]85d252e2010-04-06 22:21:02156}
157
158bool TranslateHelper::IsTranslateLibReady() {
[email protected]0dfc0e52013-04-15 14:53:00159 return ExecuteScriptAndGetBoolResult("cr.googleTranslate.libReady", false);
[email protected]85d252e2010-04-06 22:21:02160}
161
162bool TranslateHelper::HasTranslationFinished() {
[email protected]0dfc0e52013-04-15 14:53:00163 return ExecuteScriptAndGetBoolResult("cr.googleTranslate.finished", true);
[email protected]85d252e2010-04-06 22:21:02164}
165
166bool TranslateHelper::HasTranslationFailed() {
[email protected]0dfc0e52013-04-15 14:53:00167 return ExecuteScriptAndGetBoolResult("cr.googleTranslate.error", true);
[email protected]85d252e2010-04-06 22:21:02168}
169
gajendra.n5bcb90a2017-07-05 09:02:52170int64_t TranslateHelper::GetErrorCode() {
171 int64_t error_code =
172 ExecuteScriptAndGetIntegerResult("cr.googleTranslate.errorCode");
173 DCHECK_LT(error_code, static_cast<int>(TranslateErrors::TRANSLATE_ERROR_MAX));
174 return error_code;
175}
176
[email protected]d64b07b2010-04-20 22:14:06177bool TranslateHelper::StartTranslation() {
Jon Nappera7dc1b002017-06-26 01:01:21178 return ExecuteScriptAndGetBoolResult(
179 BuildTranslationScript(source_lang_, target_lang_), false);
[email protected]85d252e2010-04-06 22:21:02180}
181
[email protected]d64b07b2010-04-20 22:14:06182std::string TranslateHelper::GetOriginalPageLanguage() {
[email protected]0dfc0e52013-04-15 14:53:00183 return ExecuteScriptAndGetStringResult("cr.googleTranslate.sourceLang");
[email protected]d64b07b2010-04-20 22:14:06184}
185
[email protected]0dfc0e52013-04-15 14:53:00186base::TimeDelta TranslateHelper::AdjustDelay(int delayInMs) {
187 // Just converts |delayInMs| without any modification in practical cases.
188 // Tests will override this function to return modified value.
189 return base::TimeDelta::FromMilliseconds(delayInMs);
[email protected]e4be2dd2010-12-14 00:44:39190}
191
[email protected]e0be00992013-04-26 13:15:29192void TranslateHelper::ExecuteScript(const std::string& script) {
dglazkov24814772015-09-25 22:27:47193 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]afa9cd922013-07-30 06:12:19194 if (!main_frame)
195 return;
196
Blink Reformat1c4d759e2017-04-09 16:34:54197 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06198 main_frame->ExecuteScriptInIsolatedWorld(world_id_, source);
[email protected]e0be00992013-04-26 13:15:29199}
200
201bool TranslateHelper::ExecuteScriptAndGetBoolResult(const std::string& script,
202 bool fallback) {
dglazkov24814772015-09-25 22:27:47203 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]e0be00992013-04-26 13:15:29204 if (!main_frame)
205 return fallback;
206
[email protected]dc3d06e2013-09-06 12:21:03207 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
Blink Reformat1c4d759e2017-04-09 16:34:54208 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06209 v8::Local<v8::Value> result =
210 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source);
211 if (result.IsEmpty() || !result->IsBoolean()) {
[email protected]e0be00992013-04-26 13:15:29212 NOTREACHED();
213 return fallback;
214 }
215
Hiroshige Hayashizakie1352e62018-05-14 23:03:06216 return result->BooleanValue();
[email protected]e0be00992013-04-26 13:15:29217}
218
219std::string TranslateHelper::ExecuteScriptAndGetStringResult(
220 const std::string& script) {
dglazkov24814772015-09-25 22:27:47221 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]e0be00992013-04-26 13:15:29222 if (!main_frame)
223 return std::string();
224
Dan Elphickc027e8ae2018-07-27 10:10:10225 v8::Isolate* isolate = v8::Isolate::GetCurrent();
226 v8::HandleScope handle_scope(isolate);
Blink Reformat1c4d759e2017-04-09 16:34:54227 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06228 v8::Local<v8::Value> result =
229 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source);
230 if (result.IsEmpty() || !result->IsString()) {
[email protected]e0be00992013-04-26 13:15:29231 NOTREACHED();
232 return std::string();
233 }
234
Hiroshige Hayashizakie1352e62018-05-14 23:03:06235 v8::Local<v8::String> v8_str = result.As<v8::String>();
Dan Elphickc027e8ae2018-07-27 10:10:10236 int length = v8_str->Utf8Length(isolate) + 1;
danakj396f876c2016-04-22 23:04:39237 std::unique_ptr<char[]> str(new char[length]);
Dan Elphickc027e8ae2018-07-27 10:10:10238 v8_str->WriteUtf8(isolate, str.get(), length);
[email protected]e0be00992013-04-26 13:15:29239 return std::string(str.get());
240}
241
242double TranslateHelper::ExecuteScriptAndGetDoubleResult(
243 const std::string& script) {
dglazkov24814772015-09-25 22:27:47244 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
[email protected]e0be00992013-04-26 13:15:29245 if (!main_frame)
246 return 0.0;
247
[email protected]dc3d06e2013-09-06 12:21:03248 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
Blink Reformat1c4d759e2017-04-09 16:34:54249 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06250 v8::Local<v8::Value> result =
251 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source);
252 if (result.IsEmpty() || !result->IsNumber()) {
[email protected]e0be00992013-04-26 13:15:29253 NOTREACHED();
254 return 0.0;
255 }
256
Hiroshige Hayashizakie1352e62018-05-14 23:03:06257 return result->NumberValue();
[email protected]e0be00992013-04-26 13:15:29258}
259
gajendra.n5bcb90a2017-07-05 09:02:52260int64_t TranslateHelper::ExecuteScriptAndGetIntegerResult(
261 const std::string& script) {
262 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
263 if (!main_frame)
264 return 0;
265
266 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
gajendra.n5bcb90a2017-07-05 09:02:52267 WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
Hiroshige Hayashizakie1352e62018-05-14 23:03:06268 v8::Local<v8::Value> result =
269 main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source);
270 if (result.IsEmpty() || !result->IsNumber()) {
gajendra.n5bcb90a2017-07-05 09:02:52271 NOTREACHED();
272 return 0;
273 }
274
Hiroshige Hayashizakie1352e62018-05-14 23:03:06275 return result->IntegerValue();
gajendra.n5bcb90a2017-07-05 09:02:52276}
277
leon.han3134fc62016-08-10 07:25:58278// mojom::Page implementations.
279void TranslateHelper::Translate(const std::string& translate_script,
280 const std::string& source_lang,
281 const std::string& target_lang,
tzik9a17d7af2017-05-09 14:21:58282 TranslateCallback callback) {
dglazkov24814772015-09-25 22:27:47283 WebLocalFrame* main_frame = render_frame()->GetWebFrame();
leon.han3134fc62016-08-10 07:25:58284 if (!main_frame) {
285 // Cancelled.
tzik9a17d7af2017-05-09 14:21:58286 std::move(callback).Run(true, source_lang, target_lang,
287 TranslateErrors::NONE);
[email protected]81273622011-02-02 03:56:13288 return; // We navigated away, nothing to do.
leon.han3134fc62016-08-10 07:25:58289 }
[email protected]81273622011-02-02 03:56:13290
[email protected]4a2387e2013-05-31 03:47:56291 // A similar translation is already under way, nothing to do.
leon.han3134fc62016-08-10 07:25:58292 if (translate_callback_pending_ && target_lang_ == target_lang) {
293 // This request is ignored.
tzik9a17d7af2017-05-09 14:21:58294 std::move(callback).Run(true, source_lang, target_lang,
295 TranslateErrors::NONE);
[email protected]81273622011-02-02 03:56:13296 return;
leon.han3134fc62016-08-10 07:25:58297 }
[email protected]81273622011-02-02 03:56:13298
299 // Any pending translation is now irrelevant.
300 CancelPendingTranslation();
301
302 // Set our states.
tzik9a17d7af2017-05-09 14:21:58303 translate_callback_pending_ = std::move(callback);
[email protected]4a2387e2013-05-31 03:47:56304
[email protected]81273622011-02-02 03:56:13305 // If the source language is undetermined, we'll let the translate element
306 // detect it.
drogerf1da1802014-09-17 14:54:05307 source_lang_ = (source_lang != kUnknownLanguageCode) ? source_lang
308 : kAutoDetectionLanguage;
[email protected]81273622011-02-02 03:56:13309 target_lang_ = target_lang;
310
drogerf1da1802014-09-17 14:54:05311 ReportUserActionDuration(language_determined_time_, base::TimeTicks::Now());
[email protected]0f6afb42013-05-17 03:44:47312
Blink Reformat1c4d759e2017-04-09 16:34:54313 GURL url(main_frame->GetDocument().Url());
drogerf1da1802014-09-17 14:54:05314 ReportPageScheme(url.scheme());
[email protected]595ec512013-05-23 16:40:30315
[email protected]afa9cd922013-07-30 06:12:19316 // Set up v8 isolated world with proper content-security-policy and
317 // security-origin.
Blink Reformat1c4d759e2017-04-09 16:34:54318 main_frame->SetIsolatedWorldContentSecurityPolicy(
319 world_id_, WebString::FromUTF8(kContentSecurityPolicy));
[email protected]afa9cd922013-07-30 06:12:19320
dglazkov24814772015-09-25 22:27:47321 GURL security_origin = GetTranslateSecurityOrigin();
Blink Reformat1c4d759e2017-04-09 16:34:54322 main_frame->SetIsolatedWorldSecurityOrigin(
323 world_id_, WebSecurityOrigin::Create(security_origin));
[email protected]afa9cd922013-07-30 06:12:19324
[email protected]81273622011-02-02 03:56:13325 if (!IsTranslateLibAvailable()) {
326 // Evaluate the script to add the translation related method to the global
327 // context of the page.
328 ExecuteScript(translate_script);
329 DCHECK(IsTranslateLibAvailable());
330 }
331
leon.han3134fc62016-08-10 07:25:58332 TranslatePageImpl(0);
[email protected]81273622011-02-02 03:56:13333}
334
leon.han3134fc62016-08-10 07:25:58335void TranslateHelper::RevertTranslation() {
[email protected]81273622011-02-02 03:56:13336 if (!IsTranslateLibAvailable()) {
337 NOTREACHED();
338 return;
339 }
340
[email protected]81273622011-02-02 03:56:13341 CancelPendingTranslation();
342
[email protected]0dfc0e52013-04-15 14:53:00343 ExecuteScript("cr.googleTranslate.revert()");
[email protected]81273622011-02-02 03:56:13344}
345
leon.han3134fc62016-08-10 07:25:58346////////////////////////////////////////////////////////////////////////////////
347// TranslateHelper, private:
348void TranslateHelper::CheckTranslateStatus() {
[email protected]85d252e2010-04-06 22:21:02349 // First check if there was an error.
350 if (HasTranslationFailed()) {
gajendra.n5bcb90a2017-07-05 09:02:52351 NotifyBrowserTranslationFailed(
352 static_cast<translate::TranslateErrors::Type>(GetErrorCode()));
[email protected]85d252e2010-04-06 22:21:02353 return; // There was an error.
354 }
355
356 if (HasTranslationFinished()) {
[email protected]d64b07b2010-04-20 22:14:06357 std::string actual_source_lang;
358 // Translation was successfull, if it was auto, retrieve the source
359 // language the Translate Element detected.
360 if (source_lang_ == kAutoDetectionLanguage) {
361 actual_source_lang = GetOriginalPageLanguage();
362 if (actual_source_lang.empty()) {
drogerf1da1802014-09-17 14:54:05363 NotifyBrowserTranslationFailed(TranslateErrors::UNKNOWN_LANGUAGE);
[email protected]579317e2010-06-30 20:13:48364 return;
365 } else if (actual_source_lang == target_lang_) {
drogerf1da1802014-09-17 14:54:05366 NotifyBrowserTranslationFailed(TranslateErrors::IDENTICAL_LANGUAGES);
[email protected]d64b07b2010-04-20 22:14:06367 return;
368 }
369 } else {
370 actual_source_lang = source_lang_;
371 }
372
leon.han3134fc62016-08-10 07:25:58373 if (!translate_callback_pending_) {
[email protected]d64b07b2010-04-20 22:14:06374 NOTREACHED();
375 return;
376 }
377
[email protected]e0be00992013-04-26 13:15:29378 // Check JavaScript performance counters for UMA reports.
drogerf1da1802014-09-17 14:54:05379 ReportTimeToTranslate(
[email protected]3a2ea8f2013-05-13 18:40:15380 ExecuteScriptAndGetDoubleResult("cr.googleTranslate.translationTime"));
[email protected]e0be00992013-04-26 13:15:29381
[email protected]d64b07b2010-04-20 22:14:06382 // Notify the browser we are done.
tzik9a17d7af2017-05-09 14:21:58383 std::move(translate_callback_pending_)
384 .Run(false, actual_source_lang, target_lang_, TranslateErrors::NONE);
[email protected]85d252e2010-04-06 22:21:02385 return;
386 }
387
388 // The translation is still pending, check again later.
skyostilb0daa012015-06-02 19:03:48389 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15390 FROM_HERE,
391 base::BindOnce(&TranslateHelper::CheckTranslateStatus,
392 weak_method_factory_.GetWeakPtr()),
[email protected]0dfc0e52013-04-15 14:53:00393 AdjustDelay(kTranslateStatusCheckDelayMs));
[email protected]85d252e2010-04-06 22:21:02394}
395
leon.han3134fc62016-08-10 07:25:58396void TranslateHelper::TranslatePageImpl(int count) {
[email protected]85d252e2010-04-06 22:21:02397 DCHECK_LT(count, kMaxTranslateInitCheckAttempts);
[email protected]85d252e2010-04-06 22:21:02398 if (!IsTranslateLibReady()) {
gajendra.n5bcb90a2017-07-05 09:02:52399 // There was an error during initialization of library.
400 TranslateErrors::Type error =
401 static_cast<translate::TranslateErrors::Type>(GetErrorCode());
402 if (error != TranslateErrors::NONE) {
403 NotifyBrowserTranslationFailed(error);
404 return;
405 }
406
[email protected]85d252e2010-04-06 22:21:02407 // The library is not ready, try again later, unless we have tried several
thestig259626c2015-11-23 20:18:11408 // times unsuccessfully already.
[email protected]85d252e2010-04-06 22:21:02409 if (++count >= kMaxTranslateInitCheckAttempts) {
gajendra.n5bcb90a2017-07-05 09:02:52410 NotifyBrowserTranslationFailed(TranslateErrors::TRANSLATION_TIMEOUT);
[email protected]85d252e2010-04-06 22:21:02411 return;
412 }
skyostilb0daa012015-06-02 19:03:48413 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15414 FROM_HERE,
415 base::BindOnce(&TranslateHelper::TranslatePageImpl,
416 weak_method_factory_.GetWeakPtr(), count),
[email protected]0dfc0e52013-04-15 14:53:00417 AdjustDelay(count * kTranslateInitCheckDelayMs));
[email protected]85d252e2010-04-06 22:21:02418 return;
419 }
420
[email protected]e0be00992013-04-26 13:15:29421 // The library is loaded, and ready for translation now.
422 // Check JavaScript performance counters for UMA reports.
drogerf1da1802014-09-17 14:54:05423 ReportTimeToBeReady(
[email protected]3a2ea8f2013-05-13 18:40:15424 ExecuteScriptAndGetDoubleResult("cr.googleTranslate.readyTime"));
drogerf1da1802014-09-17 14:54:05425 ReportTimeToLoad(
[email protected]3a2ea8f2013-05-13 18:40:15426 ExecuteScriptAndGetDoubleResult("cr.googleTranslate.loadTime"));
[email protected]e0be00992013-04-26 13:15:29427
[email protected]d64b07b2010-04-20 22:14:06428 if (!StartTranslation()) {
gajendra.n5bcb90a2017-07-05 09:02:52429 CheckTranslateStatus();
[email protected]85d252e2010-04-06 22:21:02430 return;
431 }
432 // Check the status of the translation.
skyostilb0daa012015-06-02 19:03:48433 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15434 FROM_HERE,
435 base::BindOnce(&TranslateHelper::CheckTranslateStatus,
436 weak_method_factory_.GetWeakPtr()),
[email protected]0dfc0e52013-04-15 14:53:00437 AdjustDelay(kTranslateStatusCheckDelayMs));
[email protected]85d252e2010-04-06 22:21:02438}
439
440void TranslateHelper::NotifyBrowserTranslationFailed(
drogerf1da1802014-09-17 14:54:05441 TranslateErrors::Type error) {
leon.han3134fc62016-08-10 07:25:58442 DCHECK(translate_callback_pending_);
[email protected]85d252e2010-04-06 22:21:02443 // Notify the browser there was an error.
tzik9a17d7af2017-05-09 14:21:58444 std::move(translate_callback_pending_)
445 .Run(false, source_lang_, target_lang_, error);
leon.han3134fc62016-08-10 07:25:58446}
447
Michael Martis088a00a2018-04-12 09:33:05448const mojom::ContentTranslateDriverPtr& TranslateHelper::GetTranslateHandler() {
449 if (!translate_handler_) {
leon.han3134fc62016-08-10 07:25:58450 render_frame()->GetRemoteInterfaces()->GetInterface(
Michael Martis088a00a2018-04-12 09:33:05451 mojo::MakeRequest(&translate_handler_));
leon.han3134fc62016-08-10 07:25:58452 }
453
Michael Martis088a00a2018-04-12 09:33:05454 return translate_handler_;
[email protected]7faa53862010-06-16 00:09:13455}
[email protected]e5a7a2a2014-03-27 16:16:03456
leon.hanb07801312016-08-12 11:47:57457void TranslateHelper::ResetPage() {
458 binding_.Close();
459 translate_callback_pending_.Reset();
460 CancelPendingTranslation();
461}
462
xjz694b50a92016-06-07 21:49:37463void TranslateHelper::OnDestruct() {
464 delete this;
465}
466
Jon Nappera7dc1b002017-06-26 01:01:21467/* static */
468std::string TranslateHelper::BuildTranslationScript(
469 const std::string& source_lang,
470 const std::string& target_lang) {
471 return "cr.googleTranslate.translate(" +
472 base::GetQuotedJSONString(source_lang) + "," +
473 base::GetQuotedJSONString(target_lang) + ")";
474}
475
drogerf1da1802014-09-17 14:54:05476} // namespace translate