将LC_MESSAGES的setlocale()设置为不存在的语言环境失败

naf*_*fmo 5 c localization glibc setlocale

对于嵌入式软件项目,我添加了对翻译的支持,并且由于我们正在运行嵌入式Linux,因此我选择使用libc gettext()。我们没有安装任何语言环境定义,因此我仅尝试将LC_MESSAGES语言环境设置为所需的语言环境:

setlocale(LC_MESSAGES, "fake");
Run Code Online (Sandbox Code Playgroud)

(在使用正确的翻译之前,我正在使用名称fakefake.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") ==> "?????"
Run Code Online (Sandbox Code Playgroud)

现在,当我动态编译它时,它不起作用。既不在目标设备上,也不在本地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;
}
Run Code Online (Sandbox Code Playgroud)

这是动态编译时(针对目标或主机)的输出:

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"
Run Code Online (Sandbox Code Playgroud)

编辑:在我的主机(x64 Linux)上将测试二进制文件编译为静态也可以工作,因此静态编译有一些特殊之处。

附加问题:我可以强制gettext直接加载特定的mo文件吗?基本上,我想bindtextdomain()用一个文件名参数代替它。

编辑2:所以,我最终发现这篇文章说,gettext()只要我有一个有效的setlocale()电话,我就可以加载任何翻译。因此,我当前的解决方法是实际生成一个/usr/lib/locale/locale-archive仅包含en_US语言环境的,调用setlocale(LC_MESSAGES, "en_US"); setenv("LANGUAGE", "fake");,最终加载正确的消息目录。仍然感觉像一个丑陋的解决方法,而且我仍然不明白为什么没有它的静态链接会起作用。

小智 1

我遇到了类似的问题(一个嵌入式系统,我对根文件系统没有太多控制权),我发现这个解决方法有效:

\n\n
    \n
  • 将所有翻译放入/<mydir>/lang/
  • \n
  • 可以SYS_LC_MESSAGES使用 生成localedef。我从系统上的 C 语言环境创建了一个并将其复制到每个目标目录

    \n\n
    mkdir output\nlocaledef -f UTF-8 -i /usr/share/i18n/locales/C  output/mylocale\ncp output/mylocale/LC_MESSAGES/SYS_LC_MESSAGES <mydir>/lang/ENG/LC_MESSAGES/\n
    Run Code Online (Sandbox Code Playgroud)
  • \n
  • 设置LOCPATH<mydir>
  • \n
  • 调试事物以strace查看它正在尝试打开哪些文件。
  • \n
\n\n

这是我的最终文件布局:

\n\n
<mydir>\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 lang\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ENG\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 SYS_LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 mac.mo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 FRE\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 SYS_LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 mac.mo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 GER\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 SYS_LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 mac.mo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ITA\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 SYS_LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 mac.mo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 SPA\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 SYS_LC_MESSAGES\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 mac.mo\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是代码片段:

\n\n
putenv("LOCPATH=/<mydir>/lang");\nsetlocale(LC_ALL, "");  \nsetlocale(LC_MESSAGES, "ENG");\nbindtextdomain("mac", "/<mydir>/lang");\ntextdomain("mac");      \ngettext("Hello world");  \n
Run Code Online (Sandbox Code Playgroud)\n\n

这是一个 hack,正确的解决方案是正确生成区域设置。

\n