文字与国际化

DinS          Written on 2017/12/29

一、概述

文字是说明游戏的最高效的方式。一个游戏里肯定需要文字才能表达清楚概念和玩法。不过文字本身就是一个坑,现在的程序都是国际化的,如何便捷地在不同语言间切换是必须考虑的问题。

计算机中字符是对应特定编码表示的,编码有各种各样,详见《字符集简史》。目前最流行的是utf-8编码格式,这个也是urho3D建议的编码。
urho3D提供了Localization子系统,配合utf-8可以方便地切换语言,程序员不需要做更多的工作。

本文扼要介绍如何使用urho3d提供的本地化方式,更具体内容可见官网

二、显示文字

子曰:温故而知新。
是时候让我们回到最初,看看第一个urho3D的程序了:

大图点这里

我们最初的程序就是显示一行文字,这就是代码。
经过了之前的学习,应该可以理解这段代码在干什么了。我们获得ResourceCache子系统,加载资源进缓存,然后建立一个Text对象,设置属性,然后加入UI子系统。最终结果就是显示文字。
文字的显示就是这个思路。

三、初步尝试国际化

现在问题来了,注意SetText这个函数。我们不能在代码里写死显示内容,一方面是出于可配置化的考虑,另一方面就是国际化。
在代码里写字符,相当于在.cpp里写字符,但是.cpp不是utf-8编码的,也就是说会遇到编译上的困难(不深入解释了)。我们需要的是一个单独的语言包,用utf-8编码,然后代码从语言包中读取对应的字符。

这个语言包实质上就是一个utf-8编码的文本文件,当然为了让urho3D调用需要保持一定的格式,例子里也提供了样本StringsEnRu.json,用notepad++打开学习一下:

注意三点:
第一这个是utf-8编码;第二这个是json文件。
什么是json见《nlohmann::json概述与基础用法》。简言之,json是传递数据的特殊格式,本质上是字符串。
第三就是json的内容,大括号之前的称为字符串id,id最好是英文字符,这是代码中将要指明的读取内容。然后是大括号里面的内容,冒号之前是特定语言,冒号之后是在该语言下id对应的真正的内容,界面上显示的就是这个。

说了这么多来点实际的。咱们在这个基础上自己写一个语言包。
很简单,先复制一个,然后照着改:

语言包名字叫Scene1_LangPack.json,内容只有两个节点,便于演示。
一般而言id就是要显示的文字的英文,这样便于后期查找。

语言包做好了并放在Data\Lang下面,剩下的就是如何在代码中使用。
还是在之前的例子基础上增加,Start()里增加代码:

大图点这里

补充:国际化和本地化,只是叫法不一样,视角不同而已,实际上都指的是程序显示不同的语言(主要方面)。

很简洁,然后是使用:

大图点这里

重点在SetText。我们使用了loc来获取要显示的文字,而不是直接写在代码里。
运行看结果:

但是别太着急,如果我们把语言设置为ch,会发现显示不出内容,why?
经过一番排查,发现是字体的原因。
并不是所有字体都有中文,比如这个Anonymous Pro.tff里就没有亚洲文字,所以用来显示欧洲的各个语言没问题,显示中文或日文就不行了。
我们重新使用汉字字体:

然后加载这个字体,把语言设置为ch,然后运行:

成功了。所以编码是一回事,字体文件是另一回事,需要配套。

四、切换语言

确实我们做到了读取语言包并显示,但是这并不那么激动人心。我们自己完全可以很快地写出一个类似的类。换句话说,我们还没有发挥出urho3D的localization子系统真正的威力:实现便捷切换。

最开始我们调用了SetLanguage,同理,我们在过程中再次使用这个就可以切换到其他语言。但是这仅仅是把localization子系统切换了,已经显示的Text并不会自动切换。当我们调用SetLanguage时,事件E_CHANGELANGUAGE被触发,所以我们要注册事件,在事件中重新设置文字内容。

不过这种方式太繁琐,试想一旦Text控件多了,一个一个设置简直是pain in the butt,urho3D提供了一种自动切换的方式,这才是真正有用的。
修改一行代码,增加一行代码:

大图点这里

注意SetText不再显式用Get了,那个获得的是实质内容,子系统不会再去处理,这里直接使用id来表示。然后是SetAutoLicalizable,正如字面意思。

然后我们写一个切换语言的事件并注册:

大图点这里

然后运行:

注意虽然我们使用SetText(“lang”),但是显示的不是lang,而是lang这个ID对应的en语言下的内容,这说明子系统已经接管工作了。
然后点击图标:

就变成中文了,我们不用进行任何额外的操作,所有设置了自动切换属性的Text都会变化。真是方便,没有道理拒绝它。

五、加载多个语言包

把所有词条塞入一个语言包不太安全,维护难度也大,一般而言我们会按照游戏概念分成几个语言包。urho3d也提供了这个功能,实际上很简单。
比如我们再制作一个语言包:

然后同样代码加载:

大图点这里

然后一样使用了,就像一次性加载一个语言包一样。

最后提一句异常情况。
如果设置的id并没有出现在语言包,会返回空字符串。
如果存在id但是没有当前语言下的翻译,会返回id本身,一般来说也就是英文了。

学习完本地化后,让我们再次研究场景模型,看看脚本的巨大威力,见《场景模型进阶-逻辑与脚本》。