devisestring本地化的最佳方法

这是一个普遍的问题,是开放的意见。 我一直在想出一个很好的方法来为Windows MFC应用程序和相关实用程序devisestring资源的本地化。 我的心愿是:

  • 必须保留代码中的string文字(而不是用macros#define资源ID的replace),以便消息仍然可以内联
  • 必须允许本地化的string资源(杜)
  • 不得施加额外的运行时环境限制(例如:依赖.NET等)
  • 应该对现有的代码有最小的影响(修改越less越好)
  • 应该是可debugging的
  • 应该生成通用工具可编辑的资源文件(即:通用格式)
  • 不应该使用复制/粘贴注释块来保留代码中的文本string,或者其他任何可能导致解除同步的潜力
  • 如果允许静态(编译时)检查每个“notated”string在资源文件中,
  • 如果允许跨语言资源string池(对于各种语言的组件,例如:本地C ++和.NET)

除了静态检查之外,我有一种方法可以在某种程度上满足我的所有愿望,但是我必须开发一些自定义代码来实现它(并且有其局限性)。 我想知道是否有人以特别好的方式解决了这个问题。

编辑:我目前的解决scheme是这样的:

ShowMessage( RESTRING( _T("Some string") ) ); ShowMessage( RESTRING( _T("Some string with variable %1"), sNonTranslatedStringVariable ) ); 

然后,我有一个自定义实用工具从“RESTRING”块中parsing出string,并将它们放到.resx文件中进行本地化,并使用一个单独的C#COM对象从本地化资源文件中加载它们。 如果C#对象不可用(或无法加载),我将回退到代码中的string。 macros展开为调用COM对象的模板类,并进行格式化等。

无论如何,我认为这将是有益的,加上我现在的参考。

我们使用英文字符串作为ID。

如果从国际资源对象(从安装的I18N DLL加载)查找失败,那么我们默认为ID字符串。

代码如下所示:

 doAction(I18N.get("Press OK to continue")); 

作为构建过程的一部分,我们有一个perl脚本来解析字符串常量的所有源代码。 它在应用程序中构建一个包含所有字符串的临时文件,然后将它们与每个本地资源字符串进行比较,以查看它们是否存在。 任何缺少的字符串将生成电子邮件给相应的翻译团队。

我们可以为每个本地多个DLL。 该DLL的名称是基于RFC 3066
语言[_territory] ​​[。代码集] [@修饰符]

我们尝试从机器中提取语言环境,并在加载I18N dll时尽可能具体,但如果更具体的版本不存在,则回退到不太具体的本地变体。

例:

在英国:如果当地是en_GB.UTF-8
(我使用术语dll宽松不在特定的窗口意义上)。

首先查找I18N.en_GB.UTF-8 dll。 如果这个DLL不存在回落到I18N.en_GB 如果这个DLL不存在回落到I18N.en如果这个DLL不存在下降到I18N.default

此规则的唯一例外是:简体中文(zh_CN),后备为美式英语(en_US)。 如果机器不支持简体中文,那么不太可能支持全中文。

我不太了解Windows通常如何实现,但本地化的字符串在苹果的Cocoa框架中处理的方式非常好。 他们有一个非常基本的文本格式的文件,你可以发送给翻译,一些预处理宏从文件中检索值。

在你的代码中,你会看到你的母语中的字符串,而不是不透明的ID。

你的解决方案非常类似于Unix / Linux“ gettext ”解决方案。 事实上,你不需要编写抽取程序。

我不知道你为什么要_RESTRING宏来处理多个参数。 我的代码(使用wxWidgets支持gettext)如下所示: MyString.Format(_("Some string with variable %ls"), _("variable")); 也就是说,String :: Format(…)获取两个单独转换的参数。 事后看来,Boost :: Format会更好,但它也可以允许boost::format(_("Some string with variable %1")) % _("variable");

(为了简洁,我们使用_()宏)

简单的方法是只在代码中使用字符串ID – 不需要文字字符串。 然后,您可以为每种语言生成不同版本的.rc文件,并创建仅资源的DLL或简单的不同的语言版本。

有几个共享软件utilstohelp本地化的rc文件,处理调整大小对话框元素的语言与更长的单词和warnign失踪翻译。

一个更复杂的问题是语序,如果你在printf中有几个数字,它们必须按不同语言的语法顺序排​​列。 codeproject上有一些扩展的printf类,可以让你指定诸如printf(“word%1s和%2s”,var1,var2)之类的东西,所以你可以根据需要切换%1s和%2s。

在我已经被本地化为10多种语言的一个项目中,我把所有要本地化的东西放到一个单一的资源专用的dll中。 在安装的时候,用户选择了哪个dll与他们的应用程序安装。

我只需要将英文版本交给本地化团队。 他们返回了一个本地化的dll给我包括在构建中的每种语言。

我知道这不是完美的,但它的工作。

既然这是开放的意见,这是我如何做到这一点。

我的本地化文本文件是一个简单的制表符分隔的文本文件,可以在Excel中加载和编辑。 第一列是定义,右边的每一列是后续的语言,例如:

 ID ENGLISH FRENCH GERMAN STRING_YES YES OUI YA STRING_NO NO NON NEIN 

然后在我的makefile是一个cusom构建步骤,生成一个strings.h文件和一个strings.dat。 在我的情况下,它为字符串ID构建一个枚举列表,然后为文本建立一个带有偏移量的二进制文件。 由于在我的应用程序中,用户可以随时更改语言,我可以随时将它们全部存储在内存中,但是如果需要,您可以轻松地让预处理器为每种语言生成不同的输出文件。

我喜欢这个设计的事情是,如果有任何字符串丢失,那么我会得到一个编译错误,而如果在运行时查找字符串,那么你可能不知道在很少使用的代码部分缺少字符串,直到以后。

你想要一个我一直想写的先进实用程序,但从来没有时间。 如果你没有找到这样一个工具,你可能想回滚到我的CMsg()和CFMsg()包装类,这些类允许非常容易地从资源表中抽取字符串。 (CFMsg甚至提供了一个FormatMessage的单行包装器,是的,如果没有这个工具,你需要在注释中保留一个字符串的副本是一个很好的解决方案。关于注释的不同步,记住字符串是很少改变。

http://www.codeproject.com/KB/string/stringtable.aspx

顺便说一句,原生Win32程序和.NET程序有一个完全不同的资源存储管理。 你将很难找到一个共同的解决方案。