diff options
author | Jesús <heckyel@hyperbola.info> | 2019-09-21 12:03:39 -0500 |
---|---|---|
committer | Jesús <heckyel@hyperbola.info> | 2019-09-21 12:03:39 -0500 |
commit | 648066ec2b431a23bf0134b701db3914abaf752b (patch) | |
tree | aeedd94cf503655ef3ef00e80d8f6c7a45429995 | |
parent | 6f300357e247ce0645acdff25d2f0b1c056d3ae1 (diff) | |
download | ematrix-648066ec2b431a23bf0134b701db3914abaf752b.tar.lz ematrix-648066ec2b431a23bf0134b701db3914abaf752b.tar.xz ematrix-648066ec2b431a23bf0134b701db3914abaf752b.zip |
Improvement to the i18n mechanism for dashboard pages
-rw-r--r-- | js/i18n.js | 112 |
1 files changed, 64 insertions, 48 deletions
@@ -21,53 +21,62 @@ uMatrix Home: https://github.com/gorhill/uMatrix */ -/* global vAPI, uDom */ - 'use strict'; -/******************************************************************************/ - // This file should always be included at the end of the `body` tag, so as // to ensure all i18n targets are already loaded. (function() { - - /******************************************************************************/ - // https://github.com/gorhill/uBlock/issues/2084 - // Anything else than <a>, <b>, <code>, <em>, <i>, <input>, and <span> will - // be rendered as plain text. - // For <input>, only the type attribute is allowed. - // For <a>, only href attribute must be present, and it MUST starts with - // `https://`, and includes no single- or double-quotes. - // No HTML entities are allowed, there is code to handle existing HTML - // entities already present in translation files until they are all gone. - - var reSafeTags = /^([\s\S]*?)<(b|blockquote|code|em|i|kbd|span|sup)>(.+?)<\/\2>([\s\S]*)$/, - reSafeInput = /^([\s\S]*?)<(input type="[^"]+")>(.*?)([\s\S]*)$/, - reInput = /^input type=(['"])([a-z]+)\1$/, - reSafeLink = /^([\s\S]*?)<(a href=['"]https?:\/\/[^'" <>]+['"])>(.+?)<\/a>([\s\S]*)$/, - reLink = /^a href=(['"])(https?:\/\/[^'"]+)\1$/; + // Anything else than <a>, <b>, <code>, <em>, <i>, <input>, and + // <span> will be rendered as plain text. For <input>, only the + // type attribute is allowed. For <a>, only href attribute must + // be present, and it MUST starts with `https://`, and includes no + // single- or double-quotes. No HTML entities are allowed, there + // is code to handle existing HTML entities already present in + // translation files until they are all gone. + // + // ηMatrix: + // We're not going to remove anything, but rather going to make + // full use of HTML tags and HTML entities in translations. Of + // course, this check for safe tags is going to stay and will be + // used to check the source text. The above comment is kept just + // in case. + + let reSafeTags = + /^([\s\S]*?)<(b|blockquote|code|em|i|kbd|span|sup)>(.+?)<\/\2>([\s\S]*)$/; + let reSafeInput = /^([\s\S]*?)<(input type="[^"]+")>(.*?)([\s\S]*)$/; + let reInput = /^input type=(['"])([a-z]+)\1$/; + let reSafeLink = + /^([\s\S]*?)<(a href=['"]https?:\/\/[^'" <>]+['"])>(.+?)<\/a>([\s\S]*)$/; + let reLink = /^a href=(['"])(https?:\/\/[^'"]+)\1$/; var safeTextToTagNode = function(text) { - var matches, node; - if ( text.lastIndexOf('a ', 0) === 0 ) { + let matches; + let node; + + if (text.lastIndexOf('a ', 0) === 0) { matches = reLink.exec(text); - if ( matches === null ) { return null; } + if (matches === null) { + return null; + } node = document.createElement('a'); node.setAttribute('href', matches[2]); return node; } - if ( text.lastIndexOf('input ', 0) === 0 ) { + if (text.lastIndexOf('input ', 0) === 0) { matches = reInput.exec(text); - if ( matches === null ) { return null; } + if (matches === null) { + return null; + } node = document.createElement('input'); node.setAttribute('type', matches[2]); return node; } - // Firefox extension validator warns if using a variable as argument for - // document.createElement(). - switch ( text ) { + // Firefox extension validator warns if using a variable as + // argument for document.createElement(). + // ηMatrix: is it important for us? + switch (text) { case 'b': return document.createElement('b'); case 'blockquote': @@ -90,46 +99,53 @@ }; var safeTextToTextNode = function(text) { - // TODO: remove once no more HTML entities in translation files. - if ( text.indexOf('&') !== -1 ) { - text = text.replace(/“/g, '“') + if (text.indexOf('&') !== -1) { + text = text + .replace(/“/g, '“') .replace(/”/g, '”') .replace(/‘/g, '‘') - .replace(/’/g, '’'); + .replace(/’/g, '’') + .replace(/</g, '<') + .replace(/>/g, '>'); } return document.createTextNode(text); }; var safeTextToDOM = function(text, parent) { - if ( text === '' ) { return; } - // Fast path (most common). - if ( text.indexOf('<') === -1 ) { + if (text === '') { + return; + } + + if (text.indexOf('<') === -1) { return parent.appendChild(safeTextToTextNode(text)); } - // Slow path. - // `<p>` no longer allowed. Code below can be remove once all <p>'s are - // gone from translation files. - text = text.replace(/^<p>|<\/p>/g, '') + + // Using the raw <p> element is not allowed for security reason, + // but it's good for formatting content, so here it's substituted + // for a safer equivalent (for the extension.) + text = text + .replace(/^<p>|<\/p>/g, '') .replace(/<p>/g, '\n\n'); - // Parse allowed HTML tags. - var matches, - matches1 = reSafeTags.exec(text), - matches2 = reSafeLink.exec(text); - if ( matches1 !== null && matches2 !== null ) { + + let matches; + let matches1 = reSafeTags.exec(text); + let matches2 = reSafeLink.exec(text); + if (matches1 !== null && matches2 !== null) { matches = matches1.index < matches2.index ? matches1 : matches2; - } else if ( matches1 !== null ) { + } else if (matches1 !== null) { matches = matches1; - } else if ( matches2 !== null ) { + } else if (matches2 !== null) { matches = matches2; } else { matches = reSafeInput.exec(text); } - if ( matches === null ) { + if (matches === null) { parent.appendChild(safeTextToTextNode(text)); return; } + safeTextToDOM(matches[1], parent); - var node = safeTextToTagNode(matches[2]) || parent; + let node = safeTextToTagNode(matches[2]) || parent; safeTextToDOM(matches[3], node); parent.appendChild(node); safeTextToDOM(matches[4], parent); |