|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 "use strict"; |
|
5 |
|
6 module.metadata = { |
|
7 "stability": "unstable" |
|
8 }; |
|
9 |
|
10 const { Ci, Cu } = require("chrome"); |
|
11 const events = require("../system/events"); |
|
12 const core = require("./core"); |
|
13 |
|
14 const assetsURI = require('../self').data.url(); |
|
15 const { Services } = Cu.import("resource://gre/modules/Services.jsm"); |
|
16 |
|
17 const hideContentStyle = "data:text/css,:root {visibility: hidden !important;}"; |
|
18 const hideSheetUri = Services.io.newURI(hideContentStyle, null, null); |
|
19 |
|
20 // Taken from Gaia: |
|
21 // https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470 |
|
22 function translateElement(element) { |
|
23 element = element || document; |
|
24 |
|
25 // check all translatable children (= w/ a `data-l10n-id' attribute) |
|
26 var children = element.querySelectorAll('*[data-l10n-id]'); |
|
27 var elementCount = children.length; |
|
28 for (var i = 0; i < elementCount; i++) { |
|
29 var child = children[i]; |
|
30 |
|
31 // translate the child |
|
32 var key = child.dataset.l10nId; |
|
33 var data = core.get(key); |
|
34 if (data) |
|
35 child.textContent = data; |
|
36 } |
|
37 } |
|
38 exports.translateElement = translateElement; |
|
39 |
|
40 function onDocumentReady2Translate(event) { |
|
41 let document = event.target; |
|
42 document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate, |
|
43 false); |
|
44 |
|
45 translateElement(document); |
|
46 |
|
47 try { |
|
48 // Finally display document when we finished replacing all text content |
|
49 if (document.defaultView) { |
|
50 let winUtils = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) |
|
51 .getInterface(Ci.nsIDOMWindowUtils); |
|
52 winUtils.removeSheet(hideSheetUri, winUtils.USER_SHEET); |
|
53 } |
|
54 } |
|
55 catch(e) { |
|
56 console.exception(e); |
|
57 } |
|
58 } |
|
59 |
|
60 function onContentWindow(event) { |
|
61 let document = event.subject; |
|
62 |
|
63 // Accept only HTML documents |
|
64 if (!(document instanceof Ci.nsIDOMHTMLDocument)) |
|
65 return; |
|
66 |
|
67 // Bug 769483: data:URI documents instanciated with nsIDOMParser |
|
68 // have a null `location` attribute at this time |
|
69 if (!document.location) |
|
70 return; |
|
71 |
|
72 // Accept only document from this addon |
|
73 if (document.location.href.indexOf(assetsURI) !== 0) |
|
74 return; |
|
75 |
|
76 try { |
|
77 // First hide content of the document in order to have content blinking |
|
78 // between untranslated and translated states |
|
79 let winUtils = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) |
|
80 .getInterface(Ci.nsIDOMWindowUtils); |
|
81 winUtils.loadSheet(hideSheetUri, winUtils.USER_SHEET); |
|
82 } |
|
83 catch(e) { |
|
84 console.exception(e); |
|
85 } |
|
86 // Wait for DOM tree to be built before applying localization |
|
87 document.addEventListener("DOMContentLoaded", onDocumentReady2Translate, |
|
88 false); |
|
89 } |
|
90 |
|
91 // Listen to creation of content documents in order to translate them as soon |
|
92 // as possible in their loading process |
|
93 const ON_CONTENT = "document-element-inserted"; |
|
94 let enabled = false; |
|
95 function enable() { |
|
96 if (!enabled) { |
|
97 events.on(ON_CONTENT, onContentWindow); |
|
98 enabled = true; |
|
99 } |
|
100 } |
|
101 exports.enable = enable; |
|
102 |
|
103 function disable() { |
|
104 if (enabled) { |
|
105 events.off(ON_CONTENT, onContentWindow); |
|
106 enabled = false; |
|
107 } |
|
108 } |
|
109 exports.disable = disable; |
|
110 |
|
111 require("sdk/system/unload").when(disable); |