问题

在当前的C ++标准(C ++ 03)中,关于文本本地化的规范太少,这使得C ++开发人员在使用本地化文本时的生活比以往更加困难(当然,C ++ 0x标准稍后会有所帮助) )。

假设以下场景(来自真正的PC-Mac游戏开发案例):

  1. 响应式(实时)应用程序:应用程序必须将非响应时间最小化到<!>“不明显的<!>”,因此执行速度很重要。
  2. 本地化文本:显示的文本以两种以上的语言进行本地化,可能更多 - 不要期望固定数量的语言,应该易于扩展。
  3. 在运行时定义的语言:文本不应该在应用程序中编译(每种语言也没有一个应用程序),您在应用程序启动时获得所选的语言信息 - 这意味着某种文本加载
  4. 跨平台:应用程序采用跨平台编码(Windows - Linux / Ubuntu - Mac / OSX),因此本地化文本系统也必须是跨平台的。
  5. 独立应用程序:应用程序提供运行它所需的一切;它不会使用任何环境库或要求用户安装除操作系统之外的任何东西(例如大多数游戏)。
  6. 在这种应用程序中用C ++管理本地化文本的最佳实践是什么?

    我去年调查了这一点,我唯一确定的是你应该使用std::wstringstd::basic_string<ABigEnoughType>来操纵应用程序中的文本。我停止了研究,因为我在<!>“文本显示<!>”上工作得更多;问题(在实时3D的情况下),但我想有一些最佳实践来管理原始C ++中的本地化文本,并且<!>使用Unicode <!>;。

    所以,欢迎所有最佳实践,建议和信息(跨平台让我觉得很难)!

有帮助吗?

解决方案

在一家名为Black Lantern Studios的小型视频游戏公司,我是一款名为Lionel Trains DS的游戏的首席开发者。我们本地化为英语,西班牙语,法语和德语。我们事先了解所有语言,因此在编译时包含它们是唯一的选择。 (你看,它们被刻录成ROM)。

我可以向您提供有关我们所做的一些事情的信息。我们的字符串在启动时根据播放器的语言选择加载到数组中。每种语言都进入一个单独的文件,所有字符串的顺序相同。字符串1始终是游戏的标题,字符串2始终是第一个菜单选项,依此类推。我们将数组键入enum,因为integer索引非常快,而在游戏中,速度就是一切。 (在其他一个答案中链接的解决方案使用string查找,我倾向于避免。)显示字符串时,我们使用printf()类型函数将值替换为标记。 <!>“火车3正在离开城市1。 <!>”

现在有一些陷阱。

1)在语言之间,短语顺序完全不同。 <!>“火车3正在离开城市1。 <!> quot;翻译成德语并且后面结束<!> 从City 1,Train 3正在离开 <!> quot;。如果你使用类似%0的字符串,而你的字符串是<!>,则列车%d正在离开城市%d。 <!> quot;德国人最终会说<!>“从城市3开始,火车1正在离开。 <!> quot;这是完全错误的。我们通过强制翻译保留相同的单词顺序来解决这个问题,但我们最终得到了一些非常破碎的德语。如果我再次这样做,我会写一个函数,它接受字符串和一个从零开始的值数组。然后我会使用像%1%2$s这样的标记,基本上将数组索引嵌入到字符串中。 更新:@Jonathan Leffler指出符合POSIX的2$支持使用.h类型标记,其中.lang部分指示<=>用第二个附加参数填充该标记。只要速度足够快,这将非常方便。自定义解决方案可能仍然更快,因此您需要确保并测试两者。

2)语言长度差异很大。英语中有30个字符,德语有时达到110个字符。这意味着它通常不适合我们所穿的屏幕。这可能不是PC / Mac游戏的关注点,但如果您正在进行任何文本必须适合定义框的工作,您将需要考虑这一点。为了解决这个问题,我们从其文本中删除了尽可能多的形容词用于其他语言。这缩短了句子,但保留了意义,如果失去了一点味道。我后来设计了一个我们可以使用的应用程序,它包含字体和框大小,并允许翻译人员进行自己的修改以使文本适合框。不确定他们是否实施过它。如果您遇到此问题,也可以考虑滚动文本区域。

3)就跨平台而言,我们为本地化系统编写了非常纯粹的C ++。我们编写了要加载的自定义编码二进制文件,以及一个自定义程序,用于将语言文本CSV转换为带有枚举和文件到语言映射的<=>,以及每种语言的<=>。我们使用的最平台特定的东西是字体和<=>函数,但是你会有适合你开发的地方的东西,或者如果需要可以自己编写。

其他提示

GNU Gettext 可以做到这一切。

我强烈不同意接受的答案。首先,关于使用静态数组查找加速文本查找的部分仅显示执行此操作的人员优化是非常缺乏经验的 - 计算所述文本的布局并呈现所述文本比使用散列查找多花费2-4个数量级。如果有人想要实现自己的语言库,它永远不应该基于静态数组。

但这并不是真的相关,因为编写自己的语言库以在自己的游戏中使用甚至比无意义的过早优化更糟糕。 有一些非常好的理由永远不要编写自己的本地化库

  1. 规划使用本地化库的时间比计划编写本地化库的时间要容易得多。存在本地化库,它们起作用,并且许多人已经使用它们。

  2. 本地化很棘手,所以你会出错。每种语言都会添加一个新的怪癖,这意味着每当您向自己的本地化本地化库添加新语言时,您都需要再次更改代码以解决这些问题。您是否知道某些语言有多于2种复数形式,具体取决于相关项目的数量? 2个以上的性别(超过10个,甚至)?此外,数字和日期格式在不同语言的不同之间有很大差异。

  3. 当您的应用程序成功后,您将需要添加对更多语言的支持。您团队中没有人能说流利的语言。如果他们已经知道他们正在使用的工具,那么聘请某人撰写翻译将会相当便宜

  4. 一个众所周知的完整本地化库是 GNU Gettext ,使用GPL,因此应避免用于商业工作。您可以使用增强库 boost.locale 适用于Gettext文件,可以免费使用和修改任何类型的商业和非商业项目。

据我所知,C ++ 0x标准中没有任何其他功能。我怀疑委员会认为这是第三方图书馆的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow