From 5effeb16d1eaf4bc327a4d28af0d7f1a1cf341e6 Mon Sep 17 00:00:00 2001 From: Peter deHaan Date: Mon, 31 Jul 2017 14:34:28 -0700 Subject: [PATCH 1/3] Generate production locales using 'compare-locales' --- package.json | 22 +++++++++---------- scripts/get-prod-locales.js | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 12 deletions(-) create mode 100755 scripts/get-prod-locales.js diff --git a/package.json b/package.json index ff012aae..3698a880 100644 --- a/package.json +++ b/package.json @@ -46,13 +46,15 @@ "license": "MPL-2.0", "repository": "mozilla/send", "availableLanguages": [ - "en-US", - "zh-TW", - "zh-CN", "cs", + "cy", + "de", + "dsb", + "en-US", + "es-MX", "fr", "fy-NL", - "de", + "hsb", "hu", "it", "ja", @@ -60,19 +62,14 @@ "ms", "nb-NO", "nn-NO", - "pt-PT", "pt-BR", + "pt-PT", "ru", "sk", "sl", - "dsb", - "hsb", - "es-CL", - "es-ES", - "es-MX", "sv-SE", - "tr", - "cy" + "zh-CN", + "zh-TW" ], "scripts": { "build": "npm-run-all build:*", @@ -80,6 +77,7 @@ "build:download": "browserify frontend/src/download.js -g uglifyify -o public/download.js", "build:version": "node scripts/version", "build:l10n": "cp node_modules/l20n/dist/web/l20n.min.js public", + "get-prod-locales": "node scripts/get-prod-locales", "dev": "npm run build && npm start", "format": "prettier '{frontend/src/,scripts/,server/,test/**/!(bundle)}*.js' 'public/*.css' --single-quote --write", "lint": "npm-run-all lint:*", diff --git a/scripts/get-prod-locales.js b/scripts/get-prod-locales.js new file mode 100755 index 00000000..1056a978 --- /dev/null +++ b/scripts/get-prod-locales.js @@ -0,0 +1,43 @@ +const { exec } = require('child_process'); +const fs = require('fs'); + +const pkg = require('../package.json'); +const availableLanguages = pkg.availableLanguages.sort(); + +const compareLocales = + 'compare-locales l10n.toml . `ls public/locales` --data=json'; + +exec(compareLocales, (err, stdout, stderr) => { + if (err) { + console.error(err); + process.exit(1); + } + const missingLocales = (current, package) => + current.filter(locale => !package.includes(locale)); + const { summary } = JSON.parse(stdout); + const locales = Object.keys(summary) + .filter(locale => { + const loc = summary[locale]; + const hasMissing = loc.hasOwnProperty('missing'); + const hasErrors = loc.hasOwnProperty('errors'); + return !hasMissing && !hasErrors; + }) + .sort(); + + if (locales.join(',') !== availableLanguages.join(',')) { + const missingLocales = missingLocales(locales, availableLanguages); + console.log('current 100%:', JSON.stringify(locales)); + console.log('package.json:', JSON.stringify(availableLanguages)); + console.log('missing prod:', JSON.stringify(missingLocales)); + + if (process.argv.includes('--write')) { + const pkgPath = require.resolve('../package.json'); + pkg.availableLanguages = locales; + const str = JSON.stringify(pkg, null, 2) + '\n'; + console.log('Updating /package.json availableLanguages'); + fs.writeFileSync(pkgPath, str, 'utf-8'); + } + } else { + console.log('Production locales are up to date!'); + } +}); From 318964251deb5f8b05a69a25ab7644c419eafa48 Mon Sep 17 00:00:00 2001 From: Peter deHaan Date: Mon, 31 Jul 2017 15:25:29 -0700 Subject: [PATCH 2/3] Fix some linting errors --- scripts/.eslintrc.yml | 3 +++ scripts/get-prod-locales.js | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 scripts/.eslintrc.yml diff --git a/scripts/.eslintrc.yml b/scripts/.eslintrc.yml new file mode 100644 index 00000000..fc3b6e27 --- /dev/null +++ b/scripts/.eslintrc.yml @@ -0,0 +1,3 @@ +rules: + no-console: off + no-process-exit: off diff --git a/scripts/get-prod-locales.js b/scripts/get-prod-locales.js index 1056a978..3d03eab6 100755 --- a/scripts/get-prod-locales.js +++ b/scripts/get-prod-locales.js @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + const { exec } = require('child_process'); const fs = require('fs'); @@ -25,10 +27,10 @@ exec(compareLocales, (err, stdout, stderr) => { .sort(); if (locales.join(',') !== availableLanguages.join(',')) { - const missingLocales = missingLocales(locales, availableLanguages); + const missing = missingLocales(locales, availableLanguages); console.log('current 100%:', JSON.stringify(locales)); console.log('package.json:', JSON.stringify(availableLanguages)); - console.log('missing prod:', JSON.stringify(missingLocales)); + console.log('missing prod:', JSON.stringify(missing)); if (process.argv.includes('--write')) { const pkgPath = require.resolve('../package.json'); From 4f3c2498a60fc24867af588d981d5c24d94987ee Mon Sep 17 00:00:00 2001 From: Peter deHaan Date: Tue, 1 Aug 2017 20:15:45 -0700 Subject: [PATCH 3/3] Add get-prod-locales and lint-locales scripts --- package.json | 6 ++- scripts/.eslintrc.yml | 3 ++ scripts/get-prod-locales.js | 78 +++++++++++++++++++------------------ scripts/lint-locales.js | 51 ++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 38 deletions(-) create mode 100644 scripts/lint-locales.js diff --git a/package.json b/package.json index 3698a880..802e0ff1 100644 --- a/package.json +++ b/package.json @@ -77,12 +77,16 @@ "build:download": "browserify frontend/src/download.js -g uglifyify -o public/download.js", "build:version": "node scripts/version", "build:l10n": "cp node_modules/l20n/dist/web/l20n.min.js public", - "get-prod-locales": "node scripts/get-prod-locales", "dev": "npm run build && npm start", "format": "prettier '{frontend/src/,scripts/,server/,test/**/!(bundle)}*.js' 'public/*.css' --single-quote --write", + "get-prod-locales": "node scripts/get-prod-locales", + "get-prod-locales:write": "npm run get-prod-locales -- --write", "lint": "npm-run-all lint:*", "lint:css": "stylelint 'public/*.css'", "lint:js": "eslint .", + "lint-locales": "node scripts/lint-locales", + "lint-locales:dev": "npm run lint-locales", + "lint-locales:prod": "npm run lint-locales -- --production", "start": "node server/server", "test": "npm-run-all test:*", "test:unit": "mocha test/unit", diff --git a/scripts/.eslintrc.yml b/scripts/.eslintrc.yml index fc3b6e27..dfaf2328 100644 --- a/scripts/.eslintrc.yml +++ b/scripts/.eslintrc.yml @@ -1,3 +1,6 @@ rules: + node/shebang: off + security/detect-child-process: off + no-console: off no-process-exit: off diff --git a/scripts/get-prod-locales.js b/scripts/get-prod-locales.js index 3d03eab6..27c86e26 100755 --- a/scripts/get-prod-locales.js +++ b/scripts/get-prod-locales.js @@ -1,45 +1,49 @@ -/* eslint-disable no-console */ +#!/usr/bin/env node -const { exec } = require('child_process'); +const cp = require('child_process'); +const { promisify } = require('util'); const fs = require('fs'); - const pkg = require('../package.json'); + const availableLanguages = pkg.availableLanguages.sort(); +const exec = promisify(cp.exec); -const compareLocales = - 'compare-locales l10n.toml . `ls public/locales` --data=json'; +const arrayDiff = (current, package) => + current.filter(locale => !package.includes(locale)); -exec(compareLocales, (err, stdout, stderr) => { - if (err) { +const cmd = 'compare-locales l10n.toml . `ls public/locales` --data=json'; + +exec(cmd) + .then(({ stdout }) => JSON.parse(stdout)) + .then(({ summary }) => { + const locales = Object.keys(summary) + .filter(locale => { + const loc = summary[locale]; + const hasMissing = loc.hasOwnProperty('missing'); + const hasErrors = loc.hasOwnProperty('errors'); + return !hasMissing && !hasErrors; + }) + .sort(); + + if (locales.join(',') !== availableLanguages.join(',')) { + const missingLanguages = arrayDiff(locales, availableLanguages); + + console.log('current 100%:', JSON.stringify(locales)); + console.log('package.json:', JSON.stringify(availableLanguages)); + console.log('missing prod:', JSON.stringify(missingLanguages)); + + if (process.argv.includes('--write')) { + const pkgPath = require.resolve('../package.json'); + pkg.availableLanguages = locales; + const str = JSON.stringify(pkg, null, 2) + '\n'; + console.log('Updating /package.json availableLanguages'); + fs.writeFileSync(pkgPath, str, 'utf-8'); + } + } else { + console.log('Production locales are up to date!'); + } + }) + .catch(err => { console.error(err); process.exit(1); - } - const missingLocales = (current, package) => - current.filter(locale => !package.includes(locale)); - const { summary } = JSON.parse(stdout); - const locales = Object.keys(summary) - .filter(locale => { - const loc = summary[locale]; - const hasMissing = loc.hasOwnProperty('missing'); - const hasErrors = loc.hasOwnProperty('errors'); - return !hasMissing && !hasErrors; - }) - .sort(); - - if (locales.join(',') !== availableLanguages.join(',')) { - const missing = missingLocales(locales, availableLanguages); - console.log('current 100%:', JSON.stringify(locales)); - console.log('package.json:', JSON.stringify(availableLanguages)); - console.log('missing prod:', JSON.stringify(missing)); - - if (process.argv.includes('--write')) { - const pkgPath = require.resolve('../package.json'); - pkg.availableLanguages = locales; - const str = JSON.stringify(pkg, null, 2) + '\n'; - console.log('Updating /package.json availableLanguages'); - fs.writeFileSync(pkgPath, str, 'utf-8'); - } - } else { - console.log('Production locales are up to date!'); - } -}); + }); diff --git a/scripts/lint-locales.js b/scripts/lint-locales.js new file mode 100644 index 00000000..fbcf84ef --- /dev/null +++ b/scripts/lint-locales.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node + +const cp = require('child_process'); +const { promisify } = require('util'); +const pkg = require('../package.json'); +const conf = require('../server/config'); + +const exec = promisify(cp.exec); +const cmd = `compare-locales l10n.toml . ${getLocales()} --data=json`; + +console.log(cmd); + +exec(cmd) + .then(({ stdout }) => JSON.parse(stdout)) + .then(({ details }) => filterErrors(details)) + .then(results => { + if (results.length) { + results.forEach(({ locale, data }) => { + console.log(locale); + data.forEach(msg => console.log(`- ${msg}`)); + console.log(''); + }); + process.exit(2); + } + }) + .catch(err => { + console.error(err); + process.exit(1); + }); + +function filterErrors(details) { + return Object.keys(details) + .sort() + .map(locale => { + const data = details[locale] + .filter(item => item.hasOwnProperty('error')) + .map(({ error }) => error); + return { locale, data }; + }) + .filter(({ data }) => data.length); +} + +function getLocales() { + // If we're in a "production" env (or passed the `--production` flag), only + // check the locales from the package.json file's `availableLanguages` array. + if (conf.env === 'production' || process.argv.includes('--production')) { + return pkg.availableLanguages.sort().join(' '); + } + // Lint all the locales. + return '`ls public/locales`'; +}