本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
Android自身提供了多语言解决方案,但是使用Libgdx开发游戏的时候应该尽量避免使用平台特殊的代码。
如果使用Android提供的方案那么在桌面的调试就有困难,使用Libgdx自身提供的是最方便的。
Libgdx目前已经Locale来解决这个问题。
简介
从技术上将多语言国际化是指在开发设计上能够实现增加对语言的支持而不需要大规模修改代码。国际化主要解决游戏和应用在不同语言区域的适应性问题。
Libgdx提供了一套解决方案,以I18NBundle
类为中心。
宏观来看它的操作和Android原生解决方案类似,也是后缀语言代码来处理的。
结构
语言文件时一个个独立的配置文件,其名称是由基本名称加上语言代码组成。比如游戏superjump它的语言文件如下:
- superjump
- superjump_de
- superjump_en_GB
- superjump_fr_CA_VAR1
一定确保拥有一个默认配置,即superjump.properties,而其他的语言文件根据自身的需要增加吧。
语言文件的格式很随意,使用键值方式组合,比如:
gameName=SuperJump
newMission={0}, you have a new mission. Reach level {1}.
highScoreTime=High score achievedon {0,date}at {0,time}
语言文件本身支持按序号赋值和按名称赋值。
而中文化的语言文件可以写做:
gameName=超级跳跳人
newMission={0},,你有一个新任务,完成管卡{1}。
highScoreTime=最高分为{0,time},获得时间{0,date} 。
替换规则使用的是java.text.MessageFormat
,更多的格式可以参考它的API。
创建国际化模块
粗略的看,I18NBundle
的使用很简单
FileHandle baseFileHandle = Gdx.files.internal("i18n/superjump");
Locale locale =new Locale("fr","CA","VAR1");
I18NBundle bundle = I18NBundle.createBundle(baseFileHandle, locale);
从细节来看这里有几个需要注意的问题
- 不指定语言代码就会使用默认代码
- 默认的文件编码是utf-8,如果有需要可以修改它们。
privatestaticfinal String DEFAULT_ENCODING ="UTF-8";
publicstatic I18NBundlecreateBundle (FileHandle baseFileHandle, Locale locale, String encoding) {
return createBundleImpl(baseFileHandle, locale, encoding);
}
- 加载策略是从小至大的,比如制定的
new Locale("fr", "CA", "VAR1");
就会依次查找
1.superjump_fr_CA_VAR1
2.superjump_fr_CA
3.superjump_fr
4.superjump_en_US
5.superjump_en
6.superjump
相关的实现代码为
privatestatic List<Locale>getCandidateLocales (Locale locale) {
String language = locale.getLanguage();
String country = locale.getCountry();
String variant = locale.getVariant();
List<Locale> locales =new ArrayList<Locale>(4);
if (variant.length() >0) {
locales.add(locale);
}
if (country.length() >0) {
locales.add((locales.size() ==0) ? locale :new Locale(language, country));
}
if (language.length() >0) {
locales.add((locales.size() ==0) ? locale :new Locale(language));
}
locales.add(Locale.ROOT);
return locales;
}
获得对应语言值
要获得国际化以后的语言值,只需要
String value = bundle.get(key);
如果需要替换值的话需要使用format
方法
String mission = myBundle.format("newMission", player.getName(), nextLevel.getName());
在其中也可以使用比较简单的判断,比如
collectedCoins=You collected {0,choice,0#no coins|1#one coin|1<{0,number,integer} coins|100<hundreds of coins} along the path.
这样,传入值为0的时候就会使用no coins,而大于100显示hundreds of coins。
跨平台的局限性
Libgdx是跨平台的,但是目前国际化方案在GWT上还有缺陷。特别是在替换上MessageFormat
的支持不完整,仅能通过序号来替换,其他情况会抛出IllegalArgumentException
错误。
在程序一开始启用I18NBundle.setSimpleFormat(true)
来保证GWT上的正常工作。
参考资料
Internationalization and Localization
I18NBundle
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯