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:
100
utils/i18n.js
100
utils/i18n.js
@@ -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 || []
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user