• 前端页面要支持多语言,项目改造起来好费劲,大家有什么好建议?
  • 发布于 1个月前
  • 207 热度
    7 评论
  • 远行客
  • 0 粉丝 47 篇博客
  •   
当前是先开发的中文版本 web 项目,页面数量挺多的,50 来个 VUE 页面。现在想支持英语,发现从头改造一遍好费劲。每个页面都得调整。想了解下大家开发阶段是怎么做的?新开的项目的时候就支持还是说像我这样先国内版本后国外版本去支持呢?
用户评论
  • 弄潮儿
  • 哈哈哈,这个我上半年也在干,1500 个 thymeleaf 模板页面,做成双语,几个后端和我一起改的,那叫一个难受,没想到啥捷径
  • 2025/8/19 12:04:00 [ 0 ] [ 0 ] 回复
  • 张蜚
  • 改现有项目的话,工作量有点大,我最近也有在改,OP 可以看一下这个翻译的方案,离线+在线翻译,每个页面都自动翻译完之后自己手动设置离线翻译还行,不过可能还需要 ai 润色一下
  • 2025/8/19 11:50:00 [ 0 ] [ 0 ] 回复
  • 离人未归
  • i18n-ally + 人肉提取 没那么复杂的。
    规划翻译字段类型,通用的,枚举的。
    一般枚举的 我会先提取这样的。
    /**
     *$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>

  • 2025/8/19 10:04:00 [ 0 ] [ 0 ] 回复
  • 北船余音
  • 如果是 vue-i18n ,我试过三种做法
    一:单文件自定义块
    ```
    <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.t
    LocaleMessage 是我的翻译文本类型
    大概这样
    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 类型进行限定就能完全消除硬编码
  • 2025/8/19 9:21:00 [ 0 ] [ 0 ] 回复
  • Kily
  • 我们是后期才考虑加国际化的,改造花了半个月。先用脚本提取文字,记录页面上的位置,然后 AI 翻译,手动替换。社区有个方案,编译的时候自动 AI 翻译+替换
  • 2025/8/19 9:12:00 [ 0 ] [ 0 ] 回复