Added a language switcher for snowflake.tp.o

Also modified the styling of the page to match the main tp.o page a bit
more
This commit is contained in:
Cecylia Bocovich 2019-10-09 12:03:43 -04:00
parent f6517f60ce
commit ab96817381
4 changed files with 8228 additions and 98 deletions

8088
proxy/static/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,24 +9,17 @@ body {
font-size: 1.3rem; font-size: 1.3rem;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
background-color: #59316B;
color: #212529; color: #212529;
} }
header { header {
margin: 0; margin: 0;
line-height: 0; background-color: #59316B;
padding: 1.3rem 2.6rem; padding: 0 5.2rem;
}
header a {
border-style: none;
display: inline-block;
line-height: 0;
} }
#content { #content {
max-width: 55rem; max-width: 90rem;
margin: 0 auto 2.6rem auto; margin: 0 auto 2.6rem auto;
padding: 2.6rem 5.2rem; padding: 2.6rem 5.2rem;
background-color: #FFFFFF; background-color: #FFFFFF;
@ -77,6 +70,7 @@ h2 {
} }
.diagram, .screenshot { .diagram, .screenshot {
padding: 2.6rem 5.2rem;
text-align: center; text-align: center;
} }
@ -88,3 +82,13 @@ textarea {
max-width: 100%; max-width: 100%;
width: 600px; width: 600px;
} }
.dropdown:hover .dropdown-menu {
display: block;
height: 350px;
overflow: auto;
}
.pull-right {
float: right !important;
}

View file

@ -4,15 +4,30 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Snowflake</title> <title>Snowflake</title>
<link rel="icon" href="https://snowflake.torproject.org/assets/favicon.ico" /> <link rel="icon" href="./assets/favicon.ico" />
<link rel="stylesheet" href="https://snowflake.torproject.org/index.css" /> <link rel="stylesheet" href="./bootstrap.css" />
<link rel="stylesheet" href="./index.css" />
</head> </head>
<body> <body class="no-gutters">
<header id="header"> <header id="header">
<a href="https://www.torproject.org/">
<img src="https://snowflake.torproject.org/tor-logo@2x.png" alt="Tor" height="50" /> <nav class="navbar no-background navbar-dark bg-dark p-4">
<a class="navbar-brand" href="https://www.torproject.org/">
<img src="./tor-logo@2x.png" alt="Tor" height="50" />
</a> </a>
<div class="btn-group dropdown pull-right">
<button id="language-switcher" type="button" class="btn btn-dark bg-dark dropdown-toggle btn-block my-3 my-sm-0" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
en_US
</button>
<div id="supported-languages" class="dropdown-menu">
</div>
</div>
</nav>
</header> </header>
<div class="container-fluid">
<section id="content"> <section id="content">
<h1>SNOWFLAKE</h1> <h1>SNOWFLAKE</h1>
@ -32,7 +47,7 @@
<p data-msgid="__MSG_censoredUsers__">If your internet access is censored, you should download <p data-msgid="__MSG_censoredUsers__">If your internet access is censored, you should download
<a href="https://www.torproject.org/download/">Tor Browser</a>.</p> <a href="https://www.torproject.org/download/">Tor Browser</a>.</p>
<p class="screenshot"><img src="https://snowflake.torproject.org/screenshot.png" alt="Tor Browser screenshot" /></p> <p class="screenshot"><img src="./screenshot.png" alt="Tor Browser screenshot" /></p>
</section> </section>
<section id="extension" class="extension"> <section id="extension" class="extension">
@ -46,11 +61,11 @@
<p class="addon"> <p class="addon">
<a href="https://addons.mozilla.org/en-US/firefox/addon/torproject-snowflake/"> <a href="https://addons.mozilla.org/en-US/firefox/addon/torproject-snowflake/">
<img src="https://snowflake.torproject.org/firefox150.jpg" alt="Install in Firefox" height="100" /><br /> <img src="./firefox150.jpg" alt="Install in Firefox" height="100" /><br />
<span data-msgid="MSG_installFirefox__">Install in Firefox</span> <span data-msgid="MSG_installFirefox__">Install in Firefox</span>
</a> </a>
<a href="https://chrome.google.com/webstore/detail/snowflake/mafpmfcccpbjnhfhjnllmmalhifmlcie"> <a href="https://chrome.google.com/webstore/detail/snowflake/mafpmfcccpbjnhfhjnllmmalhifmlcie">
<img src="https://snowflake.torproject.org/chrome150.jpg" alt="Install in Chrome" height="100" /><br /> <img src="./chrome150.jpg" alt="Install in Chrome" height="100" /><br />
<span data-msgid="__MSG_installChrome__">Install in Chrome</span> <span data-msgid="__MSG_installChrome__">Install in Chrome</span>
</a> </a>
</p> </p>
@ -96,6 +111,7 @@
</section> </section>
</section> </section>
</div>
<script src="index.js"></script> <script src="index.js"></script>
</body> </body>
</html> </html>

View file

@ -1,9 +1,11 @@
/* global availableLangs */
class Messages { class Messages {
constructor(json) { constructor(json) {
this.json = json; this.json = json;
} }
getMessage(m, ...rest) { getMessage(m, ...rest) {
if (this.json.hasOwnProperty(m)) { if (Object.prototype.hasOwnProperty.call(this.json, m)) {
let message = this.json[m].message; let message = this.json[m].message;
return message.replace(/\$(\d+)/g, (...args) => { return message.replace(/\$(\d+)/g, (...args) => {
return rest[Number(args[1]) - 1]; return rest[Number(args[1]) - 1];
@ -13,11 +15,20 @@ class Messages {
} }
defaultLang = "en_US"; var defaultLang = "en_US";
var getLang = function() { var getLang = function() {
let lang = navigator.language || defaultLang; let lang = navigator.language || defaultLang;
lang = lang.replace(/-/g, '_'); lang = lang.replace(/-/g, '_');
//prioritize override language
var url_string = window.location.href; //window.location.href
var url = new URL(url_string);
var override_lang = url.searchParams.get("lang");
if (override_lang != null) {
lang = override_lang;
}
if (availableLangs.has(lang)) { if (availableLangs.has(lang)) {
return lang; return lang;
} }
@ -31,9 +42,10 @@ var getLang = function() {
var fill = function(n, func) { var fill = function(n, func) {
switch(n.nodeType) { switch(n.nodeType) {
case 1: // Node.ELEMENT_NODE case 1: // Node.ELEMENT_NODE
{
const m = /^__MSG_([^_]*)__$/.exec(n.dataset.msgid); const m = /^__MSG_([^_]*)__$/.exec(n.dataset.msgid);
if (m) { if (m) {
val = func(m[1]); var val = func(m[1]);
if (val != undefined) { if (val != undefined) {
n.innerHTML = val n.innerHTML = val
} }
@ -41,20 +53,30 @@ var fill = function(n, func) {
n.childNodes.forEach(c => fill(c, func)); n.childNodes.forEach(c => fill(c, func));
break; break;
} }
}
} }
console.log("Fetching", `./_locales/${getLang()}/messages.json`);
fetch(`./_locales/${getLang()}/messages.json`) fetch(`./_locales/${getLang()}/messages.json`)
.then((res) => { .then((res) => {
if (!res.ok) { return; } if (!res.ok) { return; }
return res.json(); return res.json();
}) })
.then((json) => { .then((json) => {
messages = new Messages(json); var language = document.getElementById('language-switcher');
console.log("Filling document body"); language.innerText = `${getLang()}`
var messages = new Messages(json);
fill(document.body, (m) => { fill(document.body, (m) => {
console.log("Filling ", m);
return messages.getMessage(m); return messages.getMessage(m);
}); });
}); });
// Populate language swticher list
availableLangs.forEach(function (lang) {
var languageList = document.getElementById('supported-languages');
var link = document.createElement('a');
link.setAttribute('href', '?lang='+lang);
link.setAttribute('class', "dropdown-item");
link.innerText = lang;
languageList.lastChild.after(link);
});