设计字符串本地化的最佳方式

时间:2008-10-08 23:07:31

标签: c++ windows mfc localization

这是一个普遍的问题,对意见持开放态度。我一直在努力想出一个很好的方法来设计Windows MFC应用程序和相关实用程序的字符串资源本地化。我的愿望是:

  • 必须在代码中保留字符串文字(而不是替换为宏#define资源ID),以便邮件仍然可以内联读取
  • 必须允许本地化字符串资源(duh)
  • 不得强加额外的运行时环境限制(例如:依赖于.NET等)
  • 应该对现有代码的侵略性最小(修改越少越好)
  • 应该是可调试的
  • 应生成可通过常用工具编辑的资源文件(即:通用格式)
  • 不应使用复制/粘贴注释块来保留代码中的文字字符串,或其他任何可能导致去同步的内容
  • 允许静态(编译时)检查每个“标记”字符串是否在资源文件中
  • 会很高兴
  • 很高兴允许跨语言资源字符串池(适用于各种语言的组件,例如:原生C ++和.NET)

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

编辑: 我目前的解决方案如下:

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

然后我有一个自定义实用程序来解析'RESTRING'块中的字符串并将它们放入.resx文件进行本地化,并使用单独的C#COM对象从带有回退的本地化资源文件加载它们。如果C#对象不可用(或无法加载),我将回退到代码中的字符串。宏扩展为一个模板类,它调用COM对象并进行格式化等。

无论如何,我认为添加我现在的内容以供参考是有用的。

7 个答案:

答案 0 :(得分:3)

我们使用英文字符串作为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)。如果机器不支持简体中文,则不太可能支持完整的中文。

答案 1 :(得分:1)

我不太了解在Windows上通常如何做到这一点,但在Apple的Cocoa framework中处理本地化字符串的方式非常有效。它们有一个非常基本的文本格式文件,可以发送给翻译器,还有一些预处理器宏可以从文件中检索值。

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

答案 2 :(得分:1)

您的解决方案与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");

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

答案 3 :(得分:1)

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

有一些共享软件utilstohelp对rc文件进行本地化处理,该文件处理调整大小对话框元素的语言,这些语言具有较长的单词并且有关于缺少翻译的警告。

更复杂的问题是单词顺序,如果你在printf中有多个数字,对于不同语言的语法必须有不同的顺序。 在codeproject上有一些扩展的printf类,可以让你指定像printf(“word%1s和%2s”,var1,var2)这样的东西,这样你就可以在必要时切换%1s和%2s。

答案 4 :(得分:0)

在一个我已经本地化为10多种语言的项目中,我将所有要本地化的项目放入一个仅限资源的dll中。在安装时,用户选择了与他们的应用程序一起安装的DLL。

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

我知道它并不完美,但它确实有用。

答案 5 :(得分:0)

因为它是开放的意见,所以我就是这样做的。

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

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

然后在我的makefile中是一个cusom构建步骤,它生成一个strings.h文件和一个strings.dat。在我的例子中,它为字符串id构建枚举列表,然后为文本构建偏移量的二进制文件。因为在我的应用程序中,用户可以随时更改语言,但是如果需要,您可以轻松地让预处理器为每种语言生成不同的输出文件。

我喜欢这个设计的东西是,如果缺少任何字符串,那么我会得到编译错误,而如果在运行时查找字符串,那么你可能不知道在很少使用的部分代码中缺少字符串直到晚些时候。

答案 6 :(得分:0)

你想要一个我一直想写的高级实用程序,但从来没有时间去过。 如果您没有找到这样的工具,您可能希望回退我的CMsg()和CFMsg()包装类,它们可以非常轻松地从资源表中提取字符串。 (CFMsg甚至提供FormatMessage单线程封装器。 是的,如果没有您正在寻找的工具,在评论中保留字符串的副本是一个很好的解决方案。关于注释的去同步,请记住字符串文字很少被更改。

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

BTW,本机Win32程序和.NET程序具有完全不同的资源存储管理。你很难找到两者的通用解决方案。