PostgreSQL 9.3.1 中文手册 | ||||
---|---|---|---|---|
Prev | Up | Chapter 50. 本地语言支持 | Next |
本节描述如何在属于 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 读取。在这里需要做下面一些变量的赋值:
那些在 textdomain()
调用里提供的程序的名字。
提供的翻译的语言列表,开始的时候是空的。
一列包含可翻译字符串的文件,也就是那些用 gettext
或者其它相应手段标记了的文件。
最终,这里会包括几乎所有的程序源文件。如果列表太长,你可以把第一个"文件"写成一个
+ 和第二个词组成,第二个词是一个文件,在这个文件里每行包含一个文件名。
生成给翻译者使用的消息表的工具,以便知道哪些函数调用包含可翻译字符串。
缺省时只知道 gettext()
调用。
如果你使用了 _
或其它标识符,那么你需要把它们列在这里。
如果可翻译字符串不是第一个参数,那么该项需要是这样的形式:func:2 (用于第二给参数)。
如果函数支持多个消息,那么该项看起来就像这样:func:1,2(识别单个和多个消息参数)。
编译系统将自动制作和安装消息表。
这里是一些关于如何书写易于翻译的消息的指导:
不要在运行时构造语句,比如像
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);
如果你真的要构造一条恰当的复数形消息,也是支持的,但形式上有一点笨拙。
比如当通过ereport()
生成一条概要或者详细消息时,你可以这样写:
errmsg_plural("copied %d file", "copied %d files", n, n)
第一个参数是对应英文单数形的格式字符串,第二个参数是对应英文复数形的格式字符串,第三个参数是决定是否是复数形的一个整数值。 随后的参数和通常一样对应与格式字符串中的参数值。(通常,控制复数形的值也是格式字符串中的其中一个参数。) 英语中只关心n是不是1,但其它语言中可能有多个复数形。 针对英文中作为一组的2个格式字符串,翻译者能够为根据n的运行值选中的恰当的那个提供多个替代字符串。
如果你需要一条不直接调用errmsg
或errdetail
的复数形消息,
必须使用下层的ngettext
函数。具体参考gettext的文档。
如果你想和翻译者进行交流,比如说一条消息是如何与其它输出对齐的,那么在该字符串出现之前,放上一条以 translator 开头的注释,比如
/* translator: This message is not what it seems to be. */
这些注释都拷贝到消息表文件里,这样翻译者就可以看见它们了。