From abea5a2416f279de529829022b73fb02883ae94b Mon Sep 17 00:00:00 2001 From: Vit Stanislav Date: Fri, 3 Nov 2017 11:55:40 +0100 Subject: [PATCH 1/4] Convert i18n-scanner command into a webpack plugin - Closes #831 --- config/webpack.config.react.js | 9 +++++ package.json | 1 - src/i18n-scanner.js | 73 ++++++++++++++++++++++------------ 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/config/webpack.config.react.js b/config/webpack.config.react.js index 2c50cb64a..cdba6922b 100644 --- a/config/webpack.config.react.js +++ b/config/webpack.config.react.js @@ -3,6 +3,7 @@ const { resolve } = require('path'); const webpack = require('webpack'); const StyleLintPlugin = require('stylelint-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); +const I18nScannerPlugin = require('../src/i18n-scanner'); /* eslint-enable import/no-extraneous-dependencies */ const entries = { @@ -37,5 +38,13 @@ module.exports = { filename: 'styles.css', allChunks: true, }), + new I18nScannerPlugin({ + translationFunctionNames: ['i18next.t', 'props.t', 'this.props.t', 't'], + outputFilePath: './i18n/locales/en/common.json', + files: [ + './src/**/*.js', + './app/src/**/*.js', + ], + }), ], }; diff --git a/package.json b/package.json index 231cc7b8b..b8f360e51 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "pack": "npm install && npm run build && npm run clean-dist && npm run dist", "pack:win": "cmd /c npm install && npm run clean-build && npm run copy-files && npm run build-prod && npm run build-electron && npm run clean-dist && npm run dist:win", "storybook": "start-storybook -p 6006 -s ./src/", - "i18n-scanner": "node ./src/i18n-scanner.js", "build-storybook": "build-storybook" }, "author": "Lisk Foundation , lightcurve GmbH ", diff --git a/src/i18n-scanner.js b/src/i18n-scanner.js index b4e226240..5f06dc6c2 100644 --- a/src/i18n-scanner.js +++ b/src/i18n-scanner.js @@ -2,38 +2,61 @@ const fs = require('fs'); const glob = require('glob'); const Parser = require('i18next-scanner').Parser; -const translationFunctionNames = ['i18next.t', 'props.t', 'this.props.t', 't']; -const outputFilePath = './src/locales/en/common.json'; - -const translationsSource = JSON.parse(fs.readFileSync(outputFilePath, 'utf8')); - const parser = new Parser({ keySeparator: '>', nsSeparator: '|', }); -const customHandler = function (key, options) { - const value = translationsSource[key] || key; - if (options.context) { - key += `_${options.context}`; +function i18nScanner(params) { + const sourceJSON = fs.readFileSync(params.outputFilePath, 'utf8'); + let translationsSource; + try { + translationsSource = JSON.parse(sourceJSON); + } catch (e) { + process.stderr.write(`i18nScanner: ${e}\n`); + return; } - parser.set(key, value); - if (options.count !== undefined) { - key = `${key}_plural`; - parser.set(key, translationsSource[key] || ''); + + const customHandler = function (key, options) { + const value = translationsSource[key] || key; + if (options.context) { + key += `_${options.context}`; + } + parser.set(key, value); + if (options.count !== undefined) { + key = `${key}_plural`; + parser.set(key, translationsSource[key] || ''); + } + }; + + params.files.map(filePattern => glob.sync(filePattern, {})) + .reduce(((accumulator, files) => [...accumulator, ...files]), []) + .forEach((file) => { + const content = fs.readFileSync(file, 'utf-8'); + parser.parseFuncFromString(content, { list: params.translationFunctionNames }, customHandler); + }); + + const translations = parser.get({ sort: true }).en.translation; + const count = Object.keys(translations).length; + const outputJSON = `${JSON.stringify(translations, null, 2)}\n`; + if (outputJSON !== sourceJSON) { + fs.writeFileSync(params.outputFilePath, outputJSON); + process.stdout.write(`i18nScanner: ${count} translation keys parsed and written to '${params.outputFilePath}'\n`); } -}; +} -const files = glob.sync('./src/**/*.js', {}); -const electronFiles = glob.sync('./app/src/**/*.js', {}); -[...files, ...electronFiles].forEach((file) => { - const content = fs.readFileSync(file, 'utf-8'); - parser.parseFuncFromString(content, { list: translationFunctionNames }, customHandler); -}); +class HelloWorldPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + compiler.plugin('emit', (compilation, callback) => { + i18nScanner(this.options); + callback(); + }); + } +} -const translations = parser.get({ sort: true }).en.translation; -const count = Object.keys(translations).length; -const outputJSON = JSON.stringify(translations, null, 2); -fs.writeFileSync(outputFilePath, `${outputJSON}\n`); -process.stdout.write(`${count} translation keys parsed and written to '${outputFilePath}'`); +module.exports = HelloWorldPlugin; From 3fac0ba5ad5d628460577afcd078ab6e1b49eef9 Mon Sep 17 00:00:00 2001 From: Vit Stanislav Date: Mon, 6 Nov 2017 14:04:04 +0100 Subject: [PATCH 2/4] Fix name of I18nScannerPlugin --- src/i18n-scanner.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n-scanner.js b/src/i18n-scanner.js index 5f06dc6c2..67613c14a 100644 --- a/src/i18n-scanner.js +++ b/src/i18n-scanner.js @@ -46,7 +46,7 @@ function i18nScanner(params) { } } -class HelloWorldPlugin { +class I18nScannerPlugin { constructor(options) { this.options = options; } @@ -59,4 +59,4 @@ class HelloWorldPlugin { } } -module.exports = HelloWorldPlugin; +module.exports = I18nScannerPlugin; From 14f4a8016e8659e1c95d9acbda49660792039e46 Mon Sep 17 00:00:00 2001 From: Vit Stanislav Date: Mon, 6 Nov 2017 14:04:23 +0100 Subject: [PATCH 3/4] Fix i18n-scanner to remove old strings --- src/i18n-scanner.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/i18n-scanner.js b/src/i18n-scanner.js index 67613c14a..10d7d0f0c 100644 --- a/src/i18n-scanner.js +++ b/src/i18n-scanner.js @@ -2,13 +2,12 @@ const fs = require('fs'); const glob = require('glob'); const Parser = require('i18next-scanner').Parser; -const parser = new Parser({ - keySeparator: '>', - nsSeparator: '|', -}); - - function i18nScanner(params) { + const parser = new Parser({ + keySeparator: '>', + nsSeparator: '|', + }); + const sourceJSON = fs.readFileSync(params.outputFilePath, 'utf8'); let translationsSource; try { From a350ac1b49949cb2986915c4c13668200feeec89 Mon Sep 17 00:00:00 2001 From: Vit Stanislav Date: Mon, 6 Nov 2017 14:05:08 +0100 Subject: [PATCH 4/4] Fix pricedButton test not to introduce a new i18n key --- i18n/locales/en/common.json | 1 - src/components/pricedButton/index.test.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/i18n/locales/en/common.json b/i18n/locales/en/common.json index e8b863da3..f2035c3a6 100644 --- a/i18n/locales/en/common.json +++ b/i18n/locales/en/common.json @@ -40,7 +40,6 @@ "Failed to connect to node {{address}}": "Failed to connect to node {{address}}", "Failed to connect: Node {{address}} is not active": "Failed to connect: Node {{address}} is not active", "Fee": "Fee", - "Fee: LSK": "Fee: LSK", "Fee: {{amount}} LSK": "Fee: {{amount}} LSK", "Fee: {{fee}} LSK": "Fee: {{fee}} LSK", "Forget this account": "Forget this account", diff --git a/src/components/pricedButton/index.test.js b/src/components/pricedButton/index.test.js index 46eea1cb4..e9c68c43d 100644 --- a/src/components/pricedButton/index.test.js +++ b/src/components/pricedButton/index.test.js @@ -29,7 +29,7 @@ describe('PricedButton', () => { }); it('renders a span saying "Fee: 5 LSK"', () => { - expect(wrapper.find(`.${styles.fee}`).text()).to.be.equal(i18n.t('Fee: 5 LSK')); + expect(wrapper.find(`.${styles.fee}`).text()).to.be.equal(i18n.t('Fee: {{fee}} LSK', { fee: 5 })); }); it('allows to click on Button', () => {