# 多语言

本篇为记录性质的文章。

# 一、背景、历史演变

# 1.1 Word 文档整理汇总

在前某公司,由于翻译(区域运营)同学分布在海外,运营活动的多语言文案都是本地运营先整理中文 word 版本,分发给区域运营,待翻译完后收集并整理交给开发,开发者将文案编写进 json 语言包。

# 1.2 在线 Excel 协同编辑

从 Word 文档摘取文案,手动编写 json 包的效率低下,同时会因为来回修改文案而十分折腾人,考虑到地区不同和多人编辑,调整为在线 excel 协同编辑,这样免去了运营再整理的麻烦。

给出第一列中文文案及其他列的语言码,剩下交给翻译和开发即可。

cn en ru
今年过节不收礼 Free America
收礼只收脑白金 shooting every day

# 1.3 脚本转 Excel 为 JSON 语言包

本地运营解放后,开发也着手提效,手动 copy 文案的方式绝不是技术能接受的。在观摩 Excel 表格结构后,开发想了个办法,把表格第一列当做 json 的 key名,其他列当做该 key 的 value 值。

lang cn en ru
title 今年过节不收礼 Free America заглавие
subtitle 收礼只收脑白金 shooting every day содержание

按以上设计编写脚本,将表格转换成 json, 破费~

[
  {
    "lang": "cn",
    "title": "今年过节不收礼",
    "subtitle": "收礼只收脑白金"
  },
  {
    "lang": "en",
    "title": "Free America",
    "subtitle": "shooting every day"
  },
  {
    "lang": "ru",
    "title": "заглавие",
    "subtitle": "содержание"
  }
]

# 1.4 列表问题

好景不长,很快遇到了列表问题,比如一些规则、步骤说明,一开始无法确定有多少句,并且不同地域规则说明可能多一些少一些,数量不一致。使用steps_1steps_2steps_3固定名的 key 无法根治病痛,于是乎,想到了用序号表达之,表格也就变成了以下模样。

lang cn en ru
title 大象塞进冰箱分几步 push the elephant толкнуть слона
steps[0] 打开冰箱 Free America заглавие
steps[1] 把大象塞进去 shooting every day содержание

脚本将其转换为:

[
  {
    "lang": "cn",
    "title": "大象塞进冰箱分几步",
    "steps": ["打开冰箱", "把大象塞进去"]
  }
  // ...省略其他语种
]

那么只需要for遍历这个steps即可,不再需要大量写死的诸如 steps_1 的 key 。

更复杂的情况下,列表每一项可能是描述事物,是一个对象,这就麻烦了,到了这里应该要处理普适性问题,即 excel 表格需要表达出任意结构的数据。

回顾一下,当我们访问一个对象(结构比较深)某属性时,比如第一个 elephant 的第一个 child, 我们使用 list.elephants[0].childs[0] 来访问到 张思

const list = {
  elephants: [
    {
      name: '张三',
      childs: ['张思', '张武']
    }
  ]
}

那么,我们用同样的方式来描述 excel 某行内容应该处于对象的什么位置。

lang cn en ru
elephants[0].name 张三 san zhang
elephants[0].childs[0] 张思 si zhang
elephants[0].childs[1] 张武 wu zhang

脚本将其转换为

[
  {
    lang: 'cn',
    elephants: [
      {
        name: '张三',
        childs: ['张思', '张武']
      }
    ]
  }
  // ...省略其他语种
]

至此,页面多语言管理方案尚可一战,excel 表格和 json 互转的脚本沉淀为 json-key-string-xlsx (opens new window)

# 二、H5-Raptor 实现

# 2.1 组件多语言而非页面多语言

组件化中台基于组件组装出页面,开发组件时并没有页面的概念,所以我们没法直接像上面那样处理页面多语言。 不过,基于上面的经验,可以让组件捆绑一个 excel 用于记载组件多语言,页面保存时,将多个组件的 excel 合并起来就好了。

组件A

lang cn en ru
title 大象塞进冰箱分几步 push the elephant толкнуть слона

组件B

lang cn en ru
title 今年过节不收礼 Free America заглавие
subtitle 收礼只收脑白金 shooting every day содержание

合并得出页面 excel 如下(lang字段比较特殊)

lang cn en ru
title 大象塞进冰箱分几步 push the elephant толкнуть слона
title 今年过节不收礼 Free America заглавие
subtitle 收礼只收脑白金 shooting every day содержание

从上面表格也能看出 key 名相撞问题,相撞来源可分为以下2种:

  1. 组件使用的 key 名可能重复,多个组件都使用着 title 这个 key.
  2. 单个组件在页面内被复用多次,key 名必定相撞。

key 名相撞导致转换出来的 JSON 出现值覆盖现象,从而造成吞噬文案的问题。

[
  {
    lang: 'cn',
    // title: '大象塞进冰箱分几步', // 这一行将被下一行覆盖
    title: '今年过节不收礼',
    subtitle: '收礼只收脑白金'
  }
  // ...省略其他语种
]

由于单个组件在页面内可能复用多次,所以在编辑页面时,这类中台往往会为加入的组件创建一个页面内唯一id(暂时叫做 hashid),以表达其组件唯一性,这样单个组件复用多次也有不一样的 hashid。

那么,可以用该 hashid 作为命名空间前缀,合并得到的 excel 会是:(假设2个组件的 hashid 分别是:xh86、ab2d)

lang cn en ru
xh86.title 大象塞进冰箱分几步 push the elephant толкнуть слона
ab2d.title 今年过节不收礼 Free America заглавие
ab2d.subtitle 收礼只收脑白金 shooting every day содержание

脚本会将其转换为:

[
  {
    lang: 'cn',
    xh86: {
      title: '大象塞进冰箱分几步'
    },
    ab2d: {
      title: '今年过节不收礼',
      subtitle: '收礼只收脑白金'
    },
  }
  // ...省略其他语种
]

页面渲染时,将xh86这个 key 的值传给hashidxh86的组件,hashid 很好的起到了隔离效果。

# 2.2 多语言结构而非多语言文案

如果文案信息很少的情况下,直接写 json会比编写 excel 再转换为 json更加方便。 正是因为页面多语言文案较多,页面多语言管理用后者方式更加科学。

然后,组件化中台没有明确的页面概念,只有明确的组件,同时,组件也不知道会用在哪些语种下,此时为组件编写多语言并无多大意义,更多需要的是语言的数据结构,文案信息一般都很少,那么为组件编写 excel 反倒显得不合适。

再重新设计一番,为每个组件仅编写中文的 json 文案。

// 组件A
{
  title: '大象塞进冰箱分几步'
}
// 组件B
{
  title: '今年过节不收礼',
  subtitle: '收礼只收脑白金'
}

组件化搭建后的页面,将多个组件的文案 json 汇总起来,以组件的 hashid 为命名空间前缀,得到:

{
  lang: 'cn',
  xh86: {
    title: '大象塞进冰箱分几步'
  },
  ab2d: {
    title: '今年过节不收礼',
    subtitle: '收礼只收脑白金'
  }
}

借助脚本将 json 转为 excel,得到如下表格交给运营。

lang cn
xh86.title 大象塞进冰箱分几步
ab2d.title 今年过节不收礼
ab2d.subtitle 收礼只收脑白金

组件化中台的页面多语言把组件 json 汇总后转 excel会比把各个组件 excel 汇总的效率更高,减少了文件IO耗时和带宽(Excel 文件一般存放 cdn)压力。

# 三、小结

# 3.1 页面多语言管理

针对明确的页面,明确的语种,步骤:

  1. 基于 excel 协同编辑,把表格第一列作为 json 的 key 描述。
  2. 借助脚本转换 excel 成 json。

# 3.2 组件化中台页面多语言实现

无明确页面和语种,只有明确的组件,步骤:

  1. 组件自带单语种文案 json。
  2. 为页面内每个组件创建一个页面内唯一 id,以该 id 为命名空间前缀,得到页面文案大 json。
  3. 将页面文案大 json 转换为 excel。
  4. 同页面多语言管理步骤。

# 3.3 组件化中台单语种编辑

不是所有页面都需要实现多语言,如果语言文案编辑都走 Excel 管理,对单语种需求并不友好。 接触过配置化场景的应该知道动态表单,通过JSON Schema描述来渲染出表单UI(甚至包含逻辑),组件的伸缩能力便是靠此获得。

单语种情况下,可以通过把组件单语种 json 转为 JSON Schema,再通过动态表单库实现表单渲染供运营编辑。

image.png

以 Raptor 为例,通过选项切换单语种、多语种模式,多语种通过 Excel 文件管理。↓

如果是单语种模式,则在组件编辑面板处理:↓

# 示例

Excel 转 JSON 结构。 多语言示例

取某个语种的渲染效果。 多语言示例

切换语种对比。 多语言示例

TIP

有条件的团队可能有多语言管理平台,没条件的情况下可以考虑在线 excel 表格承载翻译文案。无论何种承载方式,都可以参考以上表格和 json 互转的思路。

上次更新: 5/16/2022, 1:55:54 AM