游戏国际化的一些建议

随着国内游戏行业的迅速发展以及竞争的加剧,越来越多的游戏产品开始冲出国门,走向世界。对于国内已经成功上线运营的产品,一般来说发布海外产品不会遇到什么技术上的的瓶颈,常常出现的是发布迟缓、bug频出、版本管理混乱等问题。

本文试图总结游戏国际化的一些经验,主要关于版本管理和文本翻译这两个方面,不讨论跨国运营或部署,不讨论针对不同文化和习惯的本地化等问题。

1. 不要为每个语言版本建立单独分支。

通常项目开始做国际化版本时已经有了一个比较稳定的中文版,开始做国际化版本时为了保证中文版的稳定,常常会新建一个国际化版本分支交给专人去维护,这样一来就掉进了一个大坑。

看起来分支和主干互不影响,能最灵活地应对国际化的特殊需求。实际上主干上开发的新功能最后总是要发布到国际化版本上的,分支上做的修改越多做代码合并的工作量就越大,往往到后来靠一个人就忙不过来了,干脆成立新的项目组独立开发国际化版本——这样无疑是人力资源的极大浪费。

所以合理的做法是不建立分支,开发一个多语言版本的游戏,而不是多个独立的游戏。

2. 尽量不要针对不同地区写特殊代码。

不同语言版本都会有一些特殊的需求,再加上由于设计的问题可能产生某些语言版本上的特殊bug,在不开分支的情况下,开发人员很容易就掉进了第二个坑:在代码中编写大量针对不同地区的特殊代码。

很显然大量的特殊处理代码会削弱代码的可维护性,特别是多加一个语言版本时需要到打大量补丁,进一步使代码变得混乱不堪。

所以不到万不得已,尽量不要针对不同地区写特殊代码,而是使用统一的机制来解决不同版本的差异性。比如不同地区上线不同的运营活动,选择使用配置文件进行控制就比在代码中写死更恰当;比如UI中的文本在某些语言版本中显示不全,与其针对不同语言设置不同的文本框长度,不如统一将文本框拉至合理的长度,当然做成动态改变文本框长度就更好了。

3. 源代码中不能出现汉字或直接用于显示的字符串。

把用于显示的字符串放进统一的字典文件不仅使游戏翻译更简单,也便于策划进行维护,即使不考虑做国际化版本也是很有必要的。只是很多程序员的自控能力比较弱,或者说保持代码可维护的意识比较弱,经常为了一时的快就绕过这个约束,带来不必要的麻烦。

4. 服务器代码或配置中不能出现汉字或直接用于显示的字符串。

游戏中的一些文本其实是服务器生成发往客户端的,例如系统邮件、系统公告等。最佳实践是把服务器做成是语言无关的,服务器发给客户端的是字典Key,客户端根据自己的语言解析后拼装好文本并显示。

这样一来就不需要针对不同的语言版本打不同的服务器版本了,还可以实现多个语言版本连接同一台服务器。

举例说明,现在我们需要系统公告恭喜玩家Alice晋升至等级排行榜第1名,中文客户端有如下字典配置:NoticeRank -> 恭喜玩家#user晋升至#rankName第#rank名LevelRank -> 等级排行榜,服务器发给客户端的消息类似于{Message:"NoticeRank", user:"Alice", rankName:"#LevelRank", rank:"1"},客户端从字典中取出当前语言的文本,再把参数替换进去生成最终显示用的文字。

5. 尽量不要使用带文字的图片。

有时候游戏中为了实现特殊的美术效果,常常把文字直接画在图片资源中,其实这种做法对国际化特别不友好,容易在翻译时遗漏,而且重新制作各种语言的不同图片也增加美术的工作量,还会给资源打包带来一些麻烦,所以建议尽量避免。

如果不得不使用带文字的图片,有以下几点建议供参考:

  1. 开发中使用文档记录所有图片中的文字,并与字典文件一齐交给翻译人员,避免遗漏。
  2. 注意保留图片源文件,便于快速替换。
  3. 体验降级,对品质要求不高的版本可以考虑直接退化成使用系统文字,减少工作量。
  4. 一些常见的游戏术语可以退化成统一使用英文。比如表示暴击的Critical,表示力量的Str.
  5. 订制资源打包脚本,针对不同的语言版本打包不同资源。

6. 设计结构化的字典配置,减少冗余。

结构化的意思是不同的字典词条有层次上的区别,不同的词条是可以互相引用的。

例如上文提到的系统公告中,NoticeRank词条就引用了LevelRank词条。假如不支持词条互相引用,这个功能就需要恭喜玩家#user晋升至等级排行榜第#rank名恭喜玩家#user晋升至战斗力排行榜第#rank名恭喜玩家#user晋升至声望排行榜第#rank名等等多条几乎完全重复的词条。

使用结构化的字典配置至少有3点好处。

首先易于维护。考虑一下我们想把公告中的恭喜换成祝贺,非结构化的工作量就大了几倍。再考虑如果把字典拆分成几份交给不同的翻译人员同时翻译,很容易同一术语出现几种不同译法。

其次是更不容易犯错,以前有个项目中角色叫做“英雄”,而实际我们在讨论功能时用的词是“武将”,策划在配置文本时很容易误用,于是游戏中一会儿是“英雄”一会儿是“武将”,特别混乱。如果所有词条都引用同一个Hero词条就不存在这个问题了。

第三点就是省钱——通常翻译都是按行或字数收费的。

7. 不要使用%d、%s等标识文本中的变量。

很多程序员想当然地让策划使用%d、%s来标记变量,生成文本时直接使用sprintf函数。这里有个很大的陷阱就是sprintf是依赖于参数的次序的。

比如文本玩家%s对玩家%s造成了%d点伤害,可能在其他语言中语序变成玩家%s被玩家%s造成了%d点伤害,按照原本的次序填入参数后意思完全反过来了。甚至语序可能变成玩家%s将%d点伤害施加于玩家%s,程序在运行时试图将数字填入%s,导致内存访问越界程序崩溃。

考虑到语序的问题,上面的字典应该配置成玩家#1对玩家#2造成了#3点伤害。更好的做法是使用有意义的变量名:玩家#attacker对玩家#defender造成#damage点伤害

8. 注意多义词。

曾经玩过一个汉化版的小游戏,这个游戏第1关的标题处显示的是“1级”,显然原因是Level在英语中同时有“关卡”和“等级”的意思,原版游戏中这两处同时使用了Level这个词条。

所以我们要留意中文里的多义词,当两个词条中的同一词汇意义不同时,不能引用同一词条。比如“注册登陆”中的“登陆”和“抢滩登陆”中的“登陆”就要分开。(好吧其实应该是“注册登录”不过这不是重点……)

9. 留意UI中文字的长度问题。

UI中文字长度是国际化中的常见问题了,上文也有提到,这里再提供几个思路供参考:

  1. 涉及大段文字时,UI上的设计不要依赖于当前语言版本的文本长度,最好使用带滚动的文本区域。
  2. UI的设计不要太紧凑,为国际化后文本的长度变化预留一定的空间。
  3. 使用文档记录UI对文本长度的限制,与字典一并提供给翻译人员。如“杂货店”正常应译为”grocery”,但若是限制在6字符内翻译为”store”也没问题,若是只有4字符的空间还可以用”shop”。
  4. 体验降级,使用简单的统一机制解决文本显示不全的问题,比如按钮文字显示不全时自动循环横向滚动。

总结

总的来说,游戏国际化并没有技术上的难点,主要是考验团队的管理规划和绕坑的能力,最重要的是预判可能遇到的问题,提前想好应对措施并严格执行。