Files
SpineParticlesWeb/scripts/verify-i18n.mjs
T
2026-10-22 18:13:43 +08:00

60 lines
2.0 KiB
JavaScript

import { readFile } from 'node:fs/promises'
import { build } from 'esbuild'
const zh = JSON.parse(await readFile('src/i18n/locales/zh-CN.json', 'utf8'))
const en = JSON.parse(await readFile('src/i18n/locales/en.json', 'utf8'))
function flattenKeys(value, prefix = '') {
const keys = []
for (const [key, child] of Object.entries(value)) {
const path = prefix ? `${prefix}.${key}` : key
if (child && typeof child === 'object' && !Array.isArray(child)) {
keys.push(...flattenKeys(child, path))
} else {
keys.push(path)
}
}
return keys.sort()
}
const zhKeys = flattenKeys(zh)
const enKeys = flattenKeys(en)
const missingInEnglish = zhKeys.filter((key) => !enKeys.includes(key))
const missingInChinese = enKeys.filter((key) => !zhKeys.includes(key))
if (missingInEnglish.length || missingInChinese.length) {
throw new Error([
missingInEnglish.length ? `Missing in English: ${missingInEnglish.join(', ')}` : '',
missingInChinese.length ? `Missing in Chinese: ${missingInChinese.join(', ')}` : '',
].filter(Boolean).join('\n'))
}
const bundled = await build({
entryPoints: ['src/i18n/index.ts'],
bundle: true,
format: 'esm',
platform: 'node',
write: false,
logLevel: 'silent',
})
const i18nModule = await import(
`data:text/javascript;base64,${Buffer.from(bundled.outputFiles[0].contents).toString('base64')}`
)
const cases = [
[null, ['zh-CN'], 'zh-CN'],
[null, ['zh-Hant-TW'], 'zh-CN'],
[null, ['en-US'], 'en'],
[null, ['fr-FR'], 'en'],
[null, ['ko-KR', 'en-US'], 'en'],
['en', ['zh-CN'], 'en'],
['zh-CN', ['en-US'], 'zh-CN'],
]
for (const [saved, browserLanguages, expected] of cases) {
const actual = i18nModule.resolveAppLocale(saved, browserLanguages)
if (actual !== expected) {
throw new Error(`Locale resolution failed for ${JSON.stringify(browserLanguages)}: expected ${expected}, got ${actual}`)
}
}
console.log(`i18n 校验通过:${zhKeys.length} 个消息键,中英语言包一致,自动语言与缓存优先级正确`)