/* 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"; this.EXPORTED_SYMBOLS = ["Translation"]; const {classes: Cc, interfaces: Ci, utils: Cu} = Components; const TRANSLATION_PREF_SHOWUI = "browser.translation.ui.show"; Cu.import("resource://gre/modules/Services.jsm"); this.Translation = { supportedSourceLanguages: ["en", "zh", "ja", "es", "de", "fr", "ru", "ar", "ko", "pt"], supportedTargetLanguages: ["en", "pl", "tr", "vi"], _defaultTargetLanguage: "", get defaultTargetLanguage() { if (!this._defaultTargetLanguage) { this._defaultTargetLanguage = Cc["@mozilla.org/chrome/chrome-registry;1"] .getService(Ci.nsIXULChromeRegistry) .getSelectedLocale("global") .split("-")[0]; } return this._defaultTargetLanguage; }, languageDetected: function(aBrowser, aDetectedLanguage) { if (!Services.prefs.getBoolPref(TRANSLATION_PREF_SHOWUI)) return; if (this.supportedSourceLanguages.indexOf(aDetectedLanguage) != -1 && aDetectedLanguage != this.defaultTargetLanguage) { if (!aBrowser.translationUI) aBrowser.translationUI = new TranslationUI(aBrowser); aBrowser.translationUI.showTranslationUI(aDetectedLanguage); } } }; /* TranslationUI objects keep the information related to translation for * a specific browser. This object is passed to the translation * infobar so that it can initialize itself. The properties exposed to * the infobar are: * - detectedLanguage, code of the language detected on the web page. * - state, the state in which the infobar should be displayed * - STATE_{OFFER,TRANSLATING,TRANSLATED,ERROR} constants. * - translatedFrom, if already translated, source language code. * - translatedTo, if already translated, target language code. * - translate, method starting the translation of the current page. * - showOriginalContent, method showing the original page content. * - showTranslatedContent, method showing the translation for an * already translated page whose original content is shown. * - originalShown, boolean indicating if the original or translated * version of the page is shown. */ function TranslationUI(aBrowser) { this.browser = aBrowser; aBrowser.messageManager.addMessageListener("Translation:Finished", this); } TranslationUI.prototype = { STATE_OFFER: 0, STATE_TRANSLATING: 1, STATE_TRANSLATED: 2, STATE_ERROR: 3, translate: function(aFrom, aTo) { if (aFrom == aTo || (this.state == this.STATE_TRANSLATED && this.translatedFrom == aFrom && this.translatedTo == aTo)) { // Nothing to do. return; } this.state = this.STATE_TRANSLATING; this.translatedFrom = aFrom; this.translatedTo = aTo; this.browser.messageManager.sendAsyncMessage( "Translation:TranslateDocument", { from: aFrom, to: aTo } ); }, showURLBarIcon: function(aTranslated) { let chromeWin = this.browser.ownerGlobal; let PopupNotifications = chromeWin.PopupNotifications; let removeId = aTranslated ? "translate" : "translated"; let notification = PopupNotifications.getNotification(removeId, this.browser); if (notification) PopupNotifications.remove(notification); let callback = aTopic => { if (aTopic != "showing") return false; let notification = this.notificationBox.getNotificationWithValue("translation"); if (notification) notification.close(); else this.showTranslationInfoBar(); return true; }; let addId = aTranslated ? "translated" : "translate"; PopupNotifications.show(this.browser, addId, null, addId + "-notification-icon", null, null, {dismissed: true, eventCallback: callback}); }, _state: 0, get state() this._state, set state(val) { let notif = this.notificationBox.getNotificationWithValue("translation"); if (notif) notif.state = val; this._state = val; }, originalShown: true, showOriginalContent: function() { this.showURLBarIcon(); this.originalShown = true; this.browser.messageManager.sendAsyncMessage("Translation:ShowOriginal"); }, showTranslatedContent: function() { this.showURLBarIcon(true); this.originalShown = false; this.browser.messageManager.sendAsyncMessage("Translation:ShowTranslation"); }, get notificationBox() this.browser.ownerGlobal.gBrowser.getNotificationBox(this.browser), showTranslationInfoBar: function() { let notificationBox = this.notificationBox; let notif = notificationBox.appendNotification("", "translation", null, notificationBox.PRIORITY_INFO_HIGH); notif.init(this); return notif; }, shouldShowInfoBar: function(aURI, aDetectedLanguage) { // Check if we should never show the infobar for this language. let neverForLangs = Services.prefs.getCharPref("browser.translation.neverForLanguages"); if (neverForLangs.split(",").indexOf(aDetectedLanguage) != -1) return false; // or if we should never show the infobar for this domain. let perms = Services.perms; return perms.testExactPermission(aURI, "translate") != perms.DENY_ACTION; }, showTranslationUI: function(aDetectedLanguage) { this.detectedLanguage = aDetectedLanguage; // Reset all values before showing a new translation infobar. this.state = 0; this.translatedFrom = ""; this.translatedTo = ""; this.originalShown = true; this.showURLBarIcon(); if (!this.shouldShowInfoBar(this.browser.currentURI, aDetectedLanguage)) return null; return this.showTranslationInfoBar(); }, receiveMessage: function(msg) { switch (msg.name) { case "Translation:Finished": if (msg.data.success) { this.state = this.STATE_TRANSLATED; this.showURLBarIcon(true); this.originalShown = false; } else { this.state = this.STATE_ERROR; } break; } } };