fix: flatten i18n keys (#2483)
This commit is contained in:
@@ -5,11 +5,15 @@ import path from 'node:path';
|
|||||||
import { format } from 'prettier';
|
import { format } from 'prettier';
|
||||||
|
|
||||||
import { getAllProjectLanguages, getRemoteTranslations } from './api.js';
|
import { getAllProjectLanguages, getRemoteTranslations } from './api.js';
|
||||||
import type { TranslationRes } from './utils.js';
|
import { flattenTranslation, type TranslationRes } from './utils.js';
|
||||||
|
|
||||||
|
const INDENT = 2;
|
||||||
const RES_DIR = path.resolve(process.cwd(), 'src', 'resources');
|
const RES_DIR = path.resolve(process.cwd(), 'src', 'resources');
|
||||||
|
|
||||||
const countKeys = (obj: TranslationRes) => {
|
const countKeys = (obj: TranslationRes | null) => {
|
||||||
|
if (!obj) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
let count = 0;
|
let count = 0;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
Object.entries(obj).forEach(([_, value]) => {
|
Object.entries(obj).forEach(([_, value]) => {
|
||||||
@@ -42,6 +46,12 @@ const getBaseTranslations = async (baseLanguage: { tag: string }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
|
try {
|
||||||
|
fs.access(RES_DIR);
|
||||||
|
} catch (error) {
|
||||||
|
fs.mkdir(RES_DIR);
|
||||||
|
console.log('Create directory', RES_DIR);
|
||||||
|
}
|
||||||
console.log('Loading project languages...');
|
console.log('Loading project languages...');
|
||||||
const languages = await getAllProjectLanguages();
|
const languages = await getAllProjectLanguages();
|
||||||
const baseLanguage = languages.find(language => language.base);
|
const baseLanguage = languages.find(language => language.base);
|
||||||
@@ -58,11 +68,17 @@ const main = async () => {
|
|||||||
console.log(`Loading ${language.tag} translations...`);
|
console.log(`Loading ${language.tag} translations...`);
|
||||||
const translations = await getRemoteTranslations(language.tag);
|
const translations = await getRemoteTranslations(language.tag);
|
||||||
const keyNum = countKeys(translations);
|
const keyNum = countKeys(translations);
|
||||||
|
const completeRate = Number((keyNum / baseKeyNum).toFixed(3));
|
||||||
|
console.log(
|
||||||
|
`Load ${language.name} ${
|
||||||
|
completeRate * 100
|
||||||
|
}, %(${keyNum}/${baseKeyNum}) complete`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...language,
|
...language,
|
||||||
translations,
|
translations,
|
||||||
completeRate: keyNum / baseKeyNum,
|
completeRate,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -81,10 +97,10 @@ const main = async () => {
|
|||||||
{
|
{
|
||||||
'// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.':
|
'// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.':
|
||||||
'',
|
'',
|
||||||
...language.translations,
|
...flattenTranslation(language.translations),
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
4
|
INDENT
|
||||||
) + '\n'
|
) + '\n'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -92,7 +108,7 @@ const main = async () => {
|
|||||||
console.log('Generating meta data...');
|
console.log('Generating meta data...');
|
||||||
const code = `// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
const code = `// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
// Run \`yarn run download-resources\` to regenerate.
|
// Run \`yarn run download-resources\` to regenerate.
|
||||||
// To overwrite this, please overwrite download.ts script.
|
// If you need to update the code, please edit \`i18n/src/scripts/download.ts\` inside your project.
|
||||||
${availableLanguages
|
${availableLanguages
|
||||||
.map(
|
.map(
|
||||||
language =>
|
language =>
|
||||||
@@ -100,14 +116,16 @@ const main = async () => {
|
|||||||
language.tag
|
language.tag
|
||||||
}.json'`
|
}.json'`
|
||||||
)
|
)
|
||||||
|
.sort()
|
||||||
.join('\n')}
|
.join('\n')}
|
||||||
|
|
||||||
export const LOCALES = [
|
export const LOCALES = [
|
||||||
${availableLanguages
|
${availableLanguages
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- omit key
|
||||||
.map(({ translations, ...language }) =>
|
.map(({ translations, ...language }) =>
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
...language,
|
...language,
|
||||||
|
// a trick to generate a string without quotation marks
|
||||||
res: '__RES_PLACEHOLDER',
|
res: '__RES_PLACEHOLDER',
|
||||||
}).replace(
|
}).replace(
|
||||||
'"__RES_PLACEHOLDER"',
|
'"__RES_PLACEHOLDER"',
|
||||||
@@ -124,7 +142,7 @@ const main = async () => {
|
|||||||
parser: 'typescript',
|
parser: 'typescript',
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
trailingComma: 'es5',
|
trailingComma: 'es5',
|
||||||
tabWidth: 4,
|
tabWidth: INDENT,
|
||||||
arrowParens: 'avoid',
|
arrowParens: 'avoid',
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,35 @@
|
|||||||
export interface TranslationRes {
|
export interface TranslationRes {
|
||||||
[x: string]: string | TranslationRes;
|
[x: string]: string | TranslationRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively flattens a JSON object using dot notation.
|
||||||
|
*
|
||||||
|
* NOTE: input must be an object as described by JSON spec. Arbitrary
|
||||||
|
* JS objects (e.g. {a: () => 42}) may result in unexpected output.
|
||||||
|
* MOREOVER, it removes keys with empty objects/arrays as value (see
|
||||||
|
* examples bellow).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* flattenTranslation({a: 1, b: [{c: 2, d: {e: 3}}, 4]})
|
||||||
|
* // {a: 1, b.0.c: 2, b.0.d.e: 3, b.1: 4}
|
||||||
|
* flattenTranslation({a: 1, b: [{c: 2, d: {e: [true, false, {f: 1}]}}]})
|
||||||
|
* // {a: 1, b.0.c: 2, b.0.d.e.0: true, b.0.d.e.1: false, b.0.d.e.2.f: 1}
|
||||||
|
* flattenTranslation({a: 1, b: [], c: {}})
|
||||||
|
* // {a: 1}
|
||||||
|
*
|
||||||
|
* @param obj item to be flattened
|
||||||
|
*/
|
||||||
|
export const flattenTranslation = (
|
||||||
|
obj: string | TranslationRes,
|
||||||
|
path?: string
|
||||||
|
): TranslationRes => {
|
||||||
|
if (!(obj instanceof Object)) return { [path ?? '']: obj };
|
||||||
|
|
||||||
|
return Object.keys(obj).reduce((output, key) => {
|
||||||
|
return {
|
||||||
|
...output,
|
||||||
|
...flattenTranslation(obj[key], path ? path + '.' + key : key),
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user