113 lines
3.4 KiB
JavaScript
113 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Generate strongly-typed i18n key declarations from en-US locale modules.
|
|
*
|
|
* Usage:
|
|
* node scripts/generate-i18n-types.js
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { execSync } = require('child_process');
|
|
|
|
const LOCALES_DIR = path.resolve(__dirname, '../packages/desktop/src/renderer/services/i18n/locales');
|
|
const OUTPUT_FILE = path.resolve(__dirname, '../packages/desktop/src/renderer/services/i18n/i18n-keys.d.ts');
|
|
const OXFMT_BIN = path.resolve(
|
|
__dirname,
|
|
process.platform === 'win32' ? '../node_modules/.bin/oxfmt.exe' : '../node_modules/.bin/oxfmt'
|
|
);
|
|
const i18nConfig = require('../packages/desktop/src/common/config/i18n-config.json');
|
|
const REFERENCE_LANGUAGE = i18nConfig.referenceLanguage;
|
|
const REQUIRED_MODULES = i18nConfig.modules;
|
|
|
|
function getAllKeys(obj, prefix = '') {
|
|
const keys = [];
|
|
|
|
if (typeof obj !== 'object' || obj === null) {
|
|
return keys;
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
if (typeof value === 'object' && value !== null) {
|
|
keys.push(...getAllKeys(value, fullKey));
|
|
} else {
|
|
keys.push(fullKey);
|
|
}
|
|
}
|
|
|
|
return keys;
|
|
}
|
|
|
|
function collectReferenceKeys() {
|
|
const allKeys = new Set();
|
|
|
|
for (const moduleName of REQUIRED_MODULES) {
|
|
const moduleFile = path.join(LOCALES_DIR, REFERENCE_LANGUAGE, `${moduleName}.json`);
|
|
if (!fs.existsSync(moduleFile)) {
|
|
throw new Error(`Missing reference module: ${REFERENCE_LANGUAGE}/${moduleName}.json`);
|
|
}
|
|
|
|
const content = JSON.parse(fs.readFileSync(moduleFile, 'utf-8'));
|
|
for (const key of getAllKeys(content)) {
|
|
allKeys.add(`${moduleName}.${key}`);
|
|
}
|
|
}
|
|
|
|
return Array.from(allKeys).sort();
|
|
}
|
|
|
|
function buildI18nKeysDts(keys) {
|
|
const keyUnion = keys.length > 0 ? keys.map((key) => ` | '${key}'`).join('\n') : ' | never';
|
|
|
|
return `/* eslint-disable */\n/**\n * AUTO-GENERATED FILE - DO NOT EDIT\n * Generated by scripts/generate-i18n-types.js\n */\n\nexport type I18nKey =\n${keyUnion};\n\nexport type I18nModule =\n${REQUIRED_MODULES.map((moduleName) => ` | '${moduleName}'`).join('\n')};\n`;
|
|
}
|
|
|
|
function generateI18nKeysDtsContent() {
|
|
const keys = collectReferenceKeys();
|
|
return buildI18nKeysDts(keys);
|
|
}
|
|
|
|
function formatOutputFile(filePath) {
|
|
const commands = [`bunx prettier --write "${filePath}"`];
|
|
|
|
if (fs.existsSync(OXFMT_BIN)) {
|
|
commands.push(`"${OXFMT_BIN}" "${filePath}"`);
|
|
}
|
|
|
|
for (const command of commands) {
|
|
try {
|
|
execSync(command, { stdio: 'inherit' });
|
|
return;
|
|
} catch {
|
|
// Try the next available formatter.
|
|
}
|
|
}
|
|
|
|
console.warn(`⚠️ Unable to auto-format ${path.relative(process.cwd(), filePath)}. Continuing without formatting.`);
|
|
}
|
|
|
|
function writeOutputFile(content) {
|
|
const current = fs.existsSync(OUTPUT_FILE) ? fs.readFileSync(OUTPUT_FILE, 'utf-8') : null;
|
|
if (current === content) {
|
|
console.log(`✅ i18n key types are up to date: ${path.relative(process.cwd(), OUTPUT_FILE)}`);
|
|
return;
|
|
}
|
|
|
|
fs.writeFileSync(OUTPUT_FILE, content, 'utf-8');
|
|
formatOutputFile(OUTPUT_FILE);
|
|
console.log(`✅ i18n key types generated: ${path.relative(process.cwd(), OUTPUT_FILE)}`);
|
|
}
|
|
|
|
if (require.main === module) {
|
|
const content = generateI18nKeysDtsContent();
|
|
writeOutputFile(content);
|
|
}
|
|
|
|
module.exports = {
|
|
REQUIRED_MODULES,
|
|
collectReferenceKeys,
|
|
generateI18nKeysDtsContent,
|
|
getAllKeys,
|
|
};
|