对于嵌入式软件项目,我正在添加对翻译的支持,因为我们运行的是嵌入式Linux,所以我使用了libc gettext()
。我们没有安装任何语言环境定义,所以我只尝试将LC_MESSAGES
语言环境设置为我想要的语言环境:
setlocale(LC_MESSAGES, "fake");
(在使用正确的翻译之前,我使用名称fake
和fake.mo
文件进行伪翻译。)
这在静态链接时工作正常,它返回一个语言环境句柄,bindtextdomain()
和朋友们都工作正常,我得到了我的"翻译"串出来的字符串:
setlocale() returned "fake"
current textdomain is "ewe"
current base directory is "/opt/btech/probe/share/locale/WA"
current LC_MESSAGES locale is "fake"
gettext("Error") ==> "Ḗřřǿř"
现在,当我动态编译它时,它不起作用。既不在目标设备上,也不在我的PC上本地(文件以相同的方式安装)。 setlocale()
调用失败,返回NULL
指针并将errno设置为ENOENT
(找不到文件)。在setlocale()
点我没有指出bindtextdomain()
我的文件所在的位置,但是切换调用并没有帮助。
我做错了吗,我的工作实例是从错误中解脱出来并且不应该真的有效吗?我是否需要针对setlocale()
开启的任何内容定义,即使是LC_MESSAGES
?
这是测试二进制文件的来源:
#include <libintl.h>
#include <locale.h>
#include <stdio.h>
int main()
{
const char *l = setlocale(LC_MESSAGES, "fake");
printf("setlocale() returned \"%s\"\n", l);
bind_textdomain_codeset("ewe", "UTF-8");
bindtextdomain("ewe", "/opt/btech/probe/share/locale/WA");
textdomain("ewe");
printf("current textdomain is \"%s\"\n", textdomain(NULL));
printf("current base directory is \"%s\"\n", bindtextdomain(textdomain(NULL), NULL));
printf("current LC_MESSAGES locale is \"%s\"\n", setlocale(LC_MESSAGES, NULL));
printf("gettext(\"Error\") ==> \"%s\"\n", gettext("Error"));
return 0;
}
这是动态编译时的输出(目标或主机):
setlocale() returned "(null)"
current textdomain is "ewe"
current base directory is "/opt/btech/probe/share/locale/WA"
current LC_MESSAGES locale is "C"
gettext("Error") ==> "Error"
编辑:在我的主机(x64 Linux)上将测试二进制文件编译为静态也使它工作,因此静态编译有一些特殊之处。
其他问题:我可以强制gettext直接加载特定的mo文件吗?基本上我想替换bindtextdomain()
而取代文件名参数。
编辑2 :所以,我最终发现this post说我可以gettext()
加载任何翻译,只要我有一个有效的setlocale()
电话第一。因此,我目前的解决方法是实际生成仅包含/usr/lib/locale/locale-archive
区域设置的en_US
,调用setlocale(LC_MESSAGES, "en_US"); setenv("LANGUAGE", "fake");
,最终加载正确的消息目录。仍然感觉像一个丑陋的解决方法,我仍然不明白为什么静态链接没有它。
答案 0 :(得分:1)
我遇到了类似的问题(一个对根文件系统没有太多控制权的嵌入式系统),我发现此解决方法可以正常工作:
/<mydir>/lang/
SYS_LC_MESSAGES
可以用localedef
生成。我在系统的C语言环境中制作了一个,并将其复制到每个目标目录
mkdir output
localedef -f UTF-8 -i /usr/share/i18n/locales/C output/mylocale
cp output/mylocale/LC_MESSAGES/SYS_LC_MESSAGES <mydir>/lang/ENG/LC_MESSAGES/
LOCPATH
设置为<mydir>
strace
进行调试,以查看它试图打开哪些文件。这是我的最终文件布局:
<mydir>
├── lang
│ ├── ENG
│ │ └── LC_MESSAGES
│ │ ├── SYS_LC_MESSAGES
│ │ └── mac.mo
│ ├── FRE
│ │ └── LC_MESSAGES
│ │ ├── SYS_LC_MESSAGES
│ │ └── mac.mo
│ ├── GER
│ │ └── LC_MESSAGES
│ │ ├── SYS_LC_MESSAGES
│ │ └── mac.mo
│ ├── ITA
│ │ └── LC_MESSAGES
│ │ ├── SYS_LC_MESSAGES
│ │ └── mac.mo
│ ├── SPA
│ │ └── LC_MESSAGES
│ │ ├── SYS_LC_MESSAGES
│ │ └── mac.mo
这是代码段:
putenv("LOCPATH=/<mydir>/lang");
setlocale(LC_ALL, "");
setlocale(LC_MESSAGES, "ENG");
bindtextdomain("mac", "/<mydir>/lang");
textdomain("mac");
gettext("Hello world");
这是一个hack,正确的解决方案是正确生成语言环境。