Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / components / translate / core / browser / resources / translate.js
blobfb59e6601b97f3558e04db5dab758d9b98149dec
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 // This code is used in conjunction with the Google Translate Element script.
6 // It is executed in an isolated world of a page to translate it from one
7 // language to another.
8 // It should be included in the page before the Translate Element script.
10 var cr = cr || {};
12 /**
13 * An object to provide functions to interact with the Translate library.
14 * @type {object}
16 cr.googleTranslate = (function() {
17 /**
18 * The Translate Element library's instance.
19 * @type {object}
21 var lib;
23 /**
24 * A flag representing if the Translate Element library is initialized.
25 * @type {boolean}
27 var libReady = false;
29 /**
30 * Error definitions for |errorCode|. See chrome/common/translate_errors.h
31 * to modify the definition.
32 * @const
34 var ERROR = {
35 'NONE': 0,
36 'INITIALIZATION_ERROR': 2,
37 'UNSUPPORTED_LANGUAGE': 4,
38 'TRANSLATION_ERROR': 6,
39 'TRANSLATION_TIMEOUT': 7,
40 'UNEXPECTED_SCRIPT_ERROR': 8,
41 'BAD_ORIGIN': 9,
42 'SCRIPT_LOAD_ERROR': 10
45 /**
46 * Error code map from te.dom.DomTranslator.Error to |errorCode|.
47 * See also go/dom_translator.js in google3.
48 * @const
50 var TRANSLATE_ERROR_TO_ERROR_CODE_MAP = {
51 0: ERROR['NONE'],
52 1: ERROR['TRANSLATION_ERROR'],
53 2: ERROR['UNSUPPORTED_LANGUAGE']
56 /**
57 * An error code happened in translate.js and the Translate Element library.
59 var errorCode = ERROR['NONE'];
61 /**
62 * A flag representing if the Translate Element has finished a translation.
63 * @type {boolean}
65 var finished = false;
67 /**
68 * Counts how many times the checkLibReady function is called. The function
69 * is called in every 100 msec and counted up to 6.
70 * @type {number}
72 var checkReadyCount = 0;
74 /**
75 * Time in msec when this script is injected.
76 * @type {number}
78 var injectedTime = performance.now();
80 /**
81 * Time in msec when the Translate Element library is loaded completely.
82 * @type {number}
84 var loadedTime = 0.0;
86 /**
87 * Time in msec when the Translate Element library is initialized and ready
88 * for performing translation.
89 * @type {number}
91 var readyTime = 0.0;
93 /**
94 * Time in msec when the Translate Element library starts a translation.
95 * @type {number}
97 var startTime = 0.0;
99 /**
100 * Time in msec when the Translate Element library ends a translation.
101 * @type {number}
103 var endTime = 0.0;
105 function checkLibReady() {
106 if (lib.isAvailable()) {
107 readyTime = performance.now();
108 libReady = true;
109 return;
111 if (checkReadyCount++ > 5) {
112 errorCode = ERROR['TRANSLATION_TIMEOUT'];
113 return;
115 setTimeout(checkLibReady, 100);
118 function onTranslateProgress(progress, opt_finished, opt_error) {
119 finished = opt_finished;
120 // opt_error can be 'undefined'.
121 if (typeof opt_error == 'boolean' && opt_error) {
122 // TODO(toyoshim): Remove boolean case once a server is updated.
123 errorCode = ERROR['TRANSLATION_ERROR'];
124 // We failed to translate, restore so the page is in a consistent state.
125 lib.restore();
126 } else if (typeof opt_error == 'number' && opt_error != 0) {
127 errorCode = TRANSLATE_ERROR_TO_ERROR_CODE_MAP[opt_error];
128 lib.restore();
130 if (finished)
131 endTime = performance.now();
134 // Public API.
135 return {
137 * Whether the library is ready.
138 * The translate function should only be called when |libReady| is true.
139 * @type {boolean}
141 get libReady() {
142 return libReady;
146 * Whether the current translate has finished successfully.
147 * @type {boolean}
149 get finished() {
150 return finished;
154 * Whether an error occured initializing the library of translating the
155 * page.
156 * @type {boolean}
158 get error() {
159 return errorCode != ERROR['NONE'];
163 * Returns a number to represent error type.
164 * @type {number}
166 get errorCode() {
167 return errorCode;
171 * The language the page translated was in. Is valid only after the page
172 * has been successfully translated and the original language specified to
173 * the translate function was 'auto'. Is empty otherwise.
174 * Some versions of Element library don't provide |getDetectedLanguage|
175 * function. In that case, this function returns 'und'.
176 * @type {boolean}
178 get sourceLang() {
179 if (!libReady || !finished || errorCode != ERROR['NONE'])
180 return '';
181 if (!lib.getDetectedLanguage)
182 return 'und'; // Defined as translate::kUnknownLanguageCode in C++.
183 return lib.getDetectedLanguage();
187 * Time in msec from this script being injected to all server side scripts
188 * being loaded.
189 * @type {number}
191 get loadTime() {
192 if (loadedTime == 0)
193 return 0;
194 return loadedTime - injectedTime;
198 * Time in msec from this script being injected to the Translate Element
199 * library being ready.
200 * @type {number}
202 get readyTime() {
203 if (!libReady)
204 return 0;
205 return readyTime - injectedTime;
209 * Time in msec to perform translation.
210 * @type {number}
212 get translationTime() {
213 if (!finished)
214 return 0;
215 return endTime - startTime;
219 * Translate the page contents. Note that the translation is asynchronous.
220 * You need to regularly check the state of |finished| and |errorCode| to
221 * know if the translation finished or if there was an error.
222 * @param {string} originalLang The language the page is in.
223 * @param {string} targetLang The language the page should be translated to.
224 * @return {boolean} False if the translate library was not ready, in which
225 * case the translation is not started. True otherwise.
227 translate: function(originalLang, targetLang) {
228 finished = false;
229 errorCode = ERROR['NONE'];
230 if (!libReady)
231 return false;
232 startTime = performance.now();
233 try {
234 lib.translatePage(originalLang, targetLang, onTranslateProgress);
235 } catch (err) {
236 console.error('Translate: ' + err);
237 errorCode = ERROR['UNEXPECTED_SCRIPT_ERROR'];
238 return false;
240 return true;
244 * Reverts the page contents to its original value, effectively reverting
245 * any performed translation. Does nothing if the page was not translated.
247 revert: function() {
248 lib.restore();
252 * Entry point called by the Translate Element once it has been injected in
253 * the page.
255 onTranslateElementLoad: function() {
256 loadedTime = performance.now();
257 try {
258 lib = google.translate.TranslateService({
259 // translateApiKey is predefined by translate_script.cc.
260 'key': translateApiKey,
261 'useSecureConnection': true
263 translateApiKey = undefined;
264 } catch (err) {
265 errorCode = ERROR['INITIALIZATION_ERROR'];
266 translateApiKey = undefined;
267 return;
269 // The TranslateService is not available immediately as it needs to start
270 // Flash. Let's wait until it is ready.
271 checkLibReady();
275 * Entry point called by the Translate Element when it want to load an
276 * external CSS resource into the page.
277 * @param {string} url URL of an external CSS resource to load.
279 onLoadCSS: function(url) {
280 var element = document.createElement('link');
281 element.type = 'text/css';
282 element.rel = 'stylesheet';
283 element.charset = 'UTF-8';
284 element.href = url;
285 document.head.appendChild(element);
289 * Entry point called by the Translate Element when it want to load and run
290 * an external JavaScript on the page.
291 * @param {string} url URL of an external JavaScript to load.
293 onLoadJavascript: function(url) {
294 // securityOrigin is predefined by translate_script.cc.
295 if (url.indexOf(securityOrigin) != 0) {
296 console.error('Translate: ' + url + ' is not allowed to load.');
297 errorCode = ERROR['BAD_ORIGIN'];
298 return;
300 var xhr = new XMLHttpRequest();
301 xhr.open('GET', url, true);
302 xhr.onreadystatechange = function() {
303 if (this.readyState != this.DONE)
304 return;
305 if (this.status != 200) {
306 errorCode = ERROR['SCRIPT_LOAD_ERROR'];
307 return;
309 eval(this.responseText);
311 xhr.send();
314 })();