多语言调整

This commit is contained in:
tianmo committed 2026-10-22 18:51:26 +08:00
1 parent 04de5e5a8e
commit 8bd9154414
23 files changed
+395 -155

No files matched your search

+51 -2
View File
@@ -1,4 +1,4 @@
import { readFile } from 'node:fs/promises'
import { readFile, stat } from 'node:fs/promises'
import { build } from 'esbuild'
const localeCodes = ['zh-CN', 'zh-TW', 'en', 'ja', 'ko', 'fr', 'de', 'pt-BR', 'es']
@@ -7,6 +7,7 @@ const localeMessages = Object.fromEntries(await Promise.all(localeCodes.map(asyn
JSON.parse(await readFile(`src/i18n/locales/${code}.json`, 'utf8')),
])))
const zh = localeMessages['zh-CN']
const presetIndex = JSON.parse(await readFile('public/Preset/index.json', 'utf8'))
function flattenKeys(value, prefix = '') {
const keys = []
@@ -59,6 +60,22 @@ for (const code of localeCodes.slice(1)) {
}
}
for (const preset of presetIndex) {
const file = typeof preset === 'string' ? preset : preset?.file
if (typeof file !== 'string' || !file.trim()) throw new Error('Preset index entry is missing a file')
await stat(`public/Preset/${file}`)
if (typeof preset === 'string' || preset.name == null) continue
if (typeof preset.name === 'string') continue
if (typeof preset.name !== 'object' || Array.isArray(preset.name)) {
throw new Error(`Preset ${file} has an invalid name`)
}
for (const [code, name] of Object.entries(preset.name)) {
if (!localeCodes.includes(code) || typeof name !== 'string' || !name.trim()) {
throw new Error(`Preset ${file} has an invalid ${code} display name`)
}
}
}
const bundled = await build({
entryPoints: ['src/i18n/index.ts'],
bundle: true,
@@ -71,6 +88,38 @@ const i18nModule = await import(
`data:text/javascript;base64,${Buffer.from(bundled.outputFiles[0].contents).toString('base64')}`
)
const presetNamesBundle = await build({
entryPoints: ['src/views/particle-panel/presetNames.ts'],
bundle: true,
format: 'esm',
platform: 'node',
write: false,
logLevel: 'silent',
})
const presetNames = await import(
`data:text/javascript;base64,${Buffer.from(presetNamesBundle.outputFiles[0].contents).toString('base64')}`
)
const parsedPresets = presetNames.parsePresetIndex([
{ file: '8.test.json' },
'9.raw.json',
{ file: 'old.json', name: 'Old Preset' },
{ file: 'partial.json', name: { ja: '日本語プリセット' } },
])
if (parsedPresets.length !== 4) throw new Error('Preset compatibility parser rejected legacy entries')
const presetCases = [
[parsedPresets[0], 'zh-CN', '8.test'],
[parsedPresets[1], 'en', '9.raw'],
[parsedPresets[2], 'fr', 'Old Preset'],
[parsedPresets[3], 'ja', '日本語プリセット'],
[parsedPresets[3], 'fr', 'partial'],
]
for (const [preset, locale, expected] of presetCases) {
const actual = presetNames.resolvePresetDisplayName(preset, locale)
if (actual !== expected) {
throw new Error(`Preset fallback failed: expected ${expected}, got ${actual}`)
}
}
const cases = [
[null, ['zh-CN'], 'zh-CN'],
[null, ['zh-Hant-TW'], 'zh-TW'],
@@ -95,4 +144,4 @@ for (const [saved, browserLanguages, expected] of cases) {
}
}
console.log(`i18n 校验通过:${localeCodes.length} 种语言、${zhKeys.length} 个消息键,键与占位符一致,自动语言与缓存优先级正确`)
console.log(`i18n 校验通过:${localeCodes.length} 种语言、${zhKeys.length} 个消息键,预设索引兼容,自动语言与缓存优先级正确`)