46.2. 给程序员 #
46.2.1. 实现机制 #
本节描述如何在 PostgreSQL 发行版中的程序或库里实现本地语言支持。目前它只适用于 C 程序。
为程序添加 NLS 支持
把下面的代码插入到该程序的启动序列中:
#ifdef ENABLE_NLS #include <locale.h> #endif ... #ifdef ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain("progname", LOCALEDIR); textdomain("progname"); #endif(其中
progname实际上可以自由选择。)凡是遇到可能需要翻译的消息,都需要插入对
gettext()的调用。例如,fprintf(stderr, "panic level %d\n", lvl);
将改成
fprintf(stderr, gettext("panic level %d\n"), lvl);(如果没有配置 NLS 支持,
gettext会被定义成一个空操作。)这样往往会增加很多杂乱内容。一个常用的简写是
#define _(x) gettext(x)
如果该程序的大部分通信都是通过一个或少数几个函数完成的,例如后端中的
ereport(),另一种可行的解决办法是让这个函数在内部对所有输入字符串调用gettext。在程序源代码所在目录中添加一个
nls.mk文件。这个文件会作为 makefile 读取。这里需要设置以下变量:CATALOG_NAME程序名,即
textdomain()调用中提供的名称。AVAIL_LANGUAGES已提供的翻译列表 — 最初为空。
GETTEXT_FILES包含可翻译字符串的文件列表,也就是那些使用
gettext或其他替代方案标记过的文件。最终,这会包含该程序几乎所有的源文件。如果这个列表太长,可以让第一个“文件”是一个+,第二个词则是一个文件名,该文件每行包含一个文件名。GETTEXT_TRIGGERS为翻译者生成消息目录的工具需要知道哪些函数调用包含可翻译字符串。默认只认识
gettext()调用。如果你使用了_或其他标识符,就需要在这里列出它们。如果可翻译字符串不是第一个参数,条目就需要写成func:2这样的形式(表示第二个参数)。
构建系统会自动处理消息目录的构建和安装。
46.2.2. Message-writing guidelines #
下面列出一些便于翻译的消息编写指南。
不要像下面这样在运行时拼接句子
printf("Files were %s.\n", flag ? "copied" : "removed");句子中的词序在其他语言里可能完全不同。另外,即使你记得对每个片段都调用 gettext(),这些片段分开来看也可能难以妥善翻译。最好稍微重复一点代码,让每条待翻译消息都成为一个语义完整的整体。只有数字、文件名之类的运行时变量才应该在运行时插入消息文本中。
出于类似的原因,下面这样也行不通:
printf("copied %d file%s", n, n!=1 ? "s" : "");因为它假定了复数形式的构造方式。如果你以为可以这样解决
if (n==1) printf("copied 1 file"); else printf("copied %d files", n):那就会失望了。有些语言的复数形式不止两种,而且规则相当特殊。将来我们可能会有针对这一问题的解决方案,但就目前而言,最好还是完全避开这个问题。你可以写成:
printf("number of copied files: %d", n);如果你想向翻译者传达某些信息,例如一条消息应如何与其他输出对齐,就在该字符串出现之前放置一个以
translator开头的注释,例如,/* translator: This message is not what it seems to be. */
这些注释会被复制到消息目录文件中,这样翻译者就能看到它们。