Для проекта встроенного программного обеспечения я добавляю поддержку переводов, и, поскольку мы работаем со встроенным 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") ==> "Ḗřřǿř"
Теперь, когда я компилирую это динамически, это не работает. Ни на целевом устройстве, ни локально на моем ПК (файлы установлены одинаково). Вызов 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"
EDIT: компиляция тестового двоичного файла как статического на моем хосте (x64 Linux) также заставляет его работать, поэтому в статической компиляции есть что-то особенное.
Дополнительный вопрос: могу ли я заставить gettext загружать конкретный файл mo напрямую? В основном я хотел бы иметь замену для bindtextdomain()
, которая вместо этого принимает аргумент имени файла.
ИЗМЕНИТЬ 2: Итак, я в конце концов нашел этот пост, в котором говорилось, что я могу заставить gettext()
загрузить любой перевод, если сначала у меня есть действующий setlocale()
звонок. Итак, мой текущий обходной путь состоит в том, чтобы фактически создать /usr/lib/locale/locale-archive
, содержащий только en_US
локаль, вызывая setlocale(LC_MESSAGES, "en_US"); setenv("LANGUAGE", "fake");
, что в конечном итоге приводит к загрузке правильного каталога сообщений. По-прежнему кажется уродливым обходным решением, и я до сих пор не понимаю, почему статическая ссылка работает без нее.
setlocale(LC_MESSAGES, "");
с правильными переменными среды? - person jdarthenay   schedule 26.04.2016setenv("LC_MESSAGES", "fake")
и замена вызова setlocale наsetlocale(LC_MESSAGES, "")
по-прежнему не работают так же, как выполнение прямого вызоваsetlocale()
. - person nafmo   schedule 26.04.2016