Skip to content
This repository has been archived by the owner on Oct 21, 2022. It is now read-only.

Internationalization feature (i18n) #11

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,221 changes: 557 additions & 664 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"description": "Protect your user's passwords.",
"main": "src/index.js",
"dependencies": {
"i18next": "^17.0.13",
"i18next-browser-languagedetector": "^3.0.3",
"js-sha1": "^0.6.0",
"vex-js": "^4.1.0"
},
Expand All @@ -12,10 +14,11 @@
],
"devDependencies": {
"css-loader": "^0.28.11",
"json-loader": "^0.5.7",
"local-web-server": "^2.5.2",
"style-loader": "^0.21.0",
"webpack": "^4.8.1",
"webpack-cli": "^2.1.3",
"webpack-cli": "^2.1.5",
"webpack-shell-plugin": "^0.5.0"
},
"scripts": {
Expand Down
35 changes: 35 additions & 0 deletions src/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { pt, en } from './locales';

const options = {
interpolation: {
escapeValue: false, // not needed for react!!
},

debug: true,

// lng: 'en',

resources: {
pt: {
common: pt['pt-BR'],
},
en: {
common: en.en,
},
},
joinArrays: '',
fallbackLng: 'en',

ns: ['common'],

defaultNS: 'common',

};

i18n
.use(LanguageDetector)
.init(options);

export default i18n;
17 changes: 17 additions & 0 deletions src/i18n/locales/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"en": {
"breach-email-count": [
"<p>{{description}}</p>",
"<p>The email you entered was one of the <b>{{breach-count}}</b> that were compromised. If you haven't done so already, you should change your password.</p>"
],
"breach-email-alert": "Breach detected!",
"breach-password-count": [
"<p>The password you just entered has been found in <b>{{breach-count}}</b> data breaches. <b>This password is not safe to use</b>.</p>",
"<p>This means attackers can easily find this password online and will often try to access accounts with it.</p>",
"<p>If you are currently using this password, please change it immediately to protect yourself. For more information, visit <a href=\"https://haveibeenpwned.com/\" title=\"haveibeenpwned\">Have I Been Pwned?</a>'",
"<p>This notice will not show again for the duration of this session to give you time to update this password.</p>"
],
"breach-password-alert": "Unsafe password detected!",
"understand": "I Understand"
}
}
17 changes: 17 additions & 0 deletions src/i18n/locales/default.pt-BR.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"pt-BR": {
"breach-email-count": [
"<p>{{description}}</p>",
"<p>O e-mail que voc&ecirc; inseriu &eacute; um dos <b>{{breach-count}}</b> que estavam comprometidos. Voc&ecirc; deveria considerar uma troca de senha.</p>"
],
"breach-email-alert": "Brecha detectada!",
"breach-password-count": [
"<p>A senha que voc&ecirc; acabou de digitar foi localizada em <b>{{breach-count}}</b> bases de dados comprometidas. <b>Esta n&atilde;o &eacute; uma senha segura para ser utilizada.</b>.</p>",
"<p>Isso significa que um invasor pode encontrar facilmente essa senha online. E podem conseguir acessar sua conta com ela.</p>",
"<p>Se voc&ecirc; estiver usando essa senha no momento, altere-a imediatamente para se proteger. Para mais informa&ccedil;&otilde;es visite <a href=\"https://haveibeenpwned.com/\" title=\"haveibeenpwned\">Have I Been Pwned?</a>'",
"<p>Este aviso n&atilde;o ser&aacute; exibido novamente durante a sess&atilde;o, para que voc&ecirc; tenha tempo para atualizar esta senha.</p>"
],
"breach-password-alert": "Senha vulneravel!",
"understand": "Entendi"
}
}
7 changes: 7 additions & 0 deletions src/i18n/locales/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import en from './default.json';
import pt from './default.pt-BR.json';

export {
pt,
en,
};
45 changes: 19 additions & 26 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import * as vex from "../vendor/vex.combined.min.js";
import "../vendor/vex.css";
import "../vendor/vex-theme-wireframe.css";
import "./style.css";

import i18n from './i18n';

/**
* Settings (for the Vex library)
*/
vex.defaultOptions.className = "vex-theme-wireframe";
vex.defaultOptions.escapeButtonCloses = false;
vex.defaultOptions.overlayClosesOnClick = false;
vex.dialog.buttons.YES.text = "I Understand";
vex.dialog.buttons.YES.text = i18n.t("understand");


/**
Expand All @@ -28,11 +28,11 @@ var PASS_PROTECT_PASSWORD_CHECK_URI = "https://api.pwnedpasswords.com/range/";
* Stolen from: https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
*/
function numberFormatter(number, fractionDigits = 0, thousandSeperator = ',', fractionSeperator = '.') {
if (number !==0 && !number || !Number.isFinite(number)) {
if (number !== 0 && !number || !Number.isFinite(number)) {
return number;
}

const frDigits = Number.isFinite(fractionDigits)? Math.min(Math.max(fractionDigits, 0), 7) : 0;
const frDigits = Number.isFinite(fractionDigits) ? Math.min(Math.max(fractionDigits, 0), 7) : 0;
const num = number.toFixed(frDigits).toString();

const parts = num.split('.');
Expand All @@ -47,12 +47,12 @@ function numberFormatter(number, fractionDigits = 0, thousandSeperator = ',', fr
let pos = 0;

while (digits.length > 1) {
final.push(digits.shift());
pos++;
final.push(digits.shift());
pos++;

if (pos % 3 === 0) {
final.push(thousandSeperator);
}
if (pos % 3 === 0) {
final.push(thousandSeperator);
}
}

final.push(digits.shift());
Expand Down Expand Up @@ -141,21 +141,18 @@ function protectEmailInput(evt) {
var xmlHttp = new XMLHttpRequest();
var inputValue = evt.currentTarget.value;

xmlHttp.onreadystatechange = function() {
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var breaches = JSON.parse(xmlHttp.responseText);

for (var i = 0; i < breaches.length; i++) {
if (breaches[i].Domain === host && breaches[i].IsVerified) {
var message = [
'<p>' + breaches[i].Description + '</p>',
'<p>The email you entered was one of the <b>' + numberFormatter(breaches[i].PwnCount) + "</b> that were compromised. If you haven't done so already, you should change your password.</p>"
].join('');
var message = i18n.t('breach-email-count', { 'breach-count': numberFormatter(breaches[i].PwnCount), description: breaches[i].Description });

vex.dialog.alert({
message: "Breach detected!",
message: i18n.t('breach-email-alert'),
input: message,
callback: function() {
callback: function () {
// Cache this email once the user clicks the "I Understand" button
// so we don't continuously annoy the user with the same warnings.
localStorage.setItem(getEmailHash(inputValue), "true");
Expand Down Expand Up @@ -210,25 +207,20 @@ function protectPasswordInput(evt) {
var shortHash = hash.slice(5);
var xmlHttp = new XMLHttpRequest();

xmlHttp.onreadystatechange = function() {
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var resp = xmlHttp.responseText.split("\n");

for (var i = 0; i < resp.length; i++) {
var data = resp[i].split(":");

if (data[0].indexOf(shortHash) === 0) {
var message = [
'<p>The password you just entered has been found in <b>' + numberFormatter(parseInt(data[1])) + '</b> data breaches. <b>This password is not safe to use</b>.</p>',
'<p>This means attackers can easily find this password online and will often try to access accounts with it.</p>',
'<p>If you are currently using this password, please change it immediately to protect yourself. For more information, visit <a href="https://haveibeenpwned.com/" title="haveibeenpwned">Have I Been Pwned?</a>',
'<p>This notice will not show again for the duration of this session to give you time to update this password.</p>'
].join('');
var message = i18n.t('breach-password-count', { 'breach-count': numberFormatter(parseInt(data[1])) });

vex.dialog.alert({
message: "Unsafe password detected!",
message: i18n.t('breach-password-alert'),
input: message,
callback: function() {
callback: function () {
// Cache this password once the user clicks the "I Understand" button
// so we don't continuously annoy the user with the same warnings.
//
Expand Down Expand Up @@ -262,7 +254,7 @@ if (window.attachEvent) {
} else {
if (window.onload) {
var currentOnLoad = window.onload;
var newOnLoad = function(evt) {
var newOnLoad = function (evt) {
currentOnLoad(evt);
protectInputs(evt);
};
Expand All @@ -272,3 +264,4 @@ if (window.attachEvent) {
window.onload = protectInputs;
}
}

Binary file removed test/heroku/assets/glyphicons-halflings-regular.eot?
Binary file not shown.