下一节:,上一节:,上一级:编写 C 代码   [目录][索引]


5.8 国际化

GNU 有一个名为 GNU gettext 的库,它可以轻松地将程序中的消息翻译成各种语言。你应该在每个程序中使用这个库。程序中出现的消息应使用英文,让 gettext 提供将其翻译成其他语言的方法。

使用 GNU gettext 涉及到在每个可能需要翻译的字符串周围调用 gettext 宏,像这样:

printf (gettext ("Processing file '%s'..."), file);

这允许 GNU gettext 将字符串 "Processing file '%s'..." 替换为翻译后的版本。

一旦程序使用 gettext,请务必在添加需要翻译的新字符串时调用 gettext

在软件包中使用 GNU gettext 涉及到为软件包指定一个文本域名称。文本域名称用于将此软件包的翻译与其他软件包的翻译分开。通常,文本域名称应与软件包的名称相同,例如,GNU 核心实用工具的名称为 ‘coreutils’。

为了使 gettext 能够良好地工作,请避免编写对单词或句子的结构进行假设的代码。当你希望句子的精确文本根据数据而变化时,请使用两个或多个包含完整句子的替代字符串常量,而不是将条件化的单词或短语插入到单个句子框架中。

这是一个不应该这样做的示例:

printf ("%s is full", capacity > 5000000 ? "disk" : "floppy disk");

如果你将 gettext 应用于所有字符串,像这样:

printf (gettext ("%s is full"),
        capacity > 5000000 ? gettext ("disk") : gettext ("floppy disk"));

翻译人员很难知道 “disk” 和 “floppy disk” 应该在另一个字符串中被替换。更糟糕的是,在某些语言(如法语)中,这种结构将不起作用:“full” 一词的翻译取决于句子第一部分的名词性;它恰好对于“disk”和“floppy disk”不相同。

完整的句子可以毫无问题地翻译:

printf (capacity > 5000000 ? gettext ("disk is full")
        : gettext ("floppy disk is full"));

类似的问题出现在以下代码的句子结构级别:

printf ("#  Implicit rule search has%s been done.\n",
        f->tried_implicit ? "" : " not");

对这段代码添加 gettext 调用不能为所有语言提供正确的结果,因为某些语言中的否定需要在句子中的多个位置添加单词。相反,如果代码像这样开始,添加 gettext 调用可以简单地完成工作:

printf (f->tried_implicit
        ? "#  Implicit rule search has been done.\n",
        : "#  Implicit rule search has not been done.\n");

另一个示例是这个:

printf ("%d file%s processed", nfiles,
        nfiles != 1 ? "s" : "");

这个示例的问题在于它假设复数是通过添加 's' 来构成的。如果将 gettext 应用于格式字符串,像这样:

printf (gettext ("%d file%s processed"), nfiles,
        nfiles != 1 ? "s" : "");

消息可以使用不同的单词,但仍然会被迫使用 's' 来表示复数。这是更好的方法,将 gettext 独立地应用于两个字符串:

printf ((nfiles != 1 ? gettext ("%d files processed")
         : gettext ("%d file processed")),
        nfiles);

但这仍然不适用于像波兰语这样的语言,它有三种复数形式:一种用于 nfiles == 1,一种用于 nfiles == 2、3、4、22、23、24...,另一种用于其余情况。GNU 的 ngettext 函数解决了这个问题:

printf (ngettext ("%d files processed", "%d file processed", nfiles),
        nfiles);

下一节:,上一节:,上一级:编写 C 代码   [目录][索引]