commit 4e5a50f2b54db62991e4ce3313aa9b7f92a1c573 Author: Arlo Breault arlolra@gmail.com Date: Wed Aug 14 13:45:15 2019 -0400
Start localization
Trac 30310 --- .gitignore | 1 + proxy/init-badge.js | 53 ++++++++++++++++++++++++------- proxy/make.js | 7 ++-- proxy/static/_locales/en_US/messages.json | 32 +++++++++++++++++++ proxy/static/embed.html | 6 ++-- proxy/static/index.html | 2 +- proxy/static/popup.js | 12 +++++++ proxy/webext/embed.js | 25 +++++++++++---- proxy/webext/manifest.json | 3 +- 9 files changed, 115 insertions(+), 26 deletions(-)
diff --git a/.gitignore b/.gitignore index f3af78e..1bae622 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,6 @@ proxy/webext/popup.js proxy/webext/embed.html proxy/webext/embed.css proxy/webext/assets/ +proxy/webext/_locales/ ignore/ npm-debug.log diff --git a/proxy/init-badge.js b/proxy/init-badge.js index dbe7fea..b906f62 100644 --- a/proxy/init-badge.js +++ b/proxy/init-badge.js @@ -4,6 +4,20 @@ UI */
+class Messages { + constructor(json) { + this.json = json; + } + getMessage(m, ...rest) { + let message = this.json[m].message; + return message.replace(/$(\d+)/g, (...args) => { + return rest[Number(args[1]) - 1]; + }); + } +} + +let messages = null; + class BadgeUI extends UI {
constructor() { @@ -16,7 +30,7 @@ class BadgeUI extends UI { missingFeature(missing) { this.popup.setEnabled(false); this.popup.setActive(false); - this.popup.setStatusText("Snowflake is off"); + this.popup.setStatusText(messages.getMessage('popupStatusOff')); this.popup.setStatusDesc(missing, true); this.popup.hideButton(); } @@ -24,20 +38,23 @@ class BadgeUI extends UI { turnOn() { const clients = this.active ? 1 : 0; this.popup.setChecked(true); - this.popup.setToggleText('Turn Off'); - this.popup.setStatusText(`${clients} client${(clients !== 1) ? 's' : ''} connected.`); + this.popup.setToggleText(messages.getMessage('popupTurnOff')); + if (clients > 0) { + this.popup.setStatusText(messages.getMessage('popupStatusOn', String(clients))); + } else { + this.popup.setStatusText(messages.getMessage('popupStatusReady')); + } // FIXME: Share stats from webext - const total = 0; - this.popup.setStatusDesc(`Your snowflake has helped ${total} user${(total !== 1) ? 's' : ''} circumvent censorship in the last 24 hours.`); + this.popup.setStatusDesc(''); this.popup.setEnabled(true); this.popup.setActive(this.active); }
turnOff() { this.popup.setChecked(false); - this.popup.setToggleText('Turn On'); - this.popup.setStatusText("Snowflake is off"); - this.popup.setStatusDesc(""); + this.popup.setToggleText(messages.getMessage('popupTurnOn')); + this.popup.setStatusText(messages.getMessage('popupStatusOff')); + this.popup.setStatusDesc(''); this.popup.setEnabled(false); this.popup.setActive(false); } @@ -108,12 +125,12 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotific ui = new BadgeUI();
if (!Util.hasWebRTC()) { - ui.missingFeature("WebRTC feature is not detected."); + ui.missingFeature(messages.getMessage('popupWebRTCOff')); return; }
if (!Util.hasCookies()) { - ui.missingFeature("Cookies are not enabled."); + ui.missingFeature(messages.getMessage('badgeCookiesOff')); return; }
@@ -153,6 +170,20 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotific return null; };
- window.onload = init; + window.onload = function() { + const lang = 'en_US'; + fetch(`./_locales/${lang}/messages.json`) + .then((res) => { + if (!res.ok) { return; } + return res.json(); + }) + .then((json) => { + messages = new Messages(json); + Popup.fill(document.body, (m) => { + return messages.getMessage(m); + }); + init(); + }); + }
}()); diff --git a/proxy/make.js b/proxy/make.js index 59165b2..58b7fce 100755 --- a/proxy/make.js +++ b/proxy/make.js @@ -32,7 +32,8 @@ var SHARED_FILES = [ 'embed.html', 'embed.css', 'popup.js', - 'assets' + 'assets', + '_locales', ];
var concatJS = function(outDir, init, outFile) { @@ -67,7 +68,7 @@ task('test', 'snowflake unit tests', function() { });
task('build', 'build the snowflake proxy', function() { - execSync('rm -r build'); + execSync('rm -rf build'); execSync('cp -r ' + STATIC + '/ build/'); concatJS('build', 'badge', 'embed.js'); console.log('Snowflake prepared.'); @@ -87,7 +88,7 @@ task('node', 'build the node binary', function() { });
task('clean', 'remove all built files', function() { - execSync('rm -r build test spec/support'); + execSync('rm -rf build test spec/support'); });
var cmd = process.argv[2]; diff --git a/proxy/static/_locales/en_US/messages.json b/proxy/static/_locales/en_US/messages.json new file mode 100644 index 0000000..f9de9d4 --- /dev/null +++ b/proxy/static/_locales/en_US/messages.json @@ -0,0 +1,32 @@ +{ + "appDesc": { + "message": "Snowflake is a WebRTC pluggable transport for Tor." + }, + "popupTurnOn": { + "message": "Turn On" + }, + "popupTurnOff": { + "message": "Turn Off" + }, + "popupLearnMore": { + "message": "Learn more" + }, + "popupStatusOff": { + "message": "Snowflake is off" + }, + "popupStatusOn": { + "message": "Number of users currently connected: $1" + }, + "popupStatusReady": { + "message": "Your Snowflake is ready to help users circumvent censorship!" + }, + "popupWebRTCOff": { + "message": "WebRTC feature is not detected." + }, + "popupDescOn": { + "message": "Number of users your Snowflake has helped circumvent censorship in the last 24 hours: $1" + }, + "badgeCookiesOff": { + "message": "Cookies are not enabled." + } +} diff --git a/proxy/static/embed.html b/proxy/static/embed.html index 441241a..eb75c30 100644 --- a/proxy/static/embed.html +++ b/proxy/static/embed.html @@ -11,18 +11,18 @@ <body> <div id="active"> <div id="statusimg"></div> - <p id="statustext">Snowflake is off</p> + <p id="statustext">__MSG_popupStatusOff__</p> <p id="statusdesc"></p> </div> <div class="b button"> - <label id="toggle" for="enabled">Turn On</label> + <label id="toggle" for="enabled">__MSG_popupTurnOn__</label> <label class="switch"> <input id="enabled" type="checkbox" /> <span class="slider round"></span> </label> </div> <div class="b learn"> - <a target="_blank" href="https://snowflake.torproject.org/">Learn more</a> + <a target="_blank" href="https://snowflake.torproject.org/">__MSG_popupLearnMore__</a> </div> </body> </html> diff --git a/proxy/static/index.html b/proxy/static/index.html index 20fe5c8..5607e07 100644 --- a/proxy/static/index.html +++ b/proxy/static/index.html @@ -86,7 +86,7 @@
<p>Which looks like this:</p>
- <iframe src="embed.html" width="320px" height="200px" frameborder="0" scrolling="no"></iframe> + <iframe src="embed.html" width="320px" height="240px" frameborder="0" scrolling="no"></iframe>
</div> </body> diff --git a/proxy/static/popup.js b/proxy/static/popup.js index 9ff8121..c59f842 100644 --- a/proxy/static/popup.js +++ b/proxy/static/popup.js @@ -38,4 +38,16 @@ class Popup { setToggleText(txt) { document.getElementById('toggle').innerText = txt; } + static fill(n, func) { + switch(n.nodeType) { + case 3: { // Node.TEXT_NODE + const m = /^__MSG_([^_]*)__$/.exec(n.nodeValue); + if (m) { n.nodeValue = func(m[1]); } + break; + } + case 1: // Node.ELEMENT_NODE + n.childNodes.forEach(c => Popup.fill(c, func)); + break; + } + } } diff --git a/proxy/webext/embed.js b/proxy/webext/embed.js index 62c97a5..7e0dac9 100644 --- a/proxy/webext/embed.js +++ b/proxy/webext/embed.js @@ -1,5 +1,12 @@ /* global chrome, Popup */
+// Fill i18n in HTML +window.onload = () => { + Popup.fill(document.body, (m) => { + return chrome.i18n.getMessage(m); + }); +}; + const port = chrome.runtime.connect({ name: "popup" }); @@ -11,8 +18,8 @@ port.onMessage.addListener((m) => { if (missingFeature) { popup.setEnabled(false); popup.setActive(false); - popup.setStatusText("Snowflake is off"); - popup.setStatusDesc("WebRTC feature is not detected.", true); + popup.setStatusText(chrome.i18n.getMessage('popupStatusOff')); + popup.setStatusDesc(chrome.i18n.getMessage('popupWebRTCOff'), true); popup.hideButton(); return; } @@ -21,13 +28,17 @@ port.onMessage.addListener((m) => {
if (enabled) { popup.setChecked(true); - popup.setToggleText('Turn Off'); - popup.setStatusText(`${clients} client${(clients !== 1) ? 's' : ''} connected.`); - popup.setStatusDesc(`Your snowflake has helped ${total} user${(total !== 1) ? 's' : ''} circumvent censorship in the last 24 hours.`); + popup.setToggleText(chrome.i18n.getMessage('popupTurnOff')); + if (clients > 0) { + popup.setStatusText(chrome.i18n.getMessage('popupStatusOn', String(clients))); + } else { + popup.setStatusText(chrome.i18n.getMessage('popupStatusReady')); + } + popup.setStatusDesc((total > 0) ? chrome.i18n.getMessage('popupDescOn', String(total)) : ''); } else { popup.setChecked(false); - popup.setToggleText('Turn On'); - popup.setStatusText("Snowflake is off"); + popup.setToggleText(chrome.i18n.getMessage('popupTurnOn')); + popup.setStatusText(chrome.i18n.getMessage('popupStatusOff')); popup.setStatusDesc(""); } popup.setEnabled(enabled); diff --git a/proxy/webext/manifest.json b/proxy/webext/manifest.json index 8863dbb..7317c67 100644 --- a/proxy/webext/manifest.json +++ b/proxy/webext/manifest.json @@ -2,7 +2,8 @@ "manifest_version": 2, "name": "Snowflake", "version": "0.0.9", - "description": "Snowflake is a WebRTC pluggable transport for Tor.", + "description": "__MSG_appDesc__", + "default_locale": "en_US", "background": { "scripts": ["snowflake.js"], "persistent": true
tor-commits@lists.torproject.org