mirror of
https://github.com/elyby/accounts-frontend.git
synced 2025-05-31 14:11:58 +05:30
Remove all *.intl.json files. Move strings to the corresponding views. Implement custom command to build i18n/en.json file
This commit is contained in:
@ -1,186 +0,0 @@
|
||||
/* eslint-env node */
|
||||
/* eslint-disable no-console */
|
||||
import fs from 'fs';
|
||||
import { sync as globSync } from 'glob';
|
||||
import { sync as mkdirpSync } from 'mkdirp';
|
||||
import chalk from 'chalk';
|
||||
import { prompt } from 'inquirer';
|
||||
import localesMap from 'app/i18n';
|
||||
|
||||
const MESSAGES_PATTERN = `${__dirname}/../../build/messages/**/*.json`;
|
||||
const LANG_DIR = `${__dirname}/../app/i18n`;
|
||||
const DEFAULT_LOCALE = 'en';
|
||||
const SUPPORTED_LANGS = [DEFAULT_LOCALE, ...Object.keys(localesMap)];
|
||||
|
||||
interface MessageDescriptor {
|
||||
id: string | number;
|
||||
defaultMessage: string;
|
||||
}
|
||||
|
||||
function buildLocales() {
|
||||
mkdirpSync(LANG_DIR);
|
||||
|
||||
SUPPORTED_LANGS.map((lang) => {
|
||||
const destPath = `${LANG_DIR}/${lang}.json`;
|
||||
const newMessages = readJSON<Record<string, string>>(destPath);
|
||||
|
||||
keysToRename.forEach(([fromKey, toKey]) => {
|
||||
newMessages[toKey] = newMessages[fromKey];
|
||||
delete newMessages[fromKey];
|
||||
});
|
||||
keysToRemove.forEach((key) => {
|
||||
delete newMessages[key];
|
||||
});
|
||||
keysToUpdate.forEach((key) => {
|
||||
newMessages[`--${key}`] = newMessages[key];
|
||||
newMessages[key] = collectedMessages[key];
|
||||
});
|
||||
keysToAdd.forEach((key) => {
|
||||
newMessages[key] = collectedMessages[key];
|
||||
});
|
||||
|
||||
const sortedKeys: Array<string> = Object.keys(newMessages).sort((key1, key2) => {
|
||||
key1 = key1.replace(/^-+/, '');
|
||||
key2 = key2.replace(/^-+/, '');
|
||||
|
||||
return key1 < key2 || !isNotMarked(key1) ? -1 : 1;
|
||||
});
|
||||
|
||||
const sortedNewMessages = sortedKeys.reduce<typeof newMessages>((acc, key) => {
|
||||
acc[key] = newMessages[key];
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
fs.writeFileSync(destPath, `${JSON.stringify(sortedNewMessages, null, 4)}\n`);
|
||||
});
|
||||
}
|
||||
|
||||
function readJSON<T extends {}>(destPath: string): T {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(destPath, 'utf8'));
|
||||
} catch (err) {
|
||||
console.log(chalk.yellow(`Can't read ${destPath}. The new file will be created.`), `(${err.message})`);
|
||||
}
|
||||
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates the default messages that were extracted from the app's
|
||||
* React components via the React Intl Babel plugin. An error will be thrown if
|
||||
* there are messages in different components that use the same `id`. The result
|
||||
* is a flat collection of `id: message` pairs for the app's default locale.
|
||||
*/
|
||||
let idToFileMap: Record<string, Array<string>> = {};
|
||||
let duplicateIds: Array<string | number> = [];
|
||||
const collectedMessages = globSync(MESSAGES_PATTERN)
|
||||
.map<[string, Array<MessageDescriptor>]>((filename) => [filename, JSON.parse(fs.readFileSync(filename, 'utf8'))])
|
||||
.reduce<Record<string, string>>((collection, [file, descriptors]) => {
|
||||
descriptors.forEach(({ id, defaultMessage }) => {
|
||||
if (collection[id]) {
|
||||
duplicateIds.push(id);
|
||||
}
|
||||
|
||||
collection[id] = defaultMessage;
|
||||
idToFileMap[id] = (idToFileMap[id] || []).concat(file);
|
||||
});
|
||||
|
||||
return collection;
|
||||
}, {});
|
||||
|
||||
if (duplicateIds.length) {
|
||||
console.log('\nFound duplicated ids:');
|
||||
duplicateIds.forEach((id) => console.log(`${chalk.yellow(id)}:\n - ${idToFileMap[id].join('\n - ')}\n`));
|
||||
console.log(chalk.red('Please correct the errors above to proceed further!'));
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
duplicateIds = [];
|
||||
idToFileMap = {};
|
||||
|
||||
/**
|
||||
* Making a diff with the previous DEFAULT_LOCALE version
|
||||
*/
|
||||
const defaultMessagesPath = `${LANG_DIR}/${DEFAULT_LOCALE}.json`;
|
||||
const isNotMarked = (value: string) => value.slice(0, 2) !== '--';
|
||||
|
||||
const prevMessages = readJSON<Record<string, string>>(defaultMessagesPath);
|
||||
const prevMessagesMap = Object.entries(prevMessages).reduce((acc, [key, value]) => {
|
||||
if (acc[value]) {
|
||||
acc[value].push(key);
|
||||
} else {
|
||||
acc[value] = [key];
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {} as Record<string, Array<string>>);
|
||||
|
||||
const keysToAdd = Object.keys(collectedMessages).filter((key) => !prevMessages[key]);
|
||||
const keysToRemove: Array<string> = Object.keys(prevMessages)
|
||||
.filter((key) => !collectedMessages[key])
|
||||
.filter(isNotMarked);
|
||||
const keysToUpdate: Array<string> = Object.entries(prevMessages).reduce(
|
||||
(acc, [key, message]) => acc.concat(collectedMessages[key] && collectedMessages[key] !== message ? key : []),
|
||||
[] as Array<string>,
|
||||
);
|
||||
|
||||
const keysToRename: Array<[string, string]> = [];
|
||||
// detect keys to rename, mutating keysToAdd and keysToRemove
|
||||
[...keysToAdd].forEach((toKey) => {
|
||||
const keys = prevMessagesMap[collectedMessages[toKey]] || [];
|
||||
const fromKey = keys.find((key) => keysToRemove.indexOf(key) > -1);
|
||||
|
||||
if (fromKey) {
|
||||
keysToRename.push([fromKey, toKey]);
|
||||
keysToRemove.splice(keysToRemove.indexOf(fromKey), 1);
|
||||
keysToAdd.splice(keysToAdd.indexOf(toKey), 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (!keysToAdd.length && !keysToRemove.length && !keysToUpdate.length && !keysToRename.length) {
|
||||
console.log(chalk.green('Everything is up to date!'));
|
||||
process.exit();
|
||||
}
|
||||
|
||||
console.log(chalk.magenta(`The diff relative to default locale (${DEFAULT_LOCALE}) is:`));
|
||||
|
||||
if (keysToRemove.length) {
|
||||
console.log('The following keys will be removed:');
|
||||
console.log([chalk.red('\n - '), keysToRemove.join(chalk.red('\n - ')), '\n'].join(''));
|
||||
}
|
||||
|
||||
if (keysToAdd.length) {
|
||||
console.log('The following keys will be added:');
|
||||
console.log([chalk.green('\n + '), keysToAdd.join(chalk.green('\n + ')), '\n'].join(''));
|
||||
}
|
||||
|
||||
if (keysToUpdate.length) {
|
||||
console.log('The following keys will be updated:');
|
||||
console.log([chalk.yellow('\n @ '), keysToUpdate.join(chalk.yellow('\n @ ')), '\n'].join(''));
|
||||
}
|
||||
|
||||
if (keysToRename.length) {
|
||||
console.log('The following keys will be renamed:\n');
|
||||
console.log(keysToRename.reduce((str, pair) => [str, pair[0], chalk.yellow(' -> '), pair[1], '\n'].join(''), ''));
|
||||
}
|
||||
|
||||
prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'applyChanges',
|
||||
message: 'Apply changes?',
|
||||
default: true,
|
||||
},
|
||||
]).then(({ applyChanges }) => {
|
||||
if (!applyChanges) {
|
||||
console.log(chalk.red('Aborted'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
buildLocales();
|
||||
|
||||
console.log(chalk.green('All locales was successfuly built'));
|
||||
});
|
@ -19,13 +19,11 @@
|
||||
"inquirer": "^7.1.0",
|
||||
"iso-639-1": "^2.1.3",
|
||||
"json5": "^2.1.3",
|
||||
"mkdirp": "^1.0.4",
|
||||
"progress": "^2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"@types/json5": "^0.0.30",
|
||||
"@types/mkdirp": "^1.0.0",
|
||||
"@types/progress": "^2.0.3",
|
||||
"@types/webpack": "^4.41.13"
|
||||
}
|
||||
|
Reference in New Issue
Block a user