michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: "use strict"; michael@0: michael@0: module.metadata = { michael@0: "stability": "unstable" michael@0: }; michael@0: michael@0: const { Ci, Cu } = require("chrome"); michael@0: const events = require("../system/events"); michael@0: const core = require("./core"); michael@0: michael@0: const assetsURI = require('../self').data.url(); michael@0: const { Services } = Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: const hideContentStyle = "data:text/css,:root {visibility: hidden !important;}"; michael@0: const hideSheetUri = Services.io.newURI(hideContentStyle, null, null); michael@0: michael@0: // Taken from Gaia: michael@0: // https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470 michael@0: function translateElement(element) { michael@0: element = element || document; michael@0: michael@0: // check all translatable children (= w/ a `data-l10n-id' attribute) michael@0: var children = element.querySelectorAll('*[data-l10n-id]'); michael@0: var elementCount = children.length; michael@0: for (var i = 0; i < elementCount; i++) { michael@0: var child = children[i]; michael@0: michael@0: // translate the child michael@0: var key = child.dataset.l10nId; michael@0: var data = core.get(key); michael@0: if (data) michael@0: child.textContent = data; michael@0: } michael@0: } michael@0: exports.translateElement = translateElement; michael@0: michael@0: function onDocumentReady2Translate(event) { michael@0: let document = event.target; michael@0: document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate, michael@0: false); michael@0: michael@0: translateElement(document); michael@0: michael@0: try { michael@0: // Finally display document when we finished replacing all text content michael@0: if (document.defaultView) { michael@0: let winUtils = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) michael@0: .getInterface(Ci.nsIDOMWindowUtils); michael@0: winUtils.removeSheet(hideSheetUri, winUtils.USER_SHEET); michael@0: } michael@0: } michael@0: catch(e) { michael@0: console.exception(e); michael@0: } michael@0: } michael@0: michael@0: function onContentWindow(event) { michael@0: let document = event.subject; michael@0: michael@0: // Accept only HTML documents michael@0: if (!(document instanceof Ci.nsIDOMHTMLDocument)) michael@0: return; michael@0: michael@0: // Bug 769483: data:URI documents instanciated with nsIDOMParser michael@0: // have a null `location` attribute at this time michael@0: if (!document.location) michael@0: return; michael@0: michael@0: // Accept only document from this addon michael@0: if (document.location.href.indexOf(assetsURI) !== 0) michael@0: return; michael@0: michael@0: try { michael@0: // First hide content of the document in order to have content blinking michael@0: // between untranslated and translated states michael@0: let winUtils = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) michael@0: .getInterface(Ci.nsIDOMWindowUtils); michael@0: winUtils.loadSheet(hideSheetUri, winUtils.USER_SHEET); michael@0: } michael@0: catch(e) { michael@0: console.exception(e); michael@0: } michael@0: // Wait for DOM tree to be built before applying localization michael@0: document.addEventListener("DOMContentLoaded", onDocumentReady2Translate, michael@0: false); michael@0: } michael@0: michael@0: // Listen to creation of content documents in order to translate them as soon michael@0: // as possible in their loading process michael@0: const ON_CONTENT = "document-element-inserted"; michael@0: let enabled = false; michael@0: function enable() { michael@0: if (!enabled) { michael@0: events.on(ON_CONTENT, onContentWindow); michael@0: enabled = true; michael@0: } michael@0: } michael@0: exports.enable = enable; michael@0: michael@0: function disable() { michael@0: if (enabled) { michael@0: events.off(ON_CONTENT, onContentWindow); michael@0: enabled = false; michael@0: } michael@0: } michael@0: exports.disable = disable; michael@0: michael@0: require("sdk/system/unload").when(disable);