# 多语言
本篇为记录性质的文章。
# 一、背景、历史演变
# 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_1
、steps_2
、steps_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种:
- 组件使用的
key
名可能重复,多个组件都使用着title
这个key
. - 单个组件在页面内被复用多次,
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 的值传给hashid
为xh86
的组件,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 页面多语言管理
针对明确的页面,明确的语种,步骤:
- 基于 excel 协同编辑,把表格第一列作为 json 的 key 描述。
- 借助脚本转换 excel 成 json。
# 3.2 组件化中台页面多语言实现
无明确页面和语种,只有明确的组件,步骤:
- 组件自带单语种文案 json。
- 为页面内每个组件创建一个页面内唯一 id,以该 id 为命名空间前缀,得到页面文案大 json。
- 将页面文案大 json 转换为 excel。
- 同页面多语言管理步骤。
# 3.3 组件化中台单语种编辑
不是所有页面都需要实现多语言,如果语言文案编辑都走 Excel 管理,对单语种需求并不友好。
接触过配置化场景的应该知道动态表单
,通过JSON Schema
描述来渲染出表单UI(甚至包含逻辑),组件的伸缩能力
便是靠此获得。
单语种情况下,可以通过把组件单语种 json 转为 JSON Schema
,再通过动态表单
库实现表单渲染供运营编辑。
以 Raptor 为例,通过选项切换单语种、多语种模式,多语种通过 Excel 文件管理。↓
如果是单语种模式,则在组件编辑面板处理:↓
# 示例
Excel 转 JSON 结构。
取某个语种的渲染效果。
切换语种对比。
TIP
有条件的团队可能有多语言管理平台,没条件的情况下可以考虑在线 excel 表格承载翻译文案。无论何种承载方式,都可以参考以上表格和 json 互转的思路。