OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This code is used in conjunction with the Google Translate Element script. | 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 | 6 // It is executed in an isolated world of a page to translate it from one |
7 // language to another. | 7 // language to another. |
8 // It should be included in the page before the Translate Element script. | 8 // It should be included in the page before the Translate Element script. |
9 | 9 |
10 var cr = {}; | 10 var cr = cr || {}; |
11 | 11 |
12 /** | 12 /** |
13 * An object to provide functions to interact with the Translate library. | 13 * An object to provide functions to interact with the Translate library. |
14 * @type {object} | 14 * @type {object} |
15 */ | 15 */ |
16 cr.googleTranslate = (function() { | 16 cr.googleTranslate = (function() { |
17 /** | 17 /** |
18 * The Translate Element library's instance. | 18 * The Translate Element library's instance. |
19 * @type {object} | 19 * @type {object} |
20 */ | 20 */ |
21 var lib; | 21 var lib; |
22 | 22 |
23 /** | 23 /** |
24 * A flag representing if the Translate Element library is initialized. | 24 * A flag representing if the Translate Element library is initialized. |
25 * @type {boolean} | 25 * @type {boolean} |
26 */ | 26 */ |
27 var libReady = false; | 27 var libReady = false; |
28 | 28 |
29 /** | 29 /** |
30 * A flag representing if the Translate Element library returns error while | 30 * Error definitions for |errorCode|. See chrome/common/translate_errors.h |
31 * performing translation. Also it is set to true when the Translate Element | 31 * to modify the definition. |
32 * library is not initialized in 600 msec from the library is loaded. | 32 * @const |
33 * @type {boolean} | |
34 */ | 33 */ |
35 var error = false; | 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 |
| 43 }; |
| 44 |
| 45 /** |
| 46 * Error code map from te.dom.DomTranslator.Error to |errorCode|. |
| 47 * See also go/dom_translator.js in google3. |
| 48 * @const |
| 49 */ |
| 50 var TRANSLATE_ERROR_TO_ERROR_CODE_MAP = { |
| 51 0: ERROR['NONE'], |
| 52 1: ERROR['TRANSLATION_ERROR'], |
| 53 2: ERROR['UNSUPPORTED_LANGUAGE'] |
| 54 }; |
| 55 |
| 56 /** |
| 57 * An error code happened in translate.js and the Translate Element library. |
| 58 */ |
| 59 var errorCode = ERROR['NONE']; |
36 | 60 |
37 /** | 61 /** |
38 * A flag representing if the Translate Element has finished a translation. | 62 * A flag representing if the Translate Element has finished a translation. |
39 * @type {boolean} | 63 * @type {boolean} |
40 */ | 64 */ |
41 var finished = false; | 65 var finished = false; |
42 | 66 |
43 /** | 67 /** |
44 * Counts how many times the checkLibReady function is called. The function | 68 * Counts how many times the checkLibReady function is called. The function |
45 * is called in every 100 msec and counted up to 6. | 69 * is called in every 100 msec and counted up to 6. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 */ | 102 */ |
79 var endTime = 0.0; | 103 var endTime = 0.0; |
80 | 104 |
81 function checkLibReady() { | 105 function checkLibReady() { |
82 if (lib.isAvailable()) { | 106 if (lib.isAvailable()) { |
83 readyTime = performance.now(); | 107 readyTime = performance.now(); |
84 libReady = true; | 108 libReady = true; |
85 return; | 109 return; |
86 } | 110 } |
87 if (checkReadyCount++ > 5) { | 111 if (checkReadyCount++ > 5) { |
88 error = true; | 112 errorCode = ERROR['TRANSLATION_TIMEOUT']; |
89 return; | 113 return; |
90 } | 114 } |
91 setTimeout(checkLibReady, 100); | 115 setTimeout(checkLibReady, 100); |
92 } | 116 } |
93 | 117 |
94 function onTranslateProgress(progress, opt_finished, opt_error) { | 118 function onTranslateProgress(progress, opt_finished, opt_error) { |
95 finished = opt_finished; | 119 finished = opt_finished; |
96 // opt_error can be 'undefined'. | 120 // opt_error can be 'undefined'. |
97 if (typeof opt_error == 'boolean' && opt_error) { | 121 if (typeof opt_error == 'boolean' && opt_error) { |
98 error = true; | 122 // TODO(toyoshim): Remove boolean case once a server is updated. |
| 123 errorCode = ERROR['TRANSLATION_ERROR']; |
99 // We failed to translate, restore so the page is in a consistent state. | 124 // We failed to translate, restore so the page is in a consistent state. |
100 lib.restore(); | 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(); |
101 } | 129 } |
102 if (finished) | 130 if (finished) |
103 endTime = performance.now(); | 131 endTime = performance.now(); |
104 } | 132 } |
105 | 133 |
106 // Public API. | 134 // Public API. |
107 return { | 135 return { |
108 /** | 136 /** |
109 * Whether the library is ready. | 137 * Whether the library is ready. |
110 * The translate function should only be called when |libReady| is true. | 138 * The translate function should only be called when |libReady| is true. |
(...skipping 10 matching lines...) Expand all Loading... |
121 get finished() { | 149 get finished() { |
122 return finished; | 150 return finished; |
123 }, | 151 }, |
124 | 152 |
125 /** | 153 /** |
126 * Whether an error occured initializing the library of translating the | 154 * Whether an error occured initializing the library of translating the |
127 * page. | 155 * page. |
128 * @type {boolean} | 156 * @type {boolean} |
129 */ | 157 */ |
130 get error() { | 158 get error() { |
131 return error; | 159 return errorCode != ERROR['NONE']; |
132 }, | 160 }, |
133 | 161 |
134 /** | 162 /** |
| 163 * Returns a number to represent error type. |
| 164 * @type {number} |
| 165 */ |
| 166 get errorCode() { |
| 167 return errorCode; |
| 168 }, |
| 169 |
| 170 /** |
135 * The language the page translated was in. Is valid only after the page | 171 * The language the page translated was in. Is valid only after the page |
136 * has been successfully translated and the original language specified to | 172 * has been successfully translated and the original language specified to |
137 * the translate function was 'auto'. Is empty otherwise. | 173 * the translate function was 'auto'. Is empty otherwise. |
138 * Some versions of Element library don't provide |getDetectedLanguage| | 174 * Some versions of Element library don't provide |getDetectedLanguage| |
139 * function. In that case, this function returns 'und'. | 175 * function. In that case, this function returns 'und'. |
140 * @type {boolean} | 176 * @type {boolean} |
141 */ | 177 */ |
142 get sourceLang() { | 178 get sourceLang() { |
143 if (!libReady || !finished || error) | 179 if (!libReady || !finished || errorCode != ERROR['NONE']) |
144 return ''; | 180 return ''; |
145 if (!lib.getDetectedLanguage) | 181 if (!lib.getDetectedLanguage) |
146 return 'und'; // defined as chrome::kUnknownLanguageCode in C++ world. | 182 return 'und'; // defined as chrome::kUnknownLanguageCode in C++ world. |
147 return lib.getDetectedLanguage(); | 183 return lib.getDetectedLanguage(); |
148 }, | 184 }, |
149 | 185 |
150 /** | 186 /** |
151 * Time in msec from this script being injected to all server side scripts | 187 * Time in msec from this script being injected to all server side scripts |
152 * being loaded. | 188 * being loaded. |
153 * @type {number} | 189 * @type {number} |
(...skipping 20 matching lines...) Expand all Loading... |
174 * @type {number} | 210 * @type {number} |
175 */ | 211 */ |
176 get translationTime() { | 212 get translationTime() { |
177 if (!finished) | 213 if (!finished) |
178 return 0; | 214 return 0; |
179 return endTime - startTime; | 215 return endTime - startTime; |
180 }, | 216 }, |
181 | 217 |
182 /** | 218 /** |
183 * Translate the page contents. Note that the translation is asynchronous. | 219 * Translate the page contents. Note that the translation is asynchronous. |
184 * You need to regularly check the state of |finished| and |error| to know | 220 * You need to regularly check the state of |finished| and |errorCode| to |
185 * if the translation finished or if there was an error. | 221 * know if the translation finished or if there was an error. |
186 * @param {string} originalLang The language the page is in. | 222 * @param {string} originalLang The language the page is in. |
187 * @param {string} targetLang The language the page should be translated to. | 223 * @param {string} targetLang The language the page should be translated to. |
188 * @return {boolean} False if the translate library was not ready, in which | 224 * @return {boolean} False if the translate library was not ready, in which |
189 * case the translation is not started. True otherwise. | 225 * case the translation is not started. True otherwise. |
190 */ | 226 */ |
191 translate: function(originalLang, targetLang) { | 227 translate: function(originalLang, targetLang) { |
192 finished = false; | 228 finished = false; |
193 error = false; | 229 errorCode = ERROR['NONE']; |
194 if (!libReady) | 230 if (!libReady) |
195 return false; | 231 return false; |
196 startTime = performance.now(); | 232 startTime = performance.now(); |
197 try { | 233 try { |
198 lib.translatePage(originalLang, targetLang, onTranslateProgress); | 234 lib.translatePage(originalLang, targetLang, onTranslateProgress); |
199 } catch (err) { | 235 } catch (err) { |
200 console.error('Translate: ' + err); | 236 console.error('Translate: ' + err); |
201 // TODO(toyoshim): Check if it shows an error notification. | 237 errorCode = ERROR['UNEXPECTED_SCRIPT_ERROR']; |
202 error = true; | |
203 return false; | 238 return false; |
204 } | 239 } |
205 return true; | 240 return true; |
206 }, | 241 }, |
207 | 242 |
208 /** | 243 /** |
209 * Reverts the page contents to its original value, effectively reverting | 244 * Reverts the page contents to its original value, effectively reverting |
210 * any performed translation. Does nothing if the page was not translated. | 245 * any performed translation. Does nothing if the page was not translated. |
211 */ | 246 */ |
212 revert: function() { | 247 revert: function() { |
213 lib.restore(); | 248 lib.restore(); |
214 }, | 249 }, |
215 | 250 |
216 /** | 251 /** |
217 * Entry point called by the Translate Element once it has been injected in | 252 * Entry point called by the Translate Element once it has been injected in |
218 * the page. | 253 * the page. |
219 */ | 254 */ |
220 onTranslateElementLoad: function() { | 255 onTranslateElementLoad: function() { |
221 loadedTime = performance.now(); | 256 loadedTime = performance.now(); |
222 try { | 257 try { |
223 lib = google.translate.TranslateService({ | 258 lib = google.translate.TranslateService({ |
224 // translateApiKey is predefined by translate_script.cc. | 259 // translateApiKey is predefined by translate_script.cc. |
225 'key': translateApiKey, | 260 'key': translateApiKey, |
226 'useSecureConnection': true | 261 'useSecureConnection': true |
227 }); | 262 }); |
228 translateApiKey = undefined; | 263 translateApiKey = undefined; |
229 } catch (err) { | 264 } catch (err) { |
230 error = true; | 265 errorCode = ERROR['INITIALIZATION_ERROR']; |
231 translateApiKey = undefined; | 266 translateApiKey = undefined; |
232 return; | 267 return; |
233 } | 268 } |
234 // The TranslateService is not available immediately as it needs to start | 269 // The TranslateService is not available immediately as it needs to start |
235 // Flash. Let's wait until it is ready. | 270 // Flash. Let's wait until it is ready. |
236 checkLibReady(); | 271 checkLibReady(); |
237 }, | 272 }, |
238 | 273 |
239 /** | 274 /** |
240 * Entry point called by the Translate Element when it want to load an | 275 * Entry point called by the Translate Element when it want to load an |
(...skipping 10 matching lines...) Expand all Loading... |
251 }, | 286 }, |
252 | 287 |
253 /** | 288 /** |
254 * Entry point called by the Translate Element when it want to load and run | 289 * Entry point called by the Translate Element when it want to load and run |
255 * an external JavaScript on the page. | 290 * an external JavaScript on the page. |
256 * @param {string} url URL of an external JavaScript to load. | 291 * @param {string} url URL of an external JavaScript to load. |
257 */ | 292 */ |
258 onLoadJavascript: function(url) { | 293 onLoadJavascript: function(url) { |
259 // securityOrigin is predefined by translate_script.cc. | 294 // securityOrigin is predefined by translate_script.cc. |
260 if (url.indexOf(securityOrigin) != 0) { | 295 if (url.indexOf(securityOrigin) != 0) { |
261 // TODO(toyoshim): Handle this error to show an error notification. | |
262 console.error('Translate: ' + url + ' is not allowed to load.'); | 296 console.error('Translate: ' + url + ' is not allowed to load.'); |
263 error = true; | 297 errorCode = ERROR['BAD_ORIGIN']; |
264 return; | 298 return; |
265 } | 299 } |
266 var xhr = new XMLHttpRequest(); | 300 var xhr = new XMLHttpRequest(); |
267 xhr.open('GET', url, true); | 301 xhr.open('GET', url, true); |
268 xhr.onreadystatechange = function() { | 302 xhr.onreadystatechange = function() { |
269 if (this.readyState != this.DONE || this.status != 200) | 303 if (this.readyState != this.DONE) |
270 return; | 304 return; |
| 305 if (this.status != 200) { |
| 306 errorCode = ERROR['SCRIPT_LOAD_ERROR']; |
| 307 return; |
| 308 } |
271 eval(this.responseText); | 309 eval(this.responseText); |
272 } | 310 } |
273 xhr.send(); | 311 xhr.send(); |
274 } | 312 } |
275 }; | 313 }; |
276 })(); | 314 })(); |
OLD | NEW |