Files
AFFiNE-Mirror/scripts/i18n/download.ts
2023-01-09 11:45:56 +08:00

133 lines
3.9 KiB
TypeScript

// cSpell:ignore Tolgee
import fs from 'node:fs/promises';
import path from 'node:path';
import { format } from 'prettier';
import { getAllProjectLanguages, getRemoteTranslations } from './api';
import type { TranslationRes } from './utils';
const RES_DIR = path.resolve(process.cwd(), 'src', 'resources');
const countKeys = (obj: TranslationRes) => {
let count = 0;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Object.entries(obj).forEach(([_, value]) => {
if (typeof value === 'string') {
count++;
} else {
count += countKeys(value);
}
});
return count;
};
const getBaseTranslations = async (baseLanguage: { tag: string }) => {
try {
const baseTranslationsStr = await fs.readFile(
path.resolve(RES_DIR, `${baseLanguage.tag}.json`),
{ encoding: 'utf8' }
);
const baseTranslations = JSON.parse(baseTranslationsStr);
return baseTranslations;
} catch (e) {
console.error('base language:', JSON.stringify(baseLanguage));
console.error('Failed to read base language', e);
const translations = await getRemoteTranslations(baseLanguage.tag);
await fs.writeFile(
path.resolve(RES_DIR, `${baseLanguage.tag}.json`),
JSON.stringify(translations, null, 4)
);
}
};
const main = async () => {
console.log('Loading project languages...');
const languages = await getAllProjectLanguages();
const baseLanguage = languages.find(language => language.base);
if (!baseLanguage) {
console.error(JSON.stringify(languages));
throw new Error('Could not find base language');
}
console.log(`Loading ${baseLanguage.tag} languages translations as base...`);
const baseTranslations = await getBaseTranslations(baseLanguage);
const baseKeyNum = countKeys(baseTranslations);
const languagesWithTranslations = await Promise.all(
languages.map(async language => {
console.log(`Loading ${language.tag} translations...`);
const translations = await getRemoteTranslations(language.tag);
const keyNum = countKeys(translations);
return {
...language,
translations,
completeRate: keyNum / baseKeyNum,
};
})
);
const availableLanguages = languagesWithTranslations.filter(
language => language.completeRate > 0
);
availableLanguages
// skip base language
.filter(i => !i.base)
.forEach(async language => {
await fs.writeFile(
path.resolve(RES_DIR, `${language.tag}.json`),
JSON.stringify(
{
'// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.':
'',
...language.translations,
},
null,
4
) + '\n'
);
});
console.log('Generating meta data...');
const code = `// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
// Run \`pnpm run download-resources\` to regenerate.
// To overwrite this, please overwrite ${path.basename(__filename)}
${availableLanguages
.map(
language =>
`import ${language.tag.replaceAll('-', '_')} from './${
language.tag
}.json'`
)
.join('\n')}
export const LOCALES = [
${availableLanguages
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.map(({ translations, ...language }) =>
JSON.stringify({
...language,
res: '__RES_PLACEHOLDER',
}).replace(
'"__RES_PLACEHOLDER"',
language.tag.replaceAll('-', '_')
)
)
.join(',\n')}
] as const;
`;
await fs.writeFile(
path.resolve(RES_DIR, 'index.ts'),
format(code, {
parser: 'typescript',
singleQuote: true,
trailingComma: 'es5',
tabWidth: 4,
arrowParens: 'avoid',
})
);
console.log('Done');
};
main();