assetgraph-i18n
Version:
i18n plugin for assetgraph-builder
109 lines (103 loc) • 3.65 kB
JavaScript
module.exports = function eachI18nTagInHtmlDocument(
document,
lambda,
nestedTemplateLambda
) {
const ELEMENT_NODE = 1;
const TEXT_NODE = 3;
const queue = [document];
let i;
while (queue.length) {
const node = queue.shift();
const parentNode = node.parentNode;
let nodeStillInDocument = true;
if (parentNode && node.nodeType === ELEMENT_NODE) {
if (node.hasAttribute && node.hasAttribute('data-i18n')) {
// In IE7 the HTML node doesn't have a hasAttribute method?
const i18nStr = node.getAttribute('data-i18n');
let i18nObj;
if (i18nStr.includes(':')) {
try {
i18nObj = eval('({' + i18nStr + '})'); // eslint-disable-line no-eval
} catch (e) {
throw new Error(
'i18nTools.eachI18nTagInHtmlDocument: Error evaluating data-i18n attribute: ' +
i18nStr +
'\n' +
e.stack
);
}
} else {
i18nObj = { text: i18nStr };
}
if (i18nObj.attr) {
const attributeNames = Object.keys(i18nObj.attr);
for (i = 0; i < attributeNames.length; i += 1) {
const attributeName = attributeNames[i];
const key = i18nObj.attr[attributeName] || null;
if (
lambda({
type: 'i18nTagAttribute',
attributeName: attributeName,
node: node,
key: key,
defaultValue: node.getAttribute(attributeName),
}) === false
) {
return;
}
}
}
if (typeof i18nObj.text !== 'undefined') {
let defaultValue = '';
const placeHolders = [];
let nextPlaceHolderNumber = 0;
for (i = 0; i < node.childNodes.length; i += 1) {
const childNode = node.childNodes[i];
if (childNode.nodeType === TEXT_NODE) {
defaultValue += childNode.nodeValue;
} else {
defaultValue += '{' + nextPlaceHolderNumber + '}';
nextPlaceHolderNumber += 1;
placeHolders.push(childNode);
}
}
defaultValue = defaultValue.replace(/^[ \n\t]+|[ \n\t]+$/g, ''); // Trim leading and trailing whitespace, except non-breaking space chars
defaultValue = defaultValue.replace(/[ \n\t]+/g, ' '); // Compress and normalize sequences of 1+ spaces to one ' '
if (
lambda({
type: 'i18nTagText',
node: node,
key: i18nObj.text || null,
defaultValue: defaultValue,
placeHolders: placeHolders,
}) === false
) {
return;
}
} else {
// A tag with a data-i18n tag, but no language key for the text contents.
// Give the lambda a chance to clean up the tag anyway:
lambda({ node: node });
}
if (!node.parentNode) {
nodeStillInDocument = false;
queue.unshift(parentNode);
}
}
// Give the caller a chance to do something about nested <script type="text/html">...</script> templates (used by TRHTML in the browser):
if (
nestedTemplateLambda &&
node.nodeName.toLowerCase() === 'script' &&
node.getAttribute('type') === 'text/html'
) {
nestedTemplateLambda(node);
}
}
if (nodeStillInDocument && node.childNodes) {
for (i = node.childNodes.length - 1; i >= 0; i -= 1) {
queue.unshift(node.childNodes[i]);
}
}
}
};