- //
- // Node now looks like:
Hello [ ][ world.]
- // textnode 1^ ^textnode 2
- //
- // 3 - replace textnode 1 with " Welt."
- // 4 - clear remaining text nodes (in this case, textnode 2)
- //
- // Transformation process with this optimization:
- // 1 - start pointer at item 1
- // 2 - item 1 is already in position
- // 3 - replace textnode 2 with " Welt."
- //
- // which completely avoids any node reordering, and requires only one
- // text change instead of two (while also leaving the page closer to
- // its original state).
- while (curNode &&
- curNode.nodeType == TEXT_NODE &&
- curNode.nodeValue.trim() == "") {
- curNode = curNode.nextSibling;
- }
-
- // Now let's walk through all items in the `target` array of the
- // TranslationItem. This means either the TranslationItem.original or
- // TranslationItem.translation array.
- for (let targetItem of curItem[target]) {
-
- if (targetItem instanceof TranslationItem) {
- // If the array element is another TranslationItem object, let's
- // add it to the stack to be visited.
- visitStack.push(targetItem);
-
- let targetNode = targetItem.nodeRef;
-
- // If the node is not in the expected position, let's reorder
- // it into position...
- if (curNode != targetNode &&
- // ...unless the page has reparented this node under a totally
- // different node (or removed it). In this case, all bets are off
- // on being able to do anything correctly, so it's better not to
- // bring back the node to this parent.
- targetNode.parentNode == domNode) {
-
- // We don't need to null-check curNode because insertBefore(..., null)
- // does what we need in that case: reorder this node to the end
- // of child nodes.
- domNode.insertBefore(targetNode, curNode);
- curNode = targetNode;
- }
-
- // Move pointer forward. Since we do not add empty text nodes to the
- // list of translation items, we must skip them here too while
- // traversing the DOM in order to get better alignment between the
- // text nodes and the translation items.
- if (curNode) {
- curNode = getNextSiblingSkippingEmptyTextNodes(curNode);
- }
-
- } else if (targetItem === TranslationItem_NodePlaceholder) {
- // If the current item is a placeholder node, we need to move
- // our pointer "past" it, jumping from one side of a block of
- // elements + empty text nodes to the other side. Even if
- // non-placeholder elements exists inside the jumped block,
- // they will be pulled correctly later in the process when the
- // targetItem for those nodes are handled.
-
- while (curNode &&
- (curNode.nodeType != TEXT_NODE ||
- curNode.nodeValue.trim() == "")) {
- curNode = curNode.nextSibling;
- }
-
- } else {
- // Finally, if it's a text item, we just need to find the next
- // text node to use. Text nodes don't need to be reordered, so
- // the first one found can be used.
- while (curNode && curNode.nodeType != TEXT_NODE) {
- curNode = curNode.nextSibling;
- }
-
- // If none was found and we reached the end of the child nodes,
- // let's create a new one.
- if (!curNode) {
- // We don't know if the original content had a space or not,
- // so the best bet is to create the text node with " " which
- // will add one space at the beginning and one at the end.
- curNode = domNode.appendChild(domNode.ownerDocument.createTextNode(" "));
- }
-
- // A trailing and a leading space must be preserved because
- // they are meaningful in HTML.
- let preSpace = /^\s/.test(curNode.nodeValue) ? " " : "";
- let endSpace = /\s$/.test(curNode.nodeValue) ? " " : "";
-
- curNode.nodeValue = preSpace + targetItem + endSpace;
- curNode = getNextSiblingSkippingEmptyTextNodes(curNode);
- }
- }
-
- // The translated version of a node might have less text nodes than its
- // original version. If that's the case, let's clear the remaining nodes.
- if (curNode) {
- clearRemainingNonEmptyTextNodesFromElement(curNode);
- }
-
- // And remove any garbage "" nodes left after clearing.
- domNode.normalize();
- }
-}
-
-function getNextSiblingSkippingEmptyTextNodes(startSibling) {
- let item = startSibling.nextSibling;
- while (item &&
- item.nodeType == TEXT_NODE &&
- item.nodeValue.trim() == "") {
- item = item.nextSibling;
- }
- return item;
-}
-
-function clearRemainingNonEmptyTextNodesFromElement(startSibling) {
- let item = startSibling;
- while (item) {
- if (item.nodeType == TEXT_NODE &&
- item.nodeValue != "") {
- item.nodeValue = "";
- }
- item = item.nextSibling;
- }
-}
diff --git a/application/basilisk/components/translation/YandexTranslator.jsm b/application/basilisk/components/translation/YandexTranslator.jsm
deleted file mode 100644
index ab92e09625..0000000000
--- a/application/basilisk/components/translation/YandexTranslator.jsm
+++ /dev/null
@@ -1,343 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-this.EXPORTED_SYMBOLS = [ "YandexTranslator" ];
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://services-common/utils.js");
-Cu.import("resource://gre/modules/Http.jsm");
-
-// The maximum amount of net data allowed per request on Bing's API.
-const MAX_REQUEST_DATA = 5000; // Documentation says 10000 but anywhere
- // close to that is refused by the service.
-
-// The maximum number of chunks allowed to be translated in a single
-// request.
-const MAX_REQUEST_CHUNKS = 1000; // Documentation says 2000.
-
-// Self-imposed limit of 15 requests. This means that a page that would need
-// to be broken in more than 15 requests won't be fully translated.
-// The maximum amount of data that we will translate for a single page
-// is MAX_REQUESTS * MAX_REQUEST_DATA.
-const MAX_REQUESTS = 15;
-
-const YANDEX_RETURN_CODE_OK = 200;
-
-const YANDEX_ERR_KEY_INVALID = 401; // Invalid API key
-const YANDEX_ERR_KEY_BLOCKED = 402; // This API key has been blocked
-const YANDEX_ERR_DAILY_REQ_LIMIT_EXCEEDED = 403; // Daily limit for requests reached
-const YANDEX_ERR_DAILY_CHAR_LIMIT_EXCEEDED = 404; // Daily limit of chars reached
-const YANDEX_ERR_TEXT_TOO_LONG = 413; // The text size exceeds the maximum
-const YANDEX_ERR_UNPROCESSABLE_TEXT = 422; // The text could not be translated
-const YANDEX_ERR_LANG_NOT_SUPPORTED = 501; // The specified translation direction is not supported
-
-// Errors that should activate the service unavailable handling
-const YANDEX_PERMANENT_ERRORS = [
- YANDEX_ERR_KEY_INVALID,
- YANDEX_ERR_KEY_BLOCKED,
- YANDEX_ERR_DAILY_REQ_LIMIT_EXCEEDED,
- YANDEX_ERR_DAILY_CHAR_LIMIT_EXCEEDED,
-];
-
-/**
- * Translates a webpage using Yandex's Translation API.
- *
- * @param translationDocument The TranslationDocument object that represents
- * the webpage to be translated
- * @param sourceLanguage The source language of the document
- * @param targetLanguage The target language for the translation
- *
- * @returns {Promise} A promise that will resolve when the translation
- * task is finished.
- */
-this.YandexTranslator = function(translationDocument, sourceLanguage, targetLanguage) {
- this.translationDocument = translationDocument;
- this.sourceLanguage = sourceLanguage;
- this.targetLanguage = targetLanguage;
- this._pendingRequests = 0;
- this._partialSuccess = false;
- this._serviceUnavailable = false;
- this._translatedCharacterCount = 0;
-};
-
-this.YandexTranslator.prototype = {
- /**
- * Performs the translation, splitting the document into several chunks
- * respecting the data limits of the API.
- *
- * @returns {Promise} A promise that will resolve when the translation
- * task is finished.
- */
- translate: function() {
- return Task.spawn(function *() {
- let currentIndex = 0;
- this._onFinishedDeferred = Promise.defer();
-
- // Let's split the document into various requests to be sent to
- // Yandex's Translation API.
- for (let requestCount = 0; requestCount < MAX_REQUESTS; requestCount++) {
- // Generating the text for each request can be expensive, so
- // let's take the opportunity of the chunkification process to
- // allow for the event loop to attend other pending events
- // before we continue.
- yield CommonUtils.laterTickResolvingPromise();
-
- // Determine the data for the next request.
- let request = this._generateNextTranslationRequest(currentIndex);
-
- // Create a real request to the server, and put it on the
- // pending requests list.
- let yandexRequest = new YandexRequest(request.data,
- this.sourceLanguage,
- this.targetLanguage);
- this._pendingRequests++;
- yandexRequest.fireRequest().then(this._chunkCompleted.bind(this),
- this._chunkFailed.bind(this));
-
- currentIndex = request.lastIndex;
- if (request.finished) {
- break;
- }
- }
-
- return this._onFinishedDeferred.promise;
- }.bind(this));
- },
-
- /**
- * Function called when a request sent to the server completed successfully.
- * This function handles calling the function to parse the result and the
- * function to resolve the promise returned by the public `translate()`
- * method when there are no pending requests left.
- *
- * @param request The YandexRequest sent to the server
- */
- _chunkCompleted: function(yandexRequest) {
- if (this._parseChunkResult(yandexRequest)) {
- this._partialSuccess = true;
- // Count the number of characters successfully translated.
- this._translatedCharacterCount += yandexRequest.characterCount;
- }
-
- this._checkIfFinished();
- },
-
- /**
- * Function called when a request sent to the server has failed.
- * This function handles deciding if the error is transient or means the
- * service is unavailable (zero balance on the key or request credentials are
- * not in an active state) and calling the function to resolve the promise
- * returned by the public `translate()` method when there are no pending
- * requests left.
- *
- * @param aError [optional] The XHR object of the request that failed.
- */
- _chunkFailed: function(aError) {
- if (aError instanceof Ci.nsIXMLHttpRequest) {
- let body = aError.responseText;
- let json = { code: 0 };
- try {
- json = JSON.parse(body);
- } catch (e) {}
-
- if (json.code && YANDEX_PERMANENT_ERRORS.indexOf(json.code) != -1)
- this._serviceUnavailable = true;
- }
-
- this._checkIfFinished();
- },
-
- /**
- * Function called when a request sent to the server has completed.
- * This function handles resolving the promise
- * returned by the public `translate()` method when all chunks are completed.
- */
- _checkIfFinished: function() {
- // Check if all pending requests have been
- // completed and then resolves the promise.
- // If at least one chunk was successful, the
- // promise will be resolved positively which will
- // display the "Success" state for the infobar. Otherwise,
- // the "Error" state will appear.
- if (--this._pendingRequests == 0) {
- if (this._partialSuccess) {
- this._onFinishedDeferred.resolve({
- characterCount: this._translatedCharacterCount
- });
- } else {
- let error = this._serviceUnavailable ? "unavailable" : "failure";
- this._onFinishedDeferred.reject(error);
- }
- }
- },
-
- /**
- * This function parses the result returned by Yandex's Translation API,
- * which returns a JSON result that contains a number of elements. The
- * API is documented here:
- * http://api.yandex.com/translate/doc/dg/reference/translate.xml
- *
- * @param request The request sent to the server.
- * @returns boolean True if parsing of this chunk was successful.
- */
- _parseChunkResult: function(yandexRequest) {
- let results;
- try {
- let result = JSON.parse(yandexRequest.networkRequest.responseText);
- if (result.code != 200) {
- Services.console.logStringMessage("YandexTranslator: Result is " + result.code);
- return false;
- }
- results = result.text
- } catch (e) {
- return false;
- }
-
- let len = results.length;
- if (len != yandexRequest.translationData.length) {
- // This should never happen, but if the service returns a different number
- // of items (from the number of items submitted), we can't use this chunk
- // because all items would be paired incorrectly.
- return false;
- }
-
- let error = false;
- for (let i = 0; i < len; i++) {
- try {
- let result = results[i];
- let root = yandexRequest.translationData[i][0];
- root.parseResult(result);
- } catch (e) { error = true; }
- }
-
- return !error;
- },
-
- /**
- * This function will determine what is the data to be used for
- * the Nth request we are generating, based on the input params.
- *
- * @param startIndex What is the index, in the roots list, that the
- * chunk should start.
- */
- _generateNextTranslationRequest: function(startIndex) {
- let currentDataSize = 0;
- let currentChunks = 0;
- let output = [];
- let rootsList = this.translationDocument.roots;
-
- for (let i = startIndex; i < rootsList.length; i++) {
- let root = rootsList[i];
- let text = this.translationDocument.generateTextForItem(root);
- if (!text) {
- continue;
- }
-
- let newCurSize = currentDataSize + text.length;
- let newChunks = currentChunks + 1;
-
- if (newCurSize > MAX_REQUEST_DATA ||
- newChunks > MAX_REQUEST_CHUNKS) {
-
- // If we've reached the API limits, let's stop accumulating data
- // for this request and return. We return information useful for
- // the caller to pass back on the next call, so that the function
- // can keep working from where it stopped.
- return {
- data: output,
- finished: false,
- lastIndex: i
- };
- }
-
- currentDataSize = newCurSize;
- currentChunks = newChunks;
- output.push([root, text]);
- }
-
- return {
- data: output,
- finished: true,
- lastIndex: 0
- };
- }
-};
-
-/**
- * Represents a request (for 1 chunk) sent off to Yandex's service.
- *
- * @params translationData The data to be used for this translation,
- * generated by the generateNextTranslationRequest...
- * function.
- * @param sourceLanguage The source language of the document.
- * @param targetLanguage The target language for the translation.
- *
- */
-function YandexRequest(translationData, sourceLanguage, targetLanguage) {
- this.translationData = translationData;
- this.sourceLanguage = sourceLanguage;
- this.targetLanguage = targetLanguage;
- this.characterCount = 0;
-}
-
-YandexRequest.prototype = {
- /**
- * Initiates the request
- */
- fireRequest: function() {
- return Task.spawn(function *() {
- // Prepare URL.
- let url = getUrlParam("https://translate.yandex.net/api/v1.5/tr.json/translate",
- "browser.translation.yandex.translateURLOverride");
-
- // Prepare the request body.
- let apiKey = getUrlParam("%YANDEX_API_KEY%", "browser.translation.yandex.apiKeyOverride");
- let params = [
- ["key", apiKey],
- ["format", "html"],
- ["lang", this.sourceLanguage + "-" + this.targetLanguage],
- ];
-
- for (let [, text] of this.translationData) {
- params.push(["text", text]);
- this.characterCount += text.length;
- }
-
- // Set up request options.
- let deferred = Promise.defer();
- let options = {
- onLoad: (function(responseText, xhr) {
- deferred.resolve(this);
- }).bind(this),
- onError: function(e, responseText, xhr) {
- deferred.reject(xhr);
- },
- postData: params
- };
-
- // Fire the request.
- this.networkRequest = httpRequest(url, options);
-
- return deferred.promise;
- }.bind(this));
- }
-};
-
-/**
- * Fetch an auth token (clientID or client secret), which may be overridden by
- * a pref if it's set.
- */
-function getUrlParam(paramValue, prefName) {
- if (Services.prefs.getPrefType(prefName))
- paramValue = Services.prefs.getCharPref(prefName);
- paramValue = Services.urlFormatter.formatURL(paramValue);
- return paramValue;
-}
diff --git a/application/basilisk/components/translation/jar.mn b/application/basilisk/components/translation/jar.mn
deleted file mode 100644
index be744cb9ef..0000000000
--- a/application/basilisk/components/translation/jar.mn
+++ /dev/null
@@ -1,6 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-browser.jar:
- content/browser/translation-infobar.xml
- content/browser/microsoft-translator-attribution.png
diff --git a/application/basilisk/components/translation/microsoft-translator-attribution.png b/application/basilisk/components/translation/microsoft-translator-attribution.png
deleted file mode 100644
index d9d277461b..0000000000
Binary files a/application/basilisk/components/translation/microsoft-translator-attribution.png and /dev/null differ
diff --git a/application/basilisk/components/translation/moz.build b/application/basilisk/components/translation/moz.build
index ac0165230d..32421e4301 100644
--- a/application/basilisk/components/translation/moz.build
+++ b/application/basilisk/components/translation/moz.build
@@ -3,14 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_JS_MODULES.translation = [
- 'BingTranslator.jsm',
'cld2/cld-worker.js',
'cld2/cld-worker.js.mem',
'LanguageDetector.jsm',
- 'Translation.jsm',
- 'TranslationContentHandler.jsm',
- 'TranslationDocument.jsm',
- 'YandexTranslator.jsm'
]
-
-JAR_MANIFESTS += ['jar.mn']
diff --git a/application/basilisk/components/translation/translation-infobar.xml b/application/basilisk/components/translation/translation-infobar.xml
deleted file mode 100644
index db0695c03b..0000000000
--- a/application/basilisk/components/translation/translation-infobar.xml
+++ /dev/null
@@ -1,441 +0,0 @@
-
-
-
-
-%notificationDTD;
-
-%translationDTD;
-]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [code, bundle.GetStringFromName(code)])
- .sort((a, b) => a[1].localeCompare(b[1]));
- };
-
- // Fill the lists of supported source languages.
- let detectedLanguage = this._getAnonElt("detectedLanguage");
- let fromLanguage = this._getAnonElt("fromLanguage");
- let sourceLanguages =
- sortByLocalizedName(Translation.supportedSourceLanguages);
- for (let [code, name] of sourceLanguages) {
- detectedLanguage.appendItem(name, code);
- fromLanguage.appendItem(name, code);
- }
- detectedLanguage.value = this.translation.detectedLanguage;
-
- // translatedFrom is only set if we have already translated this page.
- if (aTranslation.translatedFrom)
- fromLanguage.value = aTranslation.translatedFrom;
-
- // Fill the list of supported target languages.
- let toLanguage = this._getAnonElt("toLanguage");
- let targetLanguages =
- sortByLocalizedName(Translation.supportedTargetLanguages);
- for (let [code, name] of targetLanguages)
- toLanguage.appendItem(name, code);
-
- if (aTranslation.translatedTo)
- toLanguage.value = aTranslation.translatedTo;
-
- if (aTranslation.state)
- this.state = aTranslation.state;
-
- // Show attribution for the preferred translator.
- let engineIndex = Object.keys(Translation.supportedEngines)
- .indexOf(Translation.translationEngine);
- if (engineIndex != -1) {
- this._getAnonElt('translationEngine').selectedIndex = engineIndex;
- }
-
- const kWelcomePref = "browser.translation.ui.welcomeMessageShown";
- if (Services.prefs.prefHasUserValue(kWelcomePref) ||
- this.translation.browser != gBrowser.selectedBrowser)
- return;
-
- this.addEventListener("transitionend", function onShown() {
- this.removeEventListener("transitionend", onShown);
-
- // These strings are hardcoded because they need to reach beta
- // without riding the trains.
- let localizedStrings = {
- en: ["Hey look! It's something new!",
- "Now the Web is even more accessible with our new in-page translation feature. Click the translate button to try it!",
- "Learn more.",
- "Thanks"],
- "es-AR": ["\xA1Mir\xE1! \xA1Hay algo nuevo!",
- "Ahora la web es a\xFAn m\xE1s accesible con nuestra nueva funcionalidad de traducci\xF3n integrada. \xA1Hac\xE9 clic en el bot\xF3n traducir para probarla!",
- "Conoc\xE9 m\xE1s.",
- "Gracias"],
- "es-ES": ["\xA1Mira! \xA1Hay algo nuevo!",
- "Con la nueva funcionalidad de traducci\xF3n integrada, ahora la Web es a\xFAn m\xE1s accesible. \xA1Pulsa el bot\xF3n Traducir y pru\xE9bala!",
- "M\xE1s informaci\xF3n.",
- "Gracias"],
- pl: ["Sp\xF3jrz tutaj! To co\u015B nowego!",
- "Sie\u0107 sta\u0142a si\u0119 w\u0142a\u015Bnie jeszcze bardziej dost\u0119pna dzi\u0119ki opcji bezpo\u015Bredniego t\u0142umaczenia stron. Kliknij przycisk t\u0142umaczenia, aby spr\xF3bowa\u0107!",
- "Dowiedz si\u0119 wi\u0119cej",
- "Dzi\u0119kuj\u0119"],
- tr: ["Bak\u0131n, burada yeni bir \u015Fey var!",
- "Yeni sayfa i\xE7i \xE7eviri \xF6zelli\u011Fimiz sayesinde Web art\u0131k \xE7ok daha anla\u015F\u0131l\u0131r olacak. Denemek i\xE7in \xC7evir d\xFC\u011Fmesine t\u0131klay\u0131n!",
- "Daha fazla bilgi al\u0131n.",
- "Te\u015Fekk\xFCrler"],
- vi: ["Nh\xECn n\xE0y! \u0110\u1ED3 m\u1EDBi!",
- "Gi\u1EDD \u0111\xE2y ch\xFAng ta c\xF3 th\u1EC3 ti\u1EBFp c\u1EADn web d\u1EC5 d\xE0ng h\u01A1n n\u1EEFa v\u1EDBi t\xEDnh n\u0103ng d\u1ECBch ngay trong trang. Hay nh\u1EA5n n\xFAt d\u1ECBch \u0111\u1EC3 th\u1EED!",
- "T\xECm hi\u1EC3u th\xEAm.",
- "C\u1EA3m \u01A1n"]
- };
-
- let locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
- .getService(Ci.nsIXULChromeRegistry)
- .getSelectedLocale("browser");
- if (!(locale in localizedStrings))
- locale = "en";
- let strings = localizedStrings[locale];
-
- this._getAnonElt("welcomeHeadline").setAttribute("value", strings[0]);
- this._getAnonElt("welcomeBody").textContent = strings[1];
- this._getAnonElt("learnMore").setAttribute("value", strings[2]);
- this._getAnonElt("thanksButton").setAttribute("label", strings[3]);
-
- let panel = this._getAnonElt("welcomePanel");
- panel.openPopup(this._getAnonElt("messageImage"),
- "bottomcenter topleft");
-
- Services.prefs.setBoolPref(kWelcomePref, true);
- });
- ]]>
-
-
-
-
-
-
- return document.getAnonymousElementByAttribute(this, "anonid", aAnonId);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
--
cgit v1.2.3