Извлечь один перевод из файла gettext .po из оболочки

В качестве этапа сборки моего приложения на C++ (с использованием CMake в качестве системы сборки) мне нужно создать несколько файлов шаблонов, которые должны включать локализованные строки.

Строки доступны у переводчиков уже в виде файлов gettext .po (таких же, которые будут использоваться для перевода самого приложения).

Поэтому мне нужен способ извлечь перевод на заданную исходную строку на английском языке из файла .po (либо через Bash/shell, либо через CMake)

То, что я придумал до сих пор, следующее

translated_string=$(
    msggrep --msgid -e "^${untranslated_string}$" ${po_file} \
        | msgattrib --no-fuzzy \
        | grep -A 1 'msgid "${untranslated_string}$"' \
        | sed -n 's/msgstr "\(.*\)"/\1/p'
)

Очевидно, что это много вызовов «простой» функции:

  • msggrep выводит файл .po, в котором есть только нужная мне строка
  • msgattrib следит за тем, чтобы перевод не был "нечетким" (т.е. нуждался в обновлении), так как я не могу использовать эти
  • Затем я вручную извлекаю перевод, используя grep и sed.

Я полагаю, должен быть лучший подход к этому? В конце концов, gettext упрощает перевод моего приложения во время выполнения, но кажется несколько негибким во время сборки...


person Patrick Storz    schedule 11.02.2019    source источник


Ответы (2)


.po файлы предназначены для переводчиков. Программное обеспечение должно использовать скомпилированные .mo файлы для поиска переводов.

GNU gettext поставляется с двоичным файлом gettext, предназначенным для интернационализации сценариев оболочки. Вы можете использовать это для своих целей следующим образом:

$ mkdir -p de/LC_MESSAGES 2>/dev/null
$ msgfmt --verbose --statistics de.po -o de/LC_MESSAGES/package.mo
$ TEXTDOMAINDIR=. LANGUAGE=de LANG=de_DE.UTF-8 LC_MESSAGES=de_DE.UTF-8 gettext package 'Hello, world!'

Замените «пакет» своим текстовым доменом «Hello, world!» с вашим идентификатором сообщения и de с языком по вашему выбору. Обратите внимание, что для этого требуется, чтобы выбранная локаль — в данном случае локаль de — была установлена ​​в системе сборки.

См. gettext(1) и msgfmt(1) для получения дополнительной информации.

person Guido Flohr    schedule 15.02.2019
comment
Это хорошее решение, и я мог бы заставить его работать в принципе. Однако он не предоставляет переводы для многих локалей (т.е. просто печатает английскую строку). К сожалению, похоже, что он не работает для нелатинских языков, что очень жаль, учитывая, что в противном случае он работает хорошо. Можете ли вы уточнить вашу заметку? Может ли это быть связано? Что вы подразумеваете под установленной локалью (т.е. что решает, установлена ​​ли локаль или нет?). - person Patrick Storz; 15.02.2019
comment
Команда locale -a выводит список установленных локалей. Установлены ли в вашей системе нелатинские локали? Попробуйте strace или эквивалент для вашей платформы, чтобы узнать, какие пути используются для $PATH/gettext. - person Guido Flohr; 16.02.2019
comment
Да, в принципе локали должны быть установлены, но это быстро становится более сложным и хрупким, чем то, что у меня было изначально... Даже если я проигнорирую тот факт, что gettext не печатает должным образом все переводы, я столкнусь с другой проблемой: Кодировка печатаемых строк полностью перепутана, и я не могу заставить ее печатать как UTF-8, поэтому, даже если я получу все переводы, я все равно не смогу их правильно использовать. Я проведу еще один эксперимент с реализацией Python gettext, в противном случае я просто останусь со своим сценарием оболочки. - person Patrick Storz; 16.02.2019
comment
Пожалуйста, прочтите документацию пользователя, например, на sensi.org/~alec/ locale/other/about-nls.html. Возможно, вы можете решить свою проблему, установив не только LANGUAGE, но и LANG и включив кодировку в последний. Я обновлю свой ответ соответственно. - person Guido Flohr; 16.02.2019
comment
Я уже пробовал несколько комбинаций LANGUAGE и LANG, включая и исключая регион, а также добавляя кодировку, но все безрезультатно. Либо моя версия gettext глючит (я использую нативную версию mingw-w64, скомпилированную проектом MSYS2), либо программа слишком умна, чтобы просто выводить строку из одного файла в той локали, которую я хочу. Сейчас я решил это на python (я добавлю ответ), который был довольно простым, работает так же хорошо, как и моя версия сценария оболочки, но значительно более эффективен. (это могло бы сэкономить мне много времени, если бы я начал с этого...) - person Patrick Storz; 17.02.2019

Использование двоичных файлов .mo и извлечение оттуда строки, как это было предложено Гвидо Флором в https://stackoverflow.com/a/54707280/2514664 оказалось рабочим решением.

Однако использование собственного исполняемого файла gettext для извлечения строки, как было предложено в исходном ответе, имело слишком много последствий (в конце концов, он предназначен для извлечения видимой пользователем строки в локали, наиболее подходящей для пользователя, из существующего сообщения каталог, а не как инструмент сборки, который «просто» должен извлечь одну строку на определенном языке из определенного файла). В конечном счете, он слишком хрупок для использования в системе сборки, которая должна работать на нескольких платформах.

Я использую Python, и его собственный модуль gettext работает намного лучше и может сэкономьте много усилий (особенно если вы хорошо разбираетесь в Python).

Создание файлов .mo из файлов .po может работать, как это предлагается в связанном ответе:

mkdir -p locale/de/LC_MESSAGES
msgfmt de.po -o locale/de/LC_MESSAGES/package.mo

Получить перевод на Python проще простого.

import gettext

translation = gettext.translation('package', localedir='locale', languages=['de'])
translated_string = translation.gettext('unstranslated_string')

Кстати. после решения моей собственной проблемы я обнаружил, что в папке «/Tools/i18n» моего дистрибутива Python также есть msgfmt.py и pygettext.py, которые должны предлагать ту же функциональность, что и сами msgfmt и gettext. Оба они могут быть интересны для решения схожих проблем либо для непосредственного использования, либо для изучения их реализации для создания чего-то нового (например, msgfmt.py включает в себя простой анализатор файлов .po).

person Patrick Storz    schedule 17.02.2019