[tor-commits] [snowflake/master] Start localization
arlo at torproject.org
arlo at torproject.org
Thu Aug 15 21:16:03 UTC 2019
commit 4e5a50f2b54db62991e4ce3313aa9b7f92a1c573
Author: Arlo Breault <arlolra at 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
More information about the tor-commits
mailing list