今天这篇文章继续讨论gettext。
一、gettext如何判断加载哪种语言?
gettext根据环境变量来决定加载哪个便携对象的二进制数据文件(.mo),按以下顺序进行查找(优先级由高到低):
LANGUAGE(最高优先级):
其键值可以是单个语言(比如:zh_CN.UTF-8),也可以是多种语言,以冒号分割(比如:zh_CN.UTF-8:en_US.UTF-8)。这种情况下,gettext 会从左到右依次尝试每种语言,直到找到可用的翻译(即存在对应的 .mo文件)。如果某种语言的 .mo文件不存在或未加载,则继续尝试下一个。如果所有列出的语言选项都失效,则回退到源代码中的原始字符串;
LC_ALL:这是一个全局变量,包括所有的LC_*。可以读取,尽量不要直接写;
LC_MESSAGES:专门控制消息翻译区的变量;
LANG(最低优先级)
二、gettext加载语言数据的时机
函数:bindtextdomain(domain, dir)、bind_textdomain_codeset(domain, codeset)、textdomain(domain)
均不会触发便携对象二进制数据文件(.mo)的加载。
1、bindtextdomain(domain, dir)
告诉 gettext:域domain的 .mo文件存放在 dir目录下。只是记录路径,不读取任何文件。
2、bind_textdomain_codeset(domain, codeset)
指定域的输出编码(例如 UTF-8)。只设置编码转换规则,不触发加载。
3、textdomain(domain)
设置当前活动的域。只是切换当前域的名称,不加载 .mo。
真正触发加载(.mo)文件的是第一次调用gettext(msg)函数。
为了提高性能,gettext会缓存加载的便携对象二进制数据文件(.mo),默认不会自动检测其文件的变化。换句话说,当更新了翻译文件后,正在运行的程序不会自动加载最新的翻译。可以通过重新启动的方式设置环境变量,从而切换语言。另外在Linux(glibc)下,可以通过改变外部变量_nl_msg_cat_cntr的值,使gettext刷新缓存,这种情况下不用重启软件。
#ifdef __GLIBC__
extern int _nl_msg_cat_cntr; // 这是 GLIBC 内部的翻译缓存计数器
_nl_msg_cat_cntr++; // 通过增加计数器来强制刷新 gettext 缓存
#endif
三、获取及设置环境变量的函数
3.1、Windows平台(包含头文件<windows.h>)
3.1.1、用getenv()或getenv_s()函数获取环境变量
函数声明:
char *getenv(const char *varname);
参数:环境变量的名称
返回值:指向环境变量的指针,失败返回NULL
例如:getenv("LANGUAGE")
errno_t getenv_s(size_t *pReturnValue,char* buffer,size_t numberOfElements,const char *varname);
名称中的s表示security(安全),参数:
pReturnValue:所需的缓冲区大小,如果找不到该变量,则为 0。
buffer:用于存储环境变量值的缓冲区。
numberOfElements:缓存区的大小。
varname:环境变量名称。
返回值:如果成功,则为零;如果失败,则返回错误代码。
3.1.2、可以用_putenv_s()函数设置环境变量,声明如下:
errno_t _putenv_s(const char *varname,const char *value_string);
参数:
varname:环境变量名称。
value_string:要将环境变量设置为的值。
返回值:如果成功,则返回 0;否则,返回错误代码。
例如:_putenv_s("LANGUAGE", "zh_CN.UTF-8");
3.2、POSIX平台(Linux),包含头文件<stdlib.h>
3.2.1、用getenv()函数获取环境变量,函数声明:
char * getenv(const char *name);
参数:name -- 包含被请求变量名称的 C 字符串。
返回值:一个以 null 结尾的字符串,该字符串为被请求环境变量的值。如果该环境变量不存在,则返回 NULL。
3.2.2、用setenv()函数设置环境变量,函数声明:
int setenv(const char *name, const char *value, int overwrite);
参数:
name:环境变量的名称;
value:环境变量的值;
overwrie:是否覆盖。0=不覆盖,非0值=覆盖
返回值:0=成功,非0值表示失败,会设置errno
3.2.3、用unsetenv()函数删除环境变量
int unsetenv(const char *name);
参数:name->要删除的环境变量
返回值:同setenv()函数
北岛夜话



发表评论