diff --git a/.github/workflows/ci-test-frontend.yml b/.github/workflows/ci-test-frontend.yml index e0f08feb..f3aaadcb 100644 --- a/.github/workflows/ci-test-frontend.yml +++ b/.github/workflows/ci-test-frontend.yml @@ -29,3 +29,6 @@ jobs: - run: npm run size working-directory: ./frontend + + - run: npm run check:translation + working-directory: ./frontend diff --git a/frontend/package.json b/frontend/package.json index c77e76c7..b53c0c06 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,6 +5,7 @@ "build": "webpack --mode production && es-check es5 './public/*.js'", "start": "webpack-dev-server --mode development", "check": "tsc -p tsconfig.json --noEmit --skipLibCheck", + "check:translation": "npm run extract-messages && node ./tasks/checkTranslation.js", "lint": "eslint --max-warnings=0 --ext=.ts,.tsx,.js,.jsx .", "lint:style": "stylelint '**/*.scss' '**/*.pcss' '**/*.css' 'iframe.html'", "test": "jest", diff --git a/frontend/tasks/checkTranslation.js b/frontend/tasks/checkTranslation.js new file mode 100644 index 00000000..111246b2 --- /dev/null +++ b/frontend/tasks/checkTranslation.js @@ -0,0 +1,24 @@ +const process = require('process'); +const locales = require('./supportedLocales'); +const { getLocalePath } = require('./getLocalePath'); +const { keys } = require('./getTranslationKeys'); + +const errors = []; + +locales.forEach(locale => { + const dict = require(getLocalePath({ locale })); + const keysFromDict = Object.keys(dict); + keysFromDict.forEach(key => { + if (!keys.includes(key)) { + errors.push( + `"${key}" key not found in "${locale}" locale dict. Please run "npm run generate-langs" and commit changes.` + ); + } + return null; + }); +}); +if (errors.length) { + // eslint-disable-next-line no-console + console.error(errors.join(`\n`)); + process.exit(1); +} diff --git a/frontend/tasks/generateDictionary.js b/frontend/tasks/generateDictionary.js index 0edd5153..53b3e4fb 100644 --- a/frontend/tasks/generateDictionary.js +++ b/frontend/tasks/generateDictionary.js @@ -1,20 +1,14 @@ const fs = require('fs'); const path = require('path'); -const defaultMessages = require('../extracted-messages/messages'); +const { keyMessagePairs, keys } = require('./getTranslationKeys'); +const { getLocalePath } = require('./getLocalePath'); const { renderLoadLocale } = require('./localeLoadTemplate'); const { getSupportedLocales } = require('./getSupportedLocales'); const locales = getSupportedLocales(); -const keyMessagePairs = []; -const keysSet = new Set(); -defaultMessages.forEach(({ id, defaultMessage }) => { - keyMessagePairs.push([id, defaultMessage]); - keysSet.add(id); -}); - function removeAbandonedKeys(existKeys, dictionary) { - return Object.fromEntries(Object.entries(dictionary).filter(([key]) => existKeys.has(key))); + return Object.fromEntries(Object.entries(dictionary).filter(([key]) => existKeys.includes(key))); } function sortDict(dict) { @@ -27,7 +21,7 @@ function sortDict(dict) { locales.forEach(locale => { let currentDict = {}; - const pathToDict = path.resolve(__dirname, `../app/locales/${locale}.json`); + const pathToDict = getLocalePath({ locale }); if (fs.existsSync(pathToDict)) { currentDict = require(pathToDict); } @@ -36,7 +30,7 @@ locales.forEach(locale => { currentDict[key] = defaultMessage; } }); - currentDict = removeAbandonedKeys(keysSet, currentDict); + currentDict = removeAbandonedKeys(keys, currentDict); currentDict = sortDict(currentDict); fs.writeFileSync(pathToDict, JSON.stringify(currentDict, null, 2) + '\n'); fs.writeFileSync( diff --git a/frontend/tasks/getLocalePath.js b/frontend/tasks/getLocalePath.js new file mode 100644 index 00000000..a9f56ace --- /dev/null +++ b/frontend/tasks/getLocalePath.js @@ -0,0 +1,6 @@ +const path = require('path'); +module.exports = { + getLocalePath({ locale }) { + return path.resolve(__dirname, `../app/locales/${locale}.json`); + }, +}; diff --git a/frontend/tasks/getTranslationKeys.js b/frontend/tasks/getTranslationKeys.js new file mode 100644 index 00000000..870a0d70 --- /dev/null +++ b/frontend/tasks/getTranslationKeys.js @@ -0,0 +1,13 @@ +const defaultMessages = require('../extracted-messages/messages'); + +const keyMessagePairs = []; +const keys = []; +defaultMessages.forEach(({ id, defaultMessage }) => { + keyMessagePairs.push([id, defaultMessage]); + keys.push(id); +}); + +module.exports = { + keyMessagePairs, + keys, +};