一直想着把文案国际化的东西整理输出,写了一些零零碎碎的,正好借这个机会整合一下。
一 前言
应用出海不是一个新鲜的话题,其中要针对国内现有应用出海,对应用本身进行国际化支持改造,是必不可少的环节;而这其中很重要的一步就是对应用的文案进行国际化支持,以支持海外用户无障碍的体验使用。
对文案进行国际化支持并不复杂,其结构一般如下图所示
![](https://img.haomeiwen.com/i27208505/1648bfea8aeb460d.png)
图1-1 文案国际化架构
用户修改应用的语言环境配置,应用语言环境发生变更,则应用需要根据当前语言环境获取展示对应的文案。其最核心要解决的技术问题是 1. 语言环境配置管理 2. 字符串资源管理
二 方案分析
落实到我们项目,业务对于文案国际化关键诉求是:
- 支持显示对应语言环境下的文案(先期支持繁体,后续支持英文)
- 支持文案在线更新(全量)
综合业务诉求与技术核心问题,我们来复盘看看最初的方案选择过程
语言环境配置管理
对于用户来说,只要的App的语言环境跟手机语言环境一致,用户使用体验就没有什么影响。移动端应用开发系统框架都提供了直接支持,只需要应用配置好支持的语言环境下的文案资源,并,就能够在用户手机上展示其手机语言环境下的文案展示。
那为什么还需要语言环境配置的管理呢?
其一,应用内容国际化不仅仅是应用端端上文案展示的支持,还存在后端提供的内容国际化的支持,所以需要给到后端相应的语言环境参数
其二,很多国际化的应用会增加一个语言环境配置,即图1中除了系统切换语言环境会有影响外,应用本身也能主动切换影响应用自身的语言环境,同时应用本身的设置通常会包括一个「自动」设置项,用于用户没有设置的时候跟随用户手机系统语言环境。
其三,对于缺省的语言环境设置。一般而言海外应用的缺省语言环境都是英文,但如果是在不同地区多个应用的场景下,设置当地语言作为应用的缺省语言才是最佳选择。
语言环境管理的核心问题就是关于语言环境参数的定义,一般提到参数定义的时候,很容易听到的是中文用zh而英文用en或者中文用1而英文用2这样的说法。事实上我们无需重复造轮子,可以参考系统实现,这里以Android的Locale类的说明
The Locale class implements IETF BCP 47 which is composed of RFC 4647 "Matching of Language Tags" and RFC 5646 "Tags for Identifying Languages" with support for the LDML (UTS#35, "Unicode Locale Data Markup Language") BCP 47-compatible extensions for locale data exchange.
可以看到,对于语言环境的定义,已经有了现成的国际标准,直接使用就行。对于语言环境标准里面没有「自动」业务诉求,可以通过代理模式的思路设计处理解决。
语言环境管理的另一关键问题是语言环境变更通知,需要通知到整个应用发生了语言环境的变更,看起来直接广播通知即可解决。但实际情况存在这样的情况,语言环境的变更之间是存在依赖关系的,比如配置系统的语言环境变更要优先通知。因此整个语言环境的变更通知需要支持优先级控制,且高优先级的通知存在阻塞操作的可能。
字符串资源管理
- 提供统一的字符资源获取接口,即提供类似如下的资源获取即可
String getString(T resId)
String getString(Locale locale,T resId)
这里T代表resId的类型,根据候问提到的字符串资源获取方案,此处最初使用了String作为resId的类型标记,后续迭代方案中增加支持回了int类型
- 获取对应locale的字符资源,需要支持在线更新
作为Android端开发,第一反应肯定是使用资源包的方式提供,但是存在以下限制需要考虑
1)前期开发支持成本。公司当下并不支持资源包生成配置管理发布,整个前期的技术成本就不限于移动端了,同时注意iOS端也需要使用自己的下发方案。
2)持续维护成本。后期的持续使用过程中,产品运营同学怎么能快速配置发布,测试怎么验证变更。
结合上述限制,灵活的使用了当前应用的配置系统,使用json的格式来描述字符串资源进行提供,双端即可实现共同的资源更新管理。
三 实施
方案确定后,具体到开发实施过程中来说,首先遇到的就是实施的体力活,清洗替换项目现有的文案资源,主要是中文字符串资源。
洗
1)字符串来源
![](https://img.haomeiwen.com/i27208505/a4e4d94b3ff7d8ab.png)
图3-1 Android字符串来源
2)利用sed + awk脚本,将符合字符串来源的文案资源洗出。然而发现文案资源规模太大,考虑到后续工作量成本,于是进行了一个比较大胆的操作,对项目中无用的代码布局等资源进行删除操作处理。对比删除前后的洗出字符串,差不多减少了50%以上的文案,这一操作也有效的降低翻译成本。
3)注意日志等调用中的文案无需处理
换
1)提供基础组件。自定义了一系列的支持国际化文案获取的TextView。通过查找替换脚本,可以快速有效的替换布局文件中使用国际化文案的字符串
2)反向替换。将res/string中的id到string的资源,在使用点用string替换对应的id,然后通过string本身,再整体使用洗出来的数据进行映射,映射回我们自定的key上去。
问题处理
下面列举了一些文案处理过程中遇到的问题点
1)文案相关图片资源。存在百张以上图片上包含了文案,考虑到需要重新实现文案背景分离的成本,此处直接通过设计作图替换;但是带来了新的问题是图片资源需要支持国际化资源获取,国际化图片资源需要跟现有的皮肤主题框架的使用兼容
2)微件(Widget),不支持使用自定义ui组件,需要注意此处只能对数据进行替换。
3)依赖关系,原有文案遍布整个项目,导致项目依赖存在循环引用风险,因此新增了国际化模块作为根本,同时剥离了utils库中的文案使用等,以解决依赖风险。
4)三方库,存在使用等三方库中写死文案,通过外部传入,包装,乃至无法处理等躺平接受无法支持等努力进行解决。
5)接口返回,需要给到不同接口放根据不同接口使用时候到语言环境参数。
6)ui缓存,惊了个大呆的是存在缓存dialog这样子的操作,导致替换不生效,解决缓存。
7)不规范的格式导致的问题,比如R.string.XXX能被格式化成R.\nstring.\nxxx等代码格式问题导致的替换处理失败
四 演进
跌跌撞撞的,在以上处理完后就第一个版本的文案国际化方案实施得到落实,后续又持续迭代了两个版本
v2版本:增量更新支持/缺省语言环境配置分包支持
考虑到应用文案改动的概率基本接近于0,实施全量更新实质是对配置资源的浪费,增加了不必要的流量成本,而本地也会保存最新配置,因此从全量更新变更为了增量更新,增加模式选择控制,事实上对于整个获取框架来说并无影响,都是先检查远端配置是否有对应key的内容,没有再从本地获取。
v3版本:开发友好
原来的的使用string作为key的获取文案资源方案,由于双端一次性导致key的平衡结果是使用了字符串,但是为了快速支持使用的是随机字符串,通过key无法方便的获取其代表的字符串,因此v1版本时候通过在获取默认字符串位置放置中文简体文案解决。后续修改为通过Android系统本身的id获取方案,IDE自动转化,有效的降低使用难度体验。具体来说关键技术点为
- 资源的名称跟id转换,解决配置的key是String,而系统提供的是int,用于检测是否存在远端更新替换
- 切换locale获取对应的字符串内容,注意存在系统版本的兼容
五 总结
总结来说就是一个规范的项目将大大降低项目的持续开发维护成本。同时方案的实施也要与项目资源相适应才能有效的开展落实。所以前期的准备估算工作很重要,对于项目的熟悉程度不足的时候不要做风险决定。不过一旦担当了,那就要踏踏实实的去落实解决,尽力达成目标,即
- 使用标准规范定义通用参数
- 代码风格规范
- 考虑研发成本限制,循序渐进
- 熟悉项目
参考
作者:Totoro_uu
链接:https://juejin.cn/post/7139570390371663879
网友评论