Files
2026-07-13 13:20:22 +08:00

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,
};