| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This code is used in conjunction with the Google Translate Element script. |
| // It is executed in an isolated world of a page to translate it from one |
| // language to another. |
| // It should be included in the page before the Translate Element script. |
| |
| var cr = {}; |
| |
| cr.googleTranslate = (function(key) { |
| /** |
| * The Translate Element library's instance. |
| * @type {object} |
| */ |
| var lib; |
| |
| /** |
| * A flag representing if the Translate Element library is initialized. |
| * @type {boolean} |
| */ |
| var libReady = false; |
| |
| /** |
| * A flag representing if the Translate Element library returns error while |
| * performing translation. Also it is set to true when the Translate Element |
| * library is not initialized in 600 msec from the library is loaded. |
| * @type {boolean} |
| */ |
| var error = false; |
| |
| /** |
| * A flag representing if the Translate Element has finished a translation. |
| * @type {boolean} |
| */ |
| var finished = false; |
| |
| /** |
| * Counts how many times the checkLibReady function is called. The function |
| * is called in every 100 msec and counted up to 6. |
| * @type {number} |
| */ |
| var checkReadyCount = 0; |
| |
| /** |
| * Time in msec when this script is injected. |
| * @type {number} |
| */ |
| var injectedTime = performance.now(); |
| |
| /** |
| * Time in msec when the Translate Element library is loaded completely. |
| * @type {number} |
| */ |
| var loadedTime = 0.0; |
| |
| /** |
| * Time in msec when the Translate Element library is initialized and ready |
| * for performing translation. |
| * @type {number} |
| */ |
| var readyTime = 0.0; |
| |
| /** |
| * Time in msec when the Translate Element library starts a translation. |
| * @type {number} |
| */ |
| var startTime = 0.0; |
| |
| /** |
| * Time in msec when the Translate Element library ends a translation. |
| * @type {number} |
| */ |
| var endTime = 0.0; |
| |
| // Create another call point for appendChild. |
| var head = document.head; |
| head._appendChild = head.appendChild; |
| |
| // TODO(toyoshim): This is temporary solution and will be removed once server |
| // side fixed to use https always. See also, http://crbug.com/164584 . |
| function forceToHttps(url) { |
| if (url.indexOf('http:') == 0) |
| return url.replace('http', 'https'); |
| |
| return url; |
| } |
| |
| /** |
| * Inserts CSS element into the main world. |
| * @param {Object} child Link element for CSS. |
| */ |
| function insertCSS(child) { |
| child.href = forceToHttps(child.href); |
| head._appendChild(child); |
| } |
| |
| /** |
| * Inserts JavaScript into the isolated world. |
| * @param {string} src JavaScript URL. |
| */ |
| function insertJS(src) { |
| var xhr = new XMLHttpRequest(); |
| xhr.open('GET', forceToHttps(src), true); |
| xhr.onreadystatechange = function() { |
| if (this.readyState != this.DONE || this.status != 200) |
| return; |
| eval(this.responseText); |
| } |
| xhr.send(); |
| } |
| |
| /** |
| * Alternate implementation of appendChild. In the isolated world, appendChild |
| * for the first head element is replaced with this function in order to make |
| * CSS link tag and script tag injection work fine like the main world. |
| */ |
| head.appendChild = function(child) { |
| if (child.type == 'text/css') |
| insertCSS(child); |
| else |
| insertJS(child.src); |
| }; |
| |
| function checkLibReady() { |
| if (lib.isAvailable()) { |
| readyTime = performance.now(); |
| libReady = true; |
| return; |
| } |
| if (checkReadyCount++ > 5) { |
| error = true; |
| return; |
| } |
| setTimeout(checkLibReady, 100); |
| } |
| |
| function onTranslateProgress(progress, opt_finished, opt_error) { |
| finished = opt_finished; |
| // opt_error can be 'undefined'. |
| if (typeof opt_error == 'boolean' && opt_error) { |
| error = true; |
| // We failed to translate, restore so the page is in a consistent state. |
| lib.restore(); |
| } |
| if (finished) |
| endTime = performance.now(); |
| } |
| |
| // Public API. |
| return { |
| /** |
| * Whether the library is ready. |
| * The translate function should only be called when |libReady| is true. |
| * @type {boolean} |
| */ |
| get libReady() { |
| return libReady; |
| }, |
| |
| /** |
| * Whether the current translate has finished successfully. |
| * @type {boolean} |
| */ |
| get finished() { |
| return finished; |
| }, |
| |
| /** |
| * Whether an error occured initializing the library of translating the |
| * page. |
| * @type {boolean} |
| */ |
| get error() { |
| return error; |
| }, |
| |
| /** |
| * The language the page translated was in. Is valid only after the page |
| * has been successfully translated and the original language specified to |
| * the translate function was 'auto'. Is empty otherwise. |
| * Some versions of Element library don't provide |getDetectedLanguage| |
| * function. In that case, this function returns 'und'. |
| * @type {boolean} |
| */ |
| get sourceLang() { |
| if (!libReady || !finished || error) |
| return ''; |
| if (!lib.getDetectedLanguage) |
| return 'und'; // defined as chrome::kUnknownLanguageCode in C++ world. |
| return lib.getDetectedLanguage(); |
| }, |
| |
| /** |
| * Time in msec from this script being injected to all server side scripts |
| * being loaded. |
| * @type {number} |
| */ |
| get loadTime() { |
| if (loadedTime == 0) |
| return 0; |
| return loadedTime - injectedTime; |
| }, |
| |
| /** |
| * Time in msec from this script being injected to the Translate Element |
| * library being ready. |
| * @type {number} |
| */ |
| get readyTime() { |
| if (!libReady) |
| return 0; |
| return readyTime - injectedTime; |
| }, |
| |
| /** |
| * Time in msec to perform translation. |
| * @type {number} |
| */ |
| get translationTime() { |
| if (!finished) |
| return 0; |
| return endTime - startTime; |
| }, |
| |
| /** |
| * Translate the page contents. Note that the translation is asynchronous. |
| * You need to regularly check the state of |finished| and |error| to know |
| * if the translation finished or if there was an error. |
| * @param {string} originalLang The language the page is in. |
| * @param {string} targetLang The language the page should be translated to. |
| * @return {boolean} False if the translate library was not ready, in which |
| * case the translation is not started. True otherwise. |
| */ |
| translate: function(originalLang, targetLang) { |
| finished = false; |
| error = false; |
| if (!libReady) |
| return false; |
| startTime = performance.now(); |
| lib.translatePage(originalLang, targetLang, onTranslateProgress); |
| return true; |
| }, |
| |
| /** |
| * Reverts the page contents to its original value, effectively reverting |
| * any performed translation. Does nothing if the page was not translated. |
| */ |
| revert: function() { |
| lib.restore(); |
| }, |
| |
| /** |
| * Entry point called by the Translate Element once it has been injected in |
| * the page. |
| */ |
| onTranslateElementLoad: function() { |
| loadedTime = performance.now(); |
| try { |
| lib = google.translate.TranslateService({ |
| 'key': key, |
| 'useSecureConnection': true |
| }); |
| } catch (err) { |
| error = true; |
| return; |
| } |
| // The TranslateService is not available immediately as it needs to start |
| // Flash. Let's wait until it is ready. |
| checkLibReady(); |
| } |
| }; |
| })/* Calling code '(|key|);' will be appended by TranslateHelper in C++ here. */ |