Skip to content

i18n国际化

困难:

  • 文本长度不可预测
    • 所有地方都要有弹性
  • 一词多义的翻译错误
  • 语法差异,不同语言的语序不同,比如RTL的语言(这种对css的要求极高,暂不支持)

实现目标的角度:多语言、多币种、多时区

  • 多币种:
    • 这个按照当地规则,转换一下就行。
  • 多时区:
    • 前后端传递时间戳,前端根据时间戳转换为本地时间。
    • 麻烦的点就是,转换之后可能不在同一天,这样用户拿到的签名的时间可能会出现跨天。而如果加上UTC的显示,会比较怪。
    • 传值和存储方案:
      • 传时间戳 -> 无法溯源推断
      • 传时间戳 和 utc 时间
    • 展示的方案:
      • 显示utc+0
        • 不方便,需要手动换算。
      • 显示发生的事情的当前时区的时间(2025-07-25 10:00:00 utc+8)
      • 动态切换为用户本地的时区时间:会丢失原始时间上下文。
      • 显示双时区(utc+0 和 发生事情的时区):太大了,并且用户理解困难。
    • 后端存UTC,接口传UTC,前端转本地
  • 多语言:
    • 文本长度不可预测
      • 所有地方都要有弹性,并且调试的时候全部都要照顾到,可以逐步适配多种语言。
    • 一词多义的翻译错误
    • 语法差异。
      • 不同语言的语序不同(比如中文的主谓宾,英文的宾主谓)
      • RTL的语言(这种对css的要求极高)
      • 不同语言的复数不同(比如 法语还有俄语)
      • 语言的的性别差异,强性别语言做人工审核。
        • 强性别:法/西/德/俄/阿
        • 弱性别:英语
        • 无性别:日/韩/中

多时区:

  • 三种方案,两种情况。

  • 核心场景:(显示)

    • 合同签署,审批节点的时间要特别具体,因此一定要双时间。
      • 出于习惯,都是精确到某一天,比如我的实习合同也是这样的。
        • 但是对于时间戳,一定会精确到某一秒,那么剩下的这一部分,你就只能设置默认。
        • 这样就可能出现,未来的时间或者过去的时间。
      • 早几个小时或者晚几个小时,可能会出现跨天的情况,天数对不上。
      • 合同签署,也会出现未来的时间以及过去的时间。
      • 当时有三个方案:
    • 格式时间选择:尽量不要默认,初始化的时候让用户自己选,然后存起来。
      • 后端存,绑定用户信息。
      • 前端存localStorge。
  • 时间显示:

    • 1,显示事件发生的时间 + 事件发生的时区
      • 缺陷:用户要手动换算
    • 2,显示双时间:
      • 具体:
        • 事件发生的时间 + 事件发生的时区;
        • 用户当地的时间 + 用户的时区
      • 缺陷:在一些小屏场景不太好显示
    • 3,只显示用户当地的时间 + 用户的时区:
      • 在精准度不太高的常见场景适用。
  • 存储场景

    • 排除到存储明文时间的方案,适合人去读,但是不适合计算机。
    • 只存时间戳,会出现信息缺失,不能知道原始时间。

存量项目国际化

  • 使用SDK扫描项目的ast语法树,然后生成key。

  • 使用sdk,key:Value化

  • 尽量遵循代数效应,让组件和逻辑分离,尽量通过高阶组件 (HOC)、Hooks 或者统一的工具函数来注入翻译能力,而不是让每个组件都去关心如何加载语言包。

    • 通过hoc来注入

技术选型

简单函数 (有缺陷)	高阶组件 (HOC)	自定义 Hook (现代方案)	成熟库 (如 react-i18next)

核心思想 全局变量和函数 函数接收组件,返回新组件(属性代理) 在函数组件中复用状态逻辑 提供完整的 HOC、Hooks 和组件 API 自动更新 ❌ 无法实现 ✅ 通过 props 传递实现 ✅ 通过 Hooks 订阅状态实现 ✅ 提供 useTranslation 等 Hooks 使用场景 仅用于非响应式环境 React 类组件或旧版函数组件 React 函数组件 (主流) 各种规模的项目,行业标准 优点 极度简单 逻辑复用、兼容性好 易于理解、避免嵌套地狱、灵活组合 功能全面、社区成熟、最佳实践 缺点 严重缺陷,不可用 Wrapper Hell (组件层级深)、props 来源不明确 只能用于函数组件 对简单项目可能过重,有学习成本 代码示例 t('key') withTranslation(Comp) const { t } = useTranslation() const { t } = useTranslation()

对比了方案:

  • 简单哈希表函数
  • hoc
    • 主要用于类组件,对于函数组件来说,会多一层嵌套。
  • 自定义hook
    • 自己的简易实现
  • 用react-i18next的hook
    • 支持懒加载
    • 因为主要是国际化项目,更加成熟稳定,项目体量也大
    • 会有很多你可能从来没想过的边缘case的坑
      • 比如带性别的语言,出现“两个”,“二十”这种单独作为一个词的语言,可以json里面单独配置它的翻译。而你在代码中,只需要写一次逻辑,他的引擎会自动针对值进行匹配。
    • 任何地方都要弹性,要做很多很细节的防御性设计。
      • css规则:
        • 配置min-width以及nowrap,其他的宽度由内容决定。text-overflow: ellipsis; /* 将溢出的部分显示为... */
        • 根据@container进行容器查询
      • 使用长文本的语言来压测
      • 使用rtl的语言
本站访客数 人次 本站总访问量