首页 > 解决方案 > dgettext 无法翻译字符串

问题描述

我正在使用 gettext/libintl 如下:

setlocale(LC_ALL, "en_US");
char * result = bindtextdomain("MyApp", "/absolute/path/to/locale/dir");
assert(result);
result = dgettext("MyApp", "Test String");

/absolute/path/to/locale/dir我有翻译文件en_US/LC_MESSAGES/MyApp.mo

我正在 macOS 上对此进行测试。它适用于使用 的 linux setlocale(LC_ALL, "en_US.UTF-8"),但这不适用于 macOS。

结果不包含翻译后的字符串,它是原始字符串“测试字符串”。我可能会错过什么?有没有办法可以调试 dgettext?

示例项目:https ://mega.nz/file/uBATVKKA#O57nnKDHRELEY8m7U_dmC1OZLiK490sqgvoDRnT7wWY


strace在Linux 上进行进一步调查后,虽然setlocale(LC_ALL, "en_US.utf8")可以工作,setlocale(LC_ALL, "en_US")但不能 -strace输出包括使用时不存在的这些行en_US.utf8

openat(AT_FDCWD, "/usr/lib/locale/en_US/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

全输出

使用 en_US.utf8 输出

看来 Linux 正在寻找要在 中使用的默认编码LC_IDENTIFICATION,但该文件不存在(Ubuntu 20.04.1)

编辑:按照Guido Flohrsudo locale-gen en_US的建议运行后,程序按预期运行。


dtruss在对 macOS 10.15.7 (19H2)进行进一步调查后,open调用是针对en_GB不存在的目录(我的默认系统语言),并且en_US仅在默认语言设置为 时才有效English (US),即它似乎setlocale实际上无法更改语言环境,即使它返回传递给它的语言环境。这似乎是一个错误?我想我会向苹果报告。

编辑:它似乎setlocale被忽略,有利于LANGmacos 中的环境变量(gettext通过 Homebrew 安装)。在加载正确的消息文件setenv((char *)"LANG=en_US");之前添加,并按预期返回翻译。bindtextdomaindgettext

标签: cinternationalizationgettext

解决方案


您的代码是正确的,并且适用于我的 Mac OS 和 linux 系统,包括en_USen_US.UTF-8. 因此,除了您通常应该""在调用中使用本机语言环境之外,您不会遗漏任何东西,setlocale()但您自己可能知道:

setlocale(LC_ALL, "");

所以,我只能回答如何调试问题的问题。

基本上有两件事可能会出错:

首先,您选择的语言环境setlocale()在您的系统上不可用。这可以通过输出 的返回值轻松检查setlocale(LC_ALL, selected_locale)。在您的测试项目中,您已经这样做了。如果选定的语言环境不可用,调用setlocale()将返回。NULL

可能出错的第二件事是找不到翻译目录。最好strace在 GNU/Linux 或dtrussMac OS 上进行调试:

$ sudo dtruss ./dgettextexample

只需跟踪您的程序正在尝试访问open()的文件,以便了解出现了什么问题。


推荐阅读