前端页面支持多语言 I8N 改造当前项目好费劲 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
ljlljl0
V2EX    程序员

前端页面支持多语言 I8N 改造当前项目好费劲

  •  
  •   ljlljl0 55 天前 2446 次点击
    这是一个创建于 55 天前的主题,其中的信息可能已经有所发展或是发生改变。
    当前是先开发的中文版本 web 项目,页面数量挺多的,50 来个 VUE 页面。现在想支持英语,发现从头改造一遍好费劲。每个页面都得调整。

    想了解下大家开发阶段是怎么做的?新开的项目的时候就支持还是说像我这样先国内版本后国外版本去支持呢?
    17 条回复    2025-08-19 22:04:40 +08:00
    apkapb
        1
    apkapb  
       55 天前
    半途添加肯定麻烦,慢慢纵使 ai 弄呗。


    最开始老虎到 i18n ,做起来就稍微简单点
    MzM2ODkx
        2
    MzM2ODkx  
       55 天前
    我们是后期才考虑加国际化的,改造花了半个月。先用脚本提取文字,记录页面上的位置,然后 AI 翻译,手动替换。

    社区有个方案,编译的时候自动 AI 翻译+替换
    kinfuy
        3
    kinfuy  
       55 天前
    Ketteiron
        4
    Ketteiron  
       55 天前
    如果是 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 类型进行限定就能完全消除硬编码
    zhuangzhuang1988
        5
    zhuangzhuang1988  
       55 天前
    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>
    zhuangzhuang1988
        6
    zhuangzhuang1988  
       55 天前 via Android
    提取翻译不是难的,难得是页面排版,特别是中文几个字,到英文变成了十几个字,页面各种乱
    raolight
        7
    raolight  
       55 天前
    改现有项目的话,工作量有点大,我最近也有在改,OP 可以看一下这个翻译的方案,离线+在线翻译,每个页面都自动翻译完之后自己手动设置离线翻译还行,不过可能还需要 ai 润色一下

    https://translate.zvo.cn/
    ljlljl0
        8
    ljlljl0  
    OP
       55 天前
    @zhuangzhuang1988 之前翻译过一次,也遇到这个问题了,后面放弃了。最近项目完善了,还是要回头重新搞,太头疼了。
    zhuangzhuang1988
        9
    zhuangzhuang1988  
       54 天前
    @ljlljl0 我也是,就一个新加坡客户,要加英文,翻译得累死
    lisongeee
        10
    lisongeee  
       54 天前
    只是想快速提取的话,可以试试 https://github.com/lisonge/i18n-ast-convert
    Thecosy
        11
    Thecosy  
       53 天前
    我直接用 claude 一键 i18 了。半天搞定。https://www.icecmspro.com
    ljlljl0
        12
    ljlljl0  
    OP
       53 天前
    @Thecosy 我项目内容太多了。另外我看你这个好像内容没有转,只是菜单支持的吧,内容多了这块 AI 也不太好用。
    itodouble657
        13
    itodouble657  
       53 天前
    我也有个疑惑 后台表怎么设计比较好 例如公告、消息提醒还有各种文档的中英文
    xiaogenban
        14
    xiaogenban  
       53 天前
    哈哈哈,这个我上半年也在干,1500 个 thymeleaf 模板页面,做成双语,几个后端和我一起改的,那叫一个难受,没想到啥捷径
    laobaiguolai
        15
    laobaiguolai  
       53 天前
    免费使用,几行代码就搞定。https://translate.zvo.cn/4019.html
    eyelly
        16
    eyelly  
       52 天前
    ljlljl0
        17
    ljlljl0  
    OP
       51 天前
    手动翻译了,目前还比较顺利,估计在有一周能翻译完。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana &nbp;   5626 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 38ms UTC 06:33 PVG 14:33 LAX 23:33 JFK 02:33
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86