gorhill 8 years ago
parent
commit
a4fb878b08
  1. 4
      src/_locales/en/messages.json
  2. 9
      src/css/dashboard-common.css
  3. 120
      src/js/i18n.js

4
src/_locales/en/messages.json

@ -360,7 +360,7 @@
"description": "Second part of 'Clear browser cache every [n] minutes'" "description": "Second part of 'Clear browser cache every [n] minutes'"
}, },
"privacyClearCacheHelp" : { "privacyClearCacheHelp" : {
"message": "<p>Some web sites are really bent on tracking you, so much that they will use not-so-nice tricks to work around whatever measures you take in order to not be tracked.</p><p>A few of these tricks rely<sup style='font-size:smaller'>[1, 2]</sup> on the <a href='https://en.wikipedia.org/wiki/Web_cache'>browser cache</a>, which content is often long lasting since rarely will users take the time to regularly clear their browser cache.</p><p>There is little inconvenience to clear the browser cache regularly (likelihood is that you won't notice when it happens), and the benefit is to prevent these obnoxious trackers from invading your privacy.</p><p>Check this option to have <i>uMatrix</i> do it for you, at the interval you wish.</p><p style='font-size:smaller'>[1] <a href='https://grepular.com/Preventing_Web_Tracking_via_the_Browser_Cache'>&ldquo;Preventing Web Tracking via the Browser Cache&rdquo;</a><br>[2] <a href='http://lucb1e.com/rp/cookielesscookies/'>&ldquo;Cookieless cookies&rdquo;</a></p>",
"message": "<p>Some web sites are really bent on tracking you, so much that they will use not-so-nice tricks to work around whatever measures you take in order to not be tracked.</p><p>A few of these tricks rely<sup>[1, 2]</sup> on the <a href='https://en.wikipedia.org/wiki/Web_cache'>browser cache</a>, which content is often long lasting since rarely will users take the time to regularly clear their browser cache.</p><p>There is little inconvenience to clear the browser cache regularly (likelihood is that you won't notice when it happens), and the benefit is to prevent these obnoxious trackers from invading your privacy.</p><p>Check this option to have <i>uMatrix</i> do it for you, at the interval you wish.</p><p>[1] <a href='https://grepular.com/Preventing_Web_Tracking_via_the_Browser_Cache'>&ldquo;Preventing Web Tracking via the Browser Cache&rdquo;</a>\n[2] <a href='http://lucb1e.com/rp/cookielesscookies/'>&ldquo;Cookieless cookies&rdquo;</a></p>",
"description": "" "description": ""
}, },
"privacyProcessRefererPrompt" : { "privacyProcessRefererPrompt" : {
@ -368,7 +368,7 @@
"description": "" "description": ""
}, },
"privacyProcessRefererHelp" : { "privacyProcessRefererHelp" : {
"message": "<p>From Wikipedia:</p><blockquote>HTTP referer is an HTTP header field that identifies the address of the webpage that linked to the resource being requested. ... <b>Because referer information can violate privacy, some web browsers allow the user to disable the sending of referer information.</b></blockquote><p>If this setting is checked, <i>uMatrix</i> will spoof the HTTP referrer information if the domain name of the HTTP referrer is third-party to the domain name of net request.",
"message": "From Wikipedia:<blockquote>HTTP referer is an HTTP header field that identifies the address of the webpage that linked to the resource being requested. ... <b>Because referer information can violate privacy, some web browsers allow the user to disable the sending of referer information.</b></blockquote>If this setting is checked, <i>uMatrix</i> will spoof the HTTP referrer information if the domain name of the HTTP referrer is third-party to the domain name of net request.",
"description": "" "description": ""
}, },
"privacyNoMixedContentPrompt" : { "privacyNoMixedContentPrompt" : {

9
src/css/dashboard-common.css

@ -56,12 +56,13 @@ button {
opacity: 1.0; opacity: 1.0;
} }
.whatisthis-expandable { .whatisthis-expandable {
background-color: #F8F8F8;
border: 1px dotted #aaa;
display: none;
font-size: smaller;
margin: 0.5em 0 1em 1.25em; margin: 0.5em 0 1em 1.25em;
padding: 0.5em; padding: 0.5em;
font-size: smaller;
display: none;
border: 1px dotted #aaa;
background-color: #F8F8F8;
white-space: pre-line;
} }
.whatisthis-expandable > p { .whatisthis-expandable > p {
margin-top: 1em; margin-top: 1em;

120
src/js/i18n.js

@ -32,11 +32,125 @@
/******************************************************************************/ /******************************************************************************/
// 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|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$/;
var safeTextToTagNode = function(text) {
var matches, node;
if ( text.lastIndexOf('a ', 0) === 0 ) {
matches = reLink.exec(text);
if ( matches === null ) { return null; }
node = document.createElement('a');
node.setAttribute('href', matches[2]);
return node;
}
if ( text.lastIndexOf('input ', 0) === 0 ) {
matches = reInput.exec(text);
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 ) {
case 'b':
return document.createElement('b');
case 'blockquote':
return document.createElement('blockquote');
case 'code':
return document.createElement('code');
case 'em':
return document.createElement('em');
case 'i':
return document.createElement('i');
case 'span':
return document.createElement('span');
case 'sup':
return document.createElement('sup');
default:
break;
}
};
var safeTextToTextNode = function(text) {
// TODO: remove once no more HTML entities in translation files.
if ( text.indexOf('&') !== -1 ) {
text = text.replace(/&ldquo;/g, '“')
.replace(/&rdquo;/g, '”')
.replace(/&lsquo;/g, '‘')
.replace(/&rsquo;/g, '’');
}
return document.createTextNode(text);
};
var safeTextToDOM = function(text, parent) {
if ( text === '' ) { return; }
// Fast path (most common).
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, '')
.replace(/<p>/g, '\n\n');
// Parse allowed HTML tags.
var matches,
matches1 = reSafeTags.exec(text),
matches2 = reSafeLink.exec(text);
if ( matches1 !== null && matches2 !== null ) {
matches = matches1.index < matches2.index ? matches1 : matches2;
} else if ( matches1 !== null ) {
matches = matches1;
} else if ( matches2 !== null ) {
matches = matches2;
} else {
matches = reSafeInput.exec(text);
}
if ( matches === null ) {
parent.appendChild(safeTextToTextNode(text));
return;
}
safeTextToDOM(matches[1], parent);
var node = safeTextToTagNode(matches[2]) || parent;
safeTextToDOM(matches[3], node);
parent.appendChild(node);
safeTextToDOM(matches[4], parent);
};
/******************************************************************************/
// Helper to deal with the i18n'ing of HTML files. // Helper to deal with the i18n'ing of HTML files.
vAPI.i18n.render = function(context) { vAPI.i18n.render = function(context) {
uDom('[data-i18n]', context).forEach(function(elem) {
elem.html(vAPI.i18n(elem.attr('data-i18n')));
});
var docu = document,
root = context || docu,
elems, n, i, elem, text;
elems = root.querySelectorAll('[data-i18n]');
n = elems.length;
for ( i = 0; i < n; i++ ) {
elem = elems[i];
text = vAPI.i18n(elem.getAttribute('data-i18n'));
if ( !text ) { continue; }
// TODO: remove once it's all replaced with <input type="...">
if ( text.indexOf('{') !== -1 ) {
text = text.replace(/\{\{input:([^}]+)\}\}/g, '<input type="$1">');
}
safeTextToDOM(text, elem);
}
uDom('[title]', context).forEach(function(elem) { uDom('[title]', context).forEach(function(elem) {
var title = vAPI.i18n(elem.attr('title')); var title = vAPI.i18n(elem.attr('title'));

Loading…
Cancel
Save