stylus/js/localization.js
2017-07-16 13:07:21 -05:00

131 lines
3.5 KiB
JavaScript

'use strict';
const template = {};
tDocLoader();
function t(key, params) {
const cache = !params && t.cache[key];
const s = cache || chrome.i18n.getMessage(key, params);
if (s === '') {
throw `Missing string "${key}"`;
}
if (!params && !cache) {
t.cache[key] = s;
}
return s;
}
function tE(id, key, attr, esc) {
if (attr) {
document.getElementById(id).setAttribute(attr, t(key));
} else if (typeof esc === 'undefined' || esc) {
document.getElementById(id).appendChild(document.createTextNode(t(key)));
} else {
document.getElementById(id).innerHTML = t(key);
}
}
function tHTML(html) {
const node = document.createElement('div');
node.innerHTML = html.replace(/>\s+</g, '><'); // spaces are removed; use &nbsp; for an explicit space
if (html.includes('i18n-')) {
tNodeList(node.getElementsByTagName('*'));
}
return node.firstElementChild;
}
function tNodeList(nodes) {
const PREFIX = 'i18n-';
for (let n = nodes.length; --n >= 0;) {
const node = nodes[n];
// skip non-ELEMENT_NODE
if (node.nodeType !== 1) {
continue;
}
if (node.localName === 'template') {
const elements = node.content.querySelectorAll('*');
tNodeList(elements);
template[node.dataset.id] = elements[0];
// compress inter-tag whitespace to reduce number of DOM nodes by 25%
const walker = document.createTreeWalker(elements[0], NodeFilter.SHOW_TEXT);
const toRemove = [];
while (walker.nextNode()) {
const textNode = walker.currentNode;
if (!textNode.nodeValue.trim()) {
toRemove.push(textNode);
}
}
toRemove.forEach(el => el.remove());
continue;
}
for (let a = node.attributes.length; --a >= 0;) {
const attr = node.attributes[a];
const name = attr.nodeName;
if (!name.startsWith(PREFIX)) {
continue;
}
const type = name.substr(PREFIX.length);
const value = t(attr.value);
switch (type) {
case 'text':
node.insertBefore(document.createTextNode(value), node.firstChild);
break;
case 'text-append':
node.appendChild(document.createTextNode(value));
break;
case 'html':
node.insertAdjacentHTML('afterbegin', value);
break;
default:
node.setAttribute(type, value);
}
node.removeAttribute(name);
}
}
}
function tDocLoader() {
t.cache = tryJSONparse(localStorage.L10N) || {};
// reset L10N cache on UI language change
const UIlang = chrome.i18n.getUILanguage();
if (t.cache.browserUIlanguage !== UIlang) {
t.cache = {browserUIlanguage: UIlang};
localStorage.L10N = JSON.stringify(t.cache);
}
const cacheLength = Object.keys(t.cache).length;
// localize HEAD
tNodeList(document.getElementsByTagName('*'));
// localize BODY
const process = mutations => {
for (const mutation of mutations) {
tNodeList(mutation.addedNodes);
}
};
const observer = new MutationObserver(process);
const onLoad = () => {
tDocLoader.stop();
process(observer.takeRecords());
if (cacheLength !== Object.keys(t.cache).length) {
localStorage.L10N = JSON.stringify(t.cache);
}
};
tDocLoader.start = () => {
observer.observe(document, {subtree: true, childList: true});
};
tDocLoader.stop = () => {
observer.disconnect();
document.removeEventListener('DOMContentLoaded', onLoad);
};
tDocLoader.start();
document.addEventListener('DOMContentLoaded', onLoad);
}