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,98 +4,114 @@
<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>
<a class="navbar-brand" href="https://www.torproject.org/">
<img src="./tor-logo@2x.png" alt="Tor" height="50" />
</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>
<section id="content"> <div class="container-fluid">
<h1>SNOWFLAKE</h1> <section id="content">
<h1>SNOWFLAKE</h1>
<p class="diagram"><img src="https://trac.torproject.org/projects/tor/raw-attachment/wiki/doc/Snowflake/snowflake-schematic.png" alt="Diagram" /></p> <p class="diagram"><img src="https://trac.torproject.org/projects/tor/raw-attachment/wiki/doc/Snowflake/snowflake-schematic.png" alt="Diagram" /></p>
<p data-msgid="__MSG_websiteIntro__">Snowflake is a system to defeat internet censorship. People who are <p data-msgid="__MSG_websiteIntro__">Snowflake is a system to defeat internet censorship. People who are
censored can use Snowflake to access the internet. Their connection goes censored can use Snowflake to access the internet. Their connection goes
through Snowflake proxies, which are run by volunteers. For more detailed through Snowflake proxies, which are run by volunteers. For more detailed
information about how Snowflake works see our information about how Snowflake works see our
<a href="https://trac.torproject.org/projects/tor/wiki/doc/Snowflake/" data-msgid="__MSG_docWiki__">documentation wiki</a>.</p> <a href="https://trac.torproject.org/projects/tor/wiki/doc/Snowflake/" data-msgid="__MSG_docWiki__">documentation wiki</a>.</p>
<div class="sidebyside"> <div class="sidebyside">
<section id="browser" class="browser"> <section id="browser" class="browser">
<h2 data-msgid="__MSG_browser__">Browser</h2> <h2 data-msgid="__MSG_browser__">Browser</h2>
<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">
<h2 data-msgid="__MSG_extension__">Extension</h2> <h2 data-msgid="__MSG_extension__">Extension</h2>
<p data-msgid="__MSG_installExtension__">If your internet access is <strong>not</strong> censored, you should <p data-msgid="__MSG_installExtension__">If your internet access is <strong>not</strong> censored, you should
consider installing the Snowflake extension to help users in censored consider installing the Snowflake extension to help users in censored
networks. There is no need to worry about which websites people are networks. There is no need to worry about which websites people are
accessing through your proxy. Their visible browsing IP address will accessing through your proxy. Their visible browsing IP address will
match their Tor exit node, not yours.</p> match their Tor exit node, not yours.</p>
<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>
</section>
</div>
<section id="bugs">
<h2 data-msgid="__MSG_reportingBugs__">Reporting Bugs</h2>
<p data-msgid="__MSG_fileBug__">If you encounter problems with Snowflake as a client or a proxy,
please consider filing a bug. To do so, you will have to,</p>
<ol>
<li data-msgid="__MSG_sharedAccount__">
Either <a href="https://trac.torproject.org/projects/tor/register">create an
account</a> or <a href="https://trac.torproject.org/projects/tor/login">log in</a>
using the shared <b>cypherpunks</b> account with password <b>writecode</b>.</li>
<li data-msgid="__MSG_bugTracker__">
<a href="https://trac.torproject.org/projects/tor/newticket?component=Circumvention%2FSnowflake">File a ticket</a>
using our bug tracker.</li>
</ol>
<p data-msgid="__MSG_descriptive__">
Please try to be as descriptive as possible with your ticket and if
possible include log messages that will help us reproduce the bug.
Consider adding keywords <em>snowflake-webextension</em> or <em>snowflake-client</em>
to let us know how which part of the Snowflake system is experiencing
problems.
</p> </p>
</section> </section>
</div> <section id="embed">
<h2 data-msgid="__MSG_embed__">Embed</h2>
<section id="bugs"> <p data-msgid="__MSG_possible__">It is now possible to embed the Snowflake badge on any website:</p>
<h2 data-msgid="__MSG_reportingBugs__">Reporting Bugs</h2>
<p data-msgid="__MSG_fileBug__">If you encounter problems with Snowflake as a client or a proxy, <textarea readonly>&lt;iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;</textarea>
please consider filing a bug. To do so, you will have to,</p>
<ol> <p data-msgid="__MSG_looksLike__">Which looks like this:</p>
<li data-msgid="__MSG_sharedAccount__">
Either <a href="https://trac.torproject.org/projects/tor/register">create an <iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
account</a> or <a href="https://trac.torproject.org/projects/tor/login">log in</a> </section>
using the shared <b>cypherpunks</b> account with password <b>writecode</b>.</li>
<li data-msgid="__MSG_bugTracker__">
<a href="https://trac.torproject.org/projects/tor/newticket?component=Circumvention%2FSnowflake">File a ticket</a>
using our bug tracker.</li>
</ol>
<p data-msgid="__MSG_descriptive__">
Please try to be as descriptive as possible with your ticket and if
possible include log messages that will help us reproduce the bug.
Consider adding keywords <em>snowflake-webextension</em> or <em>snowflake-client</em>
to let us know how which part of the Snowflake system is experiencing
problems.
</p>
</section> </section>
</div>
<section id="embed">
<h2 data-msgid="__MSG_embed__">Embed</h2>
<p data-msgid="__MSG_possible__">It is now possible to embed the Snowflake badge on any website:</p>
<textarea readonly>&lt;iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;</textarea>
<p data-msgid="__MSG_looksLike__">Which looks like this:</p>
<iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
</section>
</section>
<script src="index.js"></script> <script src="index.js"></script>
</body> </body>
</html> </html>

View file

@ -1,23 +1,34 @@
/* 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];
}); });
} }
} }
} }
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,30 +42,41 @@ 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
} }
} }
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()}`
fill(document.body, (m) => { var messages = new Messages(json);
console.log("Filling ", m); fill(document.body, (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);
});