refactor: 国际化文本迁移至全局 locales/messages.js

将组件级 i18n 对象重构为统一由全局 locales/messages.js 管理,确保中英文语言切换时正确显示对应文本。

- 新增 utils/i18n.js 国际化工具函数
- 更新 store/$t.mixin.js 翻译混入逻辑
- 迁移 pkgService、pkgBooking、pkgAccount、pkgExplore、pages 等共 58 个组件的中英文文本至全局消息表
This commit is contained in:
liangjian
2026-07-24 13:43:41 +08:00
parent 445bd850f4
commit 6e721ccc7e
58 changed files with 1810 additions and 4065 deletions

View File

@@ -128,3 +128,103 @@ export function pickLocalizedText(options = {}) {
}
return zhText || options.fallback || enText || ''
}
// === 派生扁平字典(中文 → 英文)===
// 从 globalMessages 的 zh/en 双套结构反向派生 {'中文':'英文'} map,
// 供 translateText / $tr 使用。模块加载后懒加载、进程内缓存。
let __flatDictionary = null
let __dictConflicts = null
// 手动裁决的冲突项:键为中文,值为优先采用的英文。
// 当同一中文在 messages.js 不同位置有不同英文译法时,在此指定通用译法;
// 强上下文相关、无法单一裁决的条目,组件内保留 $tm 作为逃生口。
const DICT_OVERRIDES = {}
function buildFlatDictionary() {
if (__flatDictionary) return __flatDictionary
const dict = Object.create(null)
const conflicts = []
const seen = Object.create(null)
// 1. 优先注入手动裁决项
Object.keys(DICT_OVERRIDES).forEach((zh) => {
dict[zh] = DICT_OVERRIDES[zh]
seen[zh] = { en: DICT_OVERRIDES[zh], path: '<override>' }
})
const zhRoot = globalMessages.zh || globalMessages[ZH_LOCALE] || {}
const enRoot = globalMessages.en || globalMessages[EN_LOCALE] || {}
// 2. 平行 DFS:以 zh 叶子(中文)为 key,同路径 en 叶子为 value
function walk(zhNode, enNode, path) {
if (zhNode && typeof zhNode === 'object' && !Array.isArray(zhNode)) {
const keys = Object.keys(zhNode)
for (let i = 0; i < keys.length; i += 1) {
const k = keys[i]
walk(zhNode[k], enNode ? enNode[k] : undefined, path ? path + '.' + k : k)
}
return
}
const zhText = zhNode == null ? '' : String(zhNode)
if (!zhText) return
const enText = enNode == null ? zhText : String(enNode)
if (seen[zhText]) {
if (seen[zhText].en !== enText) {
conflicts.push({
zh: zhText,
enFirst: seen[zhText].en,
enCurrent: enText,
pathFirst: seen[zhText].path,
pathCurrent: path
})
}
// 首次写入优先:已存在则不覆盖
return
}
dict[zhText] = enText
seen[zhText] = { en: enText, path }
}
walk(zhRoot, enRoot, '')
__flatDictionary = dict
__dictConflicts = conflicts
if (process.env.NODE_ENV !== 'production' && conflicts.length) {
console.warn('[i18n] flat dictionary built with ' + conflicts.length + ' conflicts; call getDictionaryConflicts() for details')
}
return dict
}
// 中文即 key 的翻译函数:中文环境原样返回,英文环境查扁平字典,查不到回退中文。
// 支持与 $tm/$translate 一致的 {param} 占位符替换。
export function translateText(text, locale, params = {}) {
if (text === null || text === undefined) return ''
const zhText = String(text)
if (!zhText) return ''
if (normalizeLocale(locale) !== EN_LOCALE) {
return formatI18nText(zhText, params)
}
const dict = buildFlatDictionary()
const enText = dict[zhText]
if (enText === undefined) {
if (process.env.NODE_ENV !== 'production') {
console.warn('[i18n] missing dictionary entry for: ' + zhText)
}
return formatI18nText(zhText, params)
}
return formatI18nText(enText, params)
}
export function getFlatDictionary() {
return buildFlatDictionary()
}
export function getDictionaryConflicts() {
if (!__dictConflicts) buildFlatDictionary()
return __dictConflicts || []
}