22

这是一个笼统的问题,欢迎发表意见。我一直在尝试想出一种好方法来设计用于 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 对象并进行格式化等。

无论如何,我认为添加我现在的参考资料会很有用。

4

7 回答 7

4

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

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

代码如下:

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

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

我们可以为每个本地设置多个 dll。dll 的名称基于 RFC 3066
语言[_territory][.codeset][@modifier]

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

例子:

在英国:如果本地是en_GB.UTF-8
(我松散地使用术语 dll,而不是在特定的 Windows 意义上)。

首先查找I18N.en_GB.UTF-8 dll。如果此 dll 不存在,则回退到 I18N.en_GB。如果这个 dll 不存在回退到 I18N.en如果这个 dll 不存在回退到 I18N.default

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

于 2008-10-08T23:30:50.007 回答
2

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

有几个共享软件 utilstohelp 本地化 rc 文件,这些文件可以处理为具有较长单词的语言调整对话框元素的大小,并警告缺少翻译。

一个更复杂的问题是词序,如果 printf 中有多个数字,对于不同语言的语法,它们的顺序必须不同。codeproject 上有一些扩展的 printf 类,可让您指定诸如 printf("word %1s and %2s",var1,var2) 之类的内容,以便您可以在必要时切换 %1s 和 %2s。

于 2008-10-24T02:41:19.710 回答
1

我不太了解这通常在 Windows 上是如何完成的,但是在 Apple 的Cocoa 框架中处理本地化字符串的方式非常有效。它们有一个非常基本的文本格式文件,您可以将其发送给翻译器,以及一些用于从文件中检索值的预处理器宏。

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

于 2008-10-08T23:20:14.833 回答
1

由于它是开放的意见,这就是我的做法。

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

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

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

我喜欢这个设计的一点是,如果缺少任何字符串,那么我会得到一个编译错误,而如果在运行时查找字符串,那么您可能直到稍后才知道代码中很少使用的部分中缺少字符串。

于 2008-10-09T02:25:13.070 回答
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");

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

于 2008-10-10T15:13:35.050 回答
0

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

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

顺便说一句,本机 Win32 程序和 .NET 程序具有完全不同的资源存储管理。您将很难为两者找到共同的解决方案。

于 2008-10-09T18:45:24.450 回答
0

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

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

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

于 2008-10-08T23:16:52.063 回答