Skip to content

Commit

Permalink
start fluent.js for node l10n
Browse files Browse the repository at this point in the history
  • Loading branch information
groovecoder committed Oct 4, 2018
1 parent 29aef58 commit bb8af38
Show file tree
Hide file tree
Showing 19 changed files with 80 additions and 46 deletions.
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ coverage
loadtests
public/dist
public/js/polyfills
public/js/l20n-min.js
1 change: 1 addition & 0 deletions controllers/hibp.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ async function notify (req, res) {
);

if (!notifiedSubscribers.includes(email)) {
// TODO: l10n
await EmailUtils.sendEmail(
email,
"Firefox Monitor Alert : Your account was involved in a breach.",
Expand Down
4 changes: 3 additions & 1 deletion controllers/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function home(req, res) {
featuredBreach = req.app.locals.breaches.filter(breach => breach.Name.toLowerCase() === reqBreachName)[0];
scanFeaturedBreach = true;
}
// TODO: l10n
res.render("monitor", {
title: "Firefox Monitor",
featuredBreach: featuredBreach,
Expand All @@ -22,7 +23,8 @@ function home(req, res) {

function notFound(req, res) {
res.status(404);
res.render("error", { message: "Page not found." });
const message = req.fluentBundle.format(req.fluentBundle.getMessage("notFound"));
res.render("error", { message });
}

module.exports = {
Expand Down
2 changes: 2 additions & 0 deletions controllers/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function init(req, res, next, client = FxAOAuthClient) {

async function confirmed(req, res, next, client = FxAOAuthClient) {
if (!req.session.state) {
// TODO: l10n
throw new Error("Invalid session");
}

Expand All @@ -52,6 +53,7 @@ async function confirmed(req, res, next, client = FxAOAuthClient) {
const email = JSON.parse(data.body).email;
await DB.addSubscriber(email);

// TODO: l10n
res.render("confirm", {
title: "Firefox Monitor : Subscribed",
email: email,
Expand Down
2 changes: 2 additions & 0 deletions controllers/scan.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ async function post (req, res) {
foundBreaches = true;
}
}
// TODO: l10n
res.render("scan", {
title: "Firefox Monitor : Scan Results",
foundBreaches,
Expand All @@ -48,6 +49,7 @@ async function post (req, res) {
}

else {
// TODO: l10n
res.render("scan", {
title: "Firefox Monitor : Scan Results",
foundBreaches,
Expand Down
14 changes: 14 additions & 0 deletions controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ async function add(req, res) {
const email = req.body.email;

if (!email || !isemail.validate(email)) {
// TODO: l10n
throw new Error("Invalid Email");
}
const fxNewsletter = Boolean(req.body.additionalEmails);
Expand All @@ -23,13 +24,15 @@ async function add(req, res) {
const verifyUrl = EmailUtils.verifyUrl(unverifiedSubscriber);
const unsubscribeUrl = EmailUtils.unsubscribeUrl(unverifiedSubscriber);

// TODO: l10n
await EmailUtils.sendEmail(
email,
"Verify your subscription to Firefox Monitor.",
"email_verify",
{ email, verifyUrl, unsubscribeUrl },
);

// TODO: l10n
res.send({
title: "Firefox Monitor : Confirm Email",
});
Expand All @@ -38,6 +41,7 @@ async function add(req, res) {

async function verify(req, res) {
if (!req.query.token) {
// TODO: l10n
throw new Error("Verification token is required.");
}
const verifiedEmailHash = await DB.verifyEmailHash(req.query.token);
Expand All @@ -48,6 +52,7 @@ async function verify(req, res) {
req.app.locals.breaches
);

// TODO: l10n
await EmailUtils.sendEmail(
verifiedEmailHash.email,
"Your Firefox Monitor report",
Expand All @@ -61,6 +66,7 @@ async function verify(req, res) {
}
);

// TODO: l10n
res.render("confirm", {
title: "Firefox Monitor: Subscribed",
email: verifiedEmailHash.email,
Expand All @@ -70,14 +76,17 @@ async function verify(req, res) {

async function getUnsubscribe(req, res) {
if (!req.query.token) {
// TODO: l10n
throw new Error("Unsubscribe requires a token.");
}
const subscriber = await DB.getSubscriberByToken(req.query.token);
//throws error if user backs into and refreshes unsubscribe page
if (!subscriber) {
// TODO: l10n
throw new Error("This email address is not subscribed to Firefox Monitor.");
}

// TODO: l10n
res.render("unsubscribe", {
title: "Firefox Monitor: Unsubscribe",
token: req.query.token,
Expand All @@ -88,11 +97,13 @@ async function getUnsubscribe(req, res) {

async function postUnsubscribe(req, res) {
if (!req.body.token || !req.body.emailHash) {
// TODO: l10n
throw new Error("Unsubscribe requires a token and emailHash.");
}
const unsubscribedUser = await DB.removeSubscriberByToken(req.body.token, req.body.emailHash);
// if user backs into unsubscribe page and clicks "unsubscribe" again
if (!unsubscribedUser) {
// TODO: l10n
throw new Error("This email address is not subscribed to Firefox Monitor.");
}

Expand All @@ -106,8 +117,10 @@ async function postUnsubscribe(req, res) {
function getUnsubSurvey(req, res) {
//throws error if user refreshes unsubscribe survey page after they have submitted an answer
if(!req.session.unsub) {
// TODO: l10n
throw new Error("This email address is not subscribed to Firefox Monitor.");
}
// TODO: l10n
res.render("unsubscribe_survey", {
title: "Firefox Monitor: Unsubscribe Survey",
UNSUB_REASONS,
Expand All @@ -118,6 +131,7 @@ function getUnsubSurvey(req, res) {
function postUnsubSurvey(req, res) {
//clear session in case a user subscribes / unsubscribes multiple times or with multiple email addresses.
req.session.reset();
// TODO: l10n
res.send({
title: "Firefox Monitor: Unsubscribed",
});
Expand Down
1 change: 1 addition & 0 deletions db/DB.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const DB = {
async verifyEmailHash(token) {
const unverifiedSubscriber = await this.getSubscriberByToken(token);
if (!unverifiedSubscriber) {
// TODO: l10n
throw new Error("This email address is not subscribed to Firefox Monitor.");
}
const verifiedSubscriber = await this._verifySubscriber(unverifiedSubscriber);
Expand Down
2 changes: 1 addition & 1 deletion hbs-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function breachDataClasses(dataClasses) {

function prettyDate(date) {
const jsDate = new Date(date);
// TODO: localize this
// TODO: l10n
return jsDate.toLocaleDateString("en-US", {year: "numeric", month: "long", day: "numeric"});
}

Expand Down
3 changes: 3 additions & 0 deletions hibp.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ const HIBP = {
log.info("_throttledGot", {err: "got a 429, tryCount: " + tryCount});
if (tryCount >= AppConstants.HIBP_THROTTLE_MAX_TRIES) {
log.error("_throttledGot", {err: err});
// TODO: l10n
throw new Error("Too many connections to HIBP.");
} else {
tryCount++;
await new Promise(resolve => setTimeout(resolve, AppConstants.HIBP_THROTTLE_DELAY * tryCount));
return await this._throttledGot(url, reqOptions, tryCount);
}
} else {
// TODO: l10n
throw new Error("Error connecting to HIBP.");
}
}
Expand Down Expand Up @@ -80,6 +82,7 @@ const HIBP = {
app.locals.breachesLoadedDateTime = Date.now();
app.locals.mostRecentBreachDateTime = this.getLatestBreachDateTime(breaches);
} catch (error) {
// TODO: l10n
throw new Error("Could not load breaches: " + error);
}
log.info("done-loading-breaches");
Expand Down
34 changes: 34 additions & 0 deletions locale-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use strict";

const fs = require("fs");
const path = require("path");

const { FluentBundle, ftl } = require("fluent");


const localesDir = path.join("public", "locales");


function loadAvailableLanguages () {
return fs.readdirSync( localesDir ).filter(item => {
return (item[0] !== "." && item.length === 2)
});
}


function loadFluentBundles (availableLanguages) {
const fluentBundles = {};
for (const lang of availableLanguages) {
const langBundle = new FluentBundle(lang);
const langFTLSource = fs.readFileSync(path.join(localesDir, lang, "app.ftl"), "utf8");
langBundle.addMessages(langFTLSource);
fluentBundles[lang] = langBundle;
}
return fluentBundles;
}


module.exports = {
loadAvailableLanguages,
loadFluentBundles,
};
13 changes: 4 additions & 9 deletions middleware.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"use strict";

const fs = require("fs");
const path = require("path");

const acceptLanguage = require("accept-language");

Expand All @@ -11,14 +9,11 @@ const mozlog = require("./log");
const log = mozlog("middleware");


function availableLanguages () {
return fs.readdirSync( path.join("public", "locales") );
}


function pickLanguage (req, res, next) {
acceptLanguage.languages(availableLanguages());
req.app.locals.locale = acceptLanguage.get(req.headers["accept-language"]);
acceptLanguage.languages(req.app.locals.AVAILABLE_LANGUAGES);
const pickedLanguage = acceptLanguage.get(req.headers["accept-language"]);
req.locale = pickedLanguage;
req.fluentBundle = req.app.locals.FLUENT_BUNDLES[pickedLanguage];
next();
}

Expand Down
34 changes: 3 additions & 31 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
"express": "^4.16.2",
"express-bearer-token": "^2.2.0",
"express-handlebars": "^3.0.0",
"fluent": "^0.8.1",
"git-rev-sync": "^1.12.0",
"got": "^8.3.1",
"hbs": "^4.0.1",
"helmet": "^3.12.1",
"isemail": "^3.1.3",
"jsdom": "^11.11.0",
"knex": "^0.14.6",
"l20n": "^5.0.0",
"mozlog": "^2.2.0",
"nodemailer": "^4.6.4",
"nodemailer-express-handlebars": "^3.0.0",
Expand Down
2 changes: 2 additions & 0 deletions public/locales/de/app.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ feedback = Feedback geben
terms = Allgemeine Geschäftsbedingungen und Datenschutzerklärung
copyright = Teile dieses Inhalts sind © 1998-2018 von einzelnen mozilla.org-Mitwirkenden. Inhalt verfügbar unter einer Creative Commons-Lizenz
notFound = Seite nicht gefunden.
2 changes: 2 additions & 0 deletions public/locales/en/app.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ feedback = Give Feedback
terms = Terms and Privacy
copyright = Portions of this content are © 1998-2018 by individual mozilla.org contributors. Content available under a Creative Commons license
notFound = Page not found.
4 changes: 4 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const EmailUtils = require("./email-utils");
const HBSHelpers = require("./hbs-helpers");
const HIBP = require("./hibp");
const {pickLanguage, logErrors, clientErrorHandler, errorHandler} = require("./middleware");
const locale = require("./locale-utils");
const mozlog = require("./log");

const HibpRoutes = require("./routes/hibp");
Expand Down Expand Up @@ -101,6 +102,9 @@ app.use(sessions({
cookie: cookie,
}));

const availableLanguages = locale.loadAvailableLanguages();
app.locals.AVAILABLE_LANGUAGES = availableLanguages;
app.locals.FLUENT_BUNDLES = locale.loadFluentBundles(availableLanguages);
app.use(pickLanguage);

if (!AppConstants.DISABLE_DOCKERFLOW) {
Expand Down
1 change: 1 addition & 0 deletions tips.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";
/*eslint-disable quotes */

// TODO: l10n
const TIPS = [
{
"number": "1",
Expand Down
1 change: 1 addition & 0 deletions unsubscribe_reasons.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";

// TODO: l10n
const UNSUB_REASONS = [
{
"id_number": "1",
Expand Down
3 changes: 1 addition & 2 deletions views/layouts/default.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<meta property="og:url" content="{{ SERVER_URL }}" />
<meta property="og:image" content="{{ SERVER_URL }}/img/firefox-monitor.png" />
<meta name="theme-color" content="#002275" />

<meta name="defaultLanguage" content="en">
<meta name="availableLanguages" content="{{ AVAILABLE_LANGUAGES }}">

<link rel="localization" href="/locales/{{ locale }}/app.ftl">

<link rel="stylesheet" href="/dist/app.min.css">
Expand All @@ -22,7 +22,6 @@
<link rel="icon" href="/img/favicons/favicon-128.png" sizes="128x128" />
<link rel="icon" href="/img/favicons/favicon-228.png" sizes="228x228" />

<script type="text/javascript" src="/js/l20n-min.js" defer></script>
<script type="text/javascript" src="/dist/app.min.js" defer></script>

<title>{{ title }}</title>
Expand Down

0 comments on commit bb8af38

Please sign in to comment.