Home | History | Annotate | Download | only in resources
      1 // Copyright (c) 2012 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.
      4 
      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.
      9 
     10 var cr = {};
     11 
     12 cr.googleTranslate = (function(key) {
     13   /**
     14    * The Translate Element library's instance.
     15    * @type {object}
     16    */
     17   var lib;
     18 
     19   /**
     20    * A flag representing if the Translate Element library is initialized.
     21    * @type {boolean}
     22    */
     23   var libReady = false;
     24 
     25   /**
     26    * A flag representing if the Translate Element library returns error while
     27    * performing translation. Also it is set to true when the Translate Element
     28    * library is not initialized in 600 msec from the library is loaded.
     29    * @type {boolean}
     30    */
     31   var error = false;
     32 
     33   /**
     34    * A flag representing if the Translate Element has finished a translation.
     35    * @type {boolean}
     36    */
     37   var finished = false;
     38 
     39   /**
     40    * Counts how many times the checkLibReady function is called. The function
     41    * is called in every 100 msec and counted up to 6.
     42    * @type {number}
     43    */
     44   var checkReadyCount = 0;
     45 
     46   /**
     47    * Time in msec when this script is injected.
     48    * @type {number}
     49    */
     50   var injectedTime = performance.now();
     51 
     52   /**
     53    * Time in msec when the Translate Element library is loaded completely.
     54    * @type {number}
     55    */
     56   var loadedTime = 0.0;
     57 
     58   /**
     59    * Time in msec when the Translate Element library is initialized and ready
     60    * for performing translation.
     61    * @type {number}
     62    */
     63   var readyTime = 0.0;
     64 
     65   /**
     66    * Time in msec when the Translate Element library starts a translation.
     67    * @type {number}
     68    */
     69   var startTime = 0.0;
     70 
     71   /**
     72    * Time in msec when the Translate Element library ends a translation.
     73    * @type {number}
     74    */
     75   var endTime = 0.0;
     76 
     77   // Create another call point for appendChild.
     78   var head = document.head;
     79   head._appendChild = head.appendChild;
     80 
     81   // TODO(toyoshim): This is temporary solution and will be removed once server
     82   // side fixed to use https always. See also, http://crbug.com/164584 .
     83   function forceToHttps(url) {
     84     if (url.indexOf('http:') == 0)
     85       return url.replace('http', 'https');
     86 
     87     return url;
     88   }
     89 
     90   /**
     91    * Inserts CSS element into the main world.
     92    * @param {Object} child Link element for CSS.
     93    */
     94   function insertCSS(child) {
     95     child.href = forceToHttps(child.href);
     96     head._appendChild(child);
     97   }
     98 
     99   /**
    100    * Inserts JavaScript into the isolated world.
    101    * @param {string} src JavaScript URL.
    102    */
    103   function insertJS(src) {
    104     var xhr = new XMLHttpRequest();
    105     xhr.open('GET', forceToHttps(src), true);
    106     xhr.onreadystatechange = function() {
    107       if (this.readyState != this.DONE || this.status != 200)
    108         return;
    109       eval(this.responseText);
    110     }
    111     xhr.send();
    112   }
    113 
    114   /**
    115    * Alternate implementation of appendChild. In the isolated world, appendChild
    116    * for the first head element is replaced with this function in order to make
    117    * CSS link tag and script tag injection work fine like the main world.
    118    */
    119   head.appendChild = function(child) {
    120     if (child.type == 'text/css')
    121       insertCSS(child);
    122     else
    123       insertJS(child.src);
    124   };
    125 
    126   function checkLibReady() {
    127     if (lib.isAvailable()) {
    128       readyTime = performance.now();
    129       libReady = true;
    130       return;
    131     }
    132     if (checkReadyCount++ > 5) {
    133       error = true;
    134       return;
    135     }
    136     setTimeout(checkLibReady, 100);
    137   }
    138 
    139   function onTranslateProgress(progress, opt_finished, opt_error) {
    140     finished = opt_finished;
    141     // opt_error can be 'undefined'.
    142     if (typeof opt_error == 'boolean' && opt_error) {
    143       error = true;
    144       // We failed to translate, restore so the page is in a consistent state.
    145       lib.restore();
    146     }
    147     if (finished)
    148       endTime = performance.now();
    149   }
    150 
    151   // Public API.
    152   return {
    153     /**
    154      * Whether the library is ready.
    155      * The translate function should only be called when |libReady| is true.
    156      * @type {boolean}
    157      */
    158     get libReady() {
    159       return libReady;
    160     },
    161 
    162     /**
    163      * Whether the current translate has finished successfully.
    164      * @type {boolean}
    165      */
    166     get finished() {
    167       return finished;
    168     },
    169 
    170     /**
    171      * Whether an error occured initializing the library of translating the
    172      * page.
    173      * @type {boolean}
    174      */
    175     get error() {
    176       return error;
    177     },
    178 
    179     /**
    180      * The language the page translated was in. Is valid only after the page
    181      * has been successfully translated and the original language specified to
    182      * the translate function was 'auto'. Is empty otherwise.
    183      * Some versions of Element library don't provide |getDetectedLanguage|
    184      * function. In that case, this function returns 'und'.
    185      * @type {boolean}
    186      */
    187     get sourceLang() {
    188       if (!libReady || !finished || error)
    189         return '';
    190       if (!lib.getDetectedLanguage)
    191         return 'und'; // defined as chrome::kUnknownLanguageCode in C++ world.
    192       return lib.getDetectedLanguage();
    193     },
    194 
    195     /**
    196      * Time in msec from this script being injected to all server side scripts
    197      * being loaded.
    198      * @type {number}
    199      */
    200     get loadTime() {
    201       if (loadedTime == 0)
    202         return 0;
    203       return loadedTime - injectedTime;
    204     },
    205 
    206     /**
    207      * Time in msec from this script being injected to the Translate Element
    208      * library being ready.
    209      * @type {number}
    210      */
    211     get readyTime() {
    212       if (!libReady)
    213         return 0;
    214       return readyTime - injectedTime;
    215     },
    216 
    217     /**
    218      * Time in msec to perform translation.
    219      * @type {number}
    220      */
    221     get translationTime() {
    222       if (!finished)
    223         return 0;
    224       return endTime - startTime;
    225     },
    226 
    227     /**
    228      * Translate the page contents.  Note that the translation is asynchronous.
    229      * You need to regularly check the state of |finished| and |error| to know
    230      * if the translation finished or if there was an error.
    231      * @param {string} originalLang The language the page is in.
    232      * @param {string} targetLang The language the page should be translated to.
    233      * @return {boolean} False if the translate library was not ready, in which
    234      *                   case the translation is not started.  True otherwise.
    235      */
    236     translate: function(originalLang, targetLang) {
    237       finished = false;
    238       error = false;
    239       if (!libReady)
    240         return false;
    241       startTime = performance.now();
    242       lib.translatePage(originalLang, targetLang, onTranslateProgress);
    243       return true;
    244     },
    245 
    246     /**
    247      * Reverts the page contents to its original value, effectively reverting
    248      * any performed translation.  Does nothing if the page was not translated.
    249      */
    250     revert: function() {
    251       lib.restore();
    252     },
    253 
    254     /**
    255      * Entry point called by the Translate Element once it has been injected in
    256      * the page.
    257      */
    258     onTranslateElementLoad: function() {
    259       loadedTime = performance.now();
    260       try {
    261         lib = google.translate.TranslateService({
    262           'key': key,
    263           'useSecureConnection': true
    264         });
    265       } catch (err) {
    266         error = true;
    267         return;
    268       }
    269       // The TranslateService is not available immediately as it needs to start
    270       // Flash.  Let's wait until it is ready.
    271       checkLibReady();
    272     }
    273   };
    274 })/* Calling code '(|key|);' will be appended by TranslateHelper in C++ here. */
    275