type GetI18nKey<T, K extends keyof T = keyof T> =
K extends string ?
T[K] extends Record<string, unknown> ?
`${K}.${GetI18nKey<T[K]>}`
: K
: never
type I18nKey = GetI18nKey<LocaleMessage>
type RouteKey = GetI18nKey<LocaleMessage, 'route'>
type TableKey = GetI18nKey<LocaleMessage, 'table'>
规划翻译字段类型,通用的,枚举的。
一般枚举的 我会先提取这样的。
/** *$t('enum.E_MessageType .Warning') *$t('enum.E_MessageType .Error') */ enum E_MessageType { /** * 警告 */ Warning, /** * 错误 */ Error, }上面注释会被 i18n-ally 识别的,然后提取到翻译。代码层, 页面(模板)层。 注入一个 $enumTrans 的翻译对象。
$enumTrans 包含各种枚举, 可以通过一些 js 动态功能 + ts 类型处理。
类似这样,
<script setup lang="ts"> const { $enumTrans } = useI18nExt() let msgType = E_MessageType.Warning function showMsg() { console.log($enumTrans.MessageType(msgType)) } </script> <template> <div> {{$enumTrans.MessageType(msgType)}} </div> </template>一:单文件自定义块
``` <i18n> { "zh-CN": { "a": "xxx" }, "en-US": { "a": "yyy" } } </i18n> ```优点是可以快速搞定,AI 工具一直 Tab 就行了,大部分时间花在看 vue-i18n 文档,缺点是零散在几十几百个 vue 文件里,适合那种特别老的项目,不想额外管理 i18n 文件,且页面和文字几乎不会再改动。二:json 文件
重构 i18n 确实烦人,但是如果还想正常迭代项目只能重构。将所有中文文本抽离出来,大致分类一下,再让 AI 一次性翻译完英文,然后手动一个个去替换原始文本 t('xxx.yyy')。我建议二层嵌套就行,顶多三层嵌套。
三:ts 文件
事先声明我这属于瞎折腾,用 json 方案就行了。
i18n-ally 和 vue-i18n 在 ts 文件上都有一些坑,搞了好久总算能用了,但是跟 json 方案比差不了多少。
这是我的 i18n-ally 的 vscode 配置文件
"i18n-ally.enabledFrameworks": ["vue"], "i18n-ally.enabledParsers": ["ts"], "i18n-ally.parsers.typescript.compilerOptions": { "moduleResolution": "node" }这样就能正常识别 ts 文件这是我的 i18n/index.ts 文件
import zhCN from './locales/zh-CN' import enUS from './locales/en-US' const messages: Record<I18n.Language, I18n.LocaleMessage> = { 'zh-CN': zhCN, 'en-US': enUS, } const i18n = createI18n({ locale: getStorage(StorageKeyEnum.language, 'zh-CN'), fallbackLocale: 'en', messages, legacy: false, }) export function setupI18n(app: App) { app.use(i18n) } export function setLocale(locale: I18n.Language) { i18n.global.locale.value = locale } export const t = i18n.global.tLocaleMessage 是我的翻译文本类型大概这样
type LocaleMessage = { icon: { ... } route: { ... } tab: { ... } table: { ... } }然后可以递归得到所有 key 的联合类型type GetI18nKey<T, K extends keyof T = keyof T> = K extends string ? T[K] extends Record<string, unknown> ? `${K}.${GetI18nKey<T[K]>}` : K : never type I18nKey = GetI18nKey<LocaleMessage> type RouteKey = GetI18nKey<LocaleMessage, 'route'> type TableKey = GetI18nKey<LocaleMessage, 'table'>在你需要硬编码比如路由元信息等地方用 I18nKey 类型进行限定就能完全消除硬编码