Интернационализация и локализация

Лекции прошлых лет:

Термины

Объекты ПО

Другие объекты продукта

Локализация: инструменты

GNU Gettext

Документация

Создание перевода

  1. I18n: Обмажем функцией gettext() все строки, нуждающиеся в переводе

    • Есть ещё ngettext(), см. ниже

  2. xgettext: Создадим на основе i18n-ванного исходного кода шаблон перевода, файл domain.pot (domain — это довольно произвольное название того, что мы переводим)

    • Не удаляйте сгенерированные комментарии из файла, это не комментарии☺!

  3. msginit: Создадим прототип перевода (для русского — ru.po)

  4. (текстовый редактор или специализированный инструмент редактирования .po) Переведём все строки в ru.po

  5. msgfmt: Скомпилируем перевод в файл ru.mo

Обновление перевода

Вышла новая версия программы (или сами поправили). Там «поехали» строки с сообщениями (появились новые, пропали/изменились/переместились старые).

  1. xgettext: Сгенерируем новый шаблон

  2. msgmerge: Обновим содержимое ru.po на основании шаблона и старого ru.po. У msgmerge много искусственного мозга:

    • Не теряет старые переводы (только комментирует)
    • Размечает новые сообщения возможными (fuzzy) переводами из старых/закомментированных

    • Умеет в примитивную память переводов

  3. Допереводим ru.po

  4. msgfmt: Компилируем новый перевод

LecturesCMC/PythonDevelopment2020/08_L10n/Gettext.svg.png

Есть ещё вспомогательные инструменты:

$ rpm -ql gettext-tools | grep /bin/ | cut -d/ -f4 | xargs -n1 whatis
autopoint (1)        - copies standard gettext infrastructure
gettextize (1)       - install or upgrade gettext infrastructure
msgattrib (1)        - attribute matching and manipulation on message catalog
msgcat (1)           - combines several message catalogs
msgcat (n)           - Tcl message catalog
msgcmp (1)           - compare message catalog and template
msgcomm (1)          - match two message catalogs
msgconv (1)          - character set conversion for message catalog
msgen (1)            - create English message catalog
msgexec (1)          - process translations of message catalog
msgfilter (1)        - edit translations of message catalog
msgfmt (1)           - compile message catalog to binary format
msggrep (1)          - pattern matching on message catalog
msginit (1)          - initialize a message catalog
msgmerge (1)         - merge message catalog and template
msgunfmt (1)         - uncompile message catalog from binary format
msguniq (1)          - unify duplicate translations in message catalog
recode-sr-latin (1)  - convert Serbian text from Cyrillic to Latin script
xgettext (1)         - extract gettext strings from source

Ход работы

простая методичка

  1. Преобразовать текст на Си (собственно i18n)

    • Традиционный макрос _() (не обязателен)

     #include <libintl.h>
     #include <locale.h>
     #define _(STRING) gettext(STRING)
    • В main()-е

     setlocale (LC_ALL, "")
     bindtextdomain ("домен", "путь к локализации");
     textdomain ("домен");
    • Во всей программе заменить строки "Something..." на _("Something...") (вызов gettext())

  2. Создание шаблона (шаблон — это генерат)
    $ xgettext --keyword=_ исходник -o шаблон.pot
    • Документация xgettext

    • Если не использовать «_», то и --keyword не нужен

  3. Создание первоначального пустого перевода
    $ msginit -i шаблон.pot -l локаль -o перевод.po
    • Документация msginit

    • Большинство комментариев — значащие (например, "#, c-format"), лучше их не трогать

    • Некоторые поля следует заполнить заранее (vim выделяет их жёлтым)
  4. Перевод
    • Строки msgstr — это переводы (поначалу пустые)

  5. Компиляция перевода (нужна для интерпретации формулы множественного числа)
     $ msgfmt -o скомпилированный_перевод.mo перевод.po
  6. Обновление перевода
    • Перегенерация шаблона (см. выше, точно той же командой xgettext)

    • Обновление старого перевода на основании нового шаблона
      $ msgmerge -U старый_перевод.po новый_шаблон.pot
    • При этом;
      • Совсем удалённые сообщения в переводе комментируются (но не удаляются — это translation memory!)
      • Некоторые новые сообщения не переведены, для других подобраны похожие переводы, и помечены #, fuzzy. Fuzzy-строки считаются непереведёнными, для того, чтобы они вступили в силу, эту часть комментария (и только ее!) надо удалить

Варианты «пути к локализации»

  1. Локальный — положить рядом с бинарником или в подкаталог po/

    • /!\ Так в Linux не принято!

  2. Системный — положить в /usr/share/locale и/или в /usr/local/share/locale

    • /!\ Требует прав администратора и средств деинсталляции (⇒ вариант для пакетов)

  3. Микс — предусмотреть два варианта сборки, определить переменную в configure и т. д.

  4. С относительным путём: сформировать путь относительно местоположения бинарника

    • если бинарник ставится в /usr/bin, а переводы — в /usr/share/locale

      • то путь получится ../share/locale

    • выполнить тестовую установку куда-нибудь в /tmp или /home/пользователь/что-то-там

      • при этом бинарник должен ставиться в /home/пользователь/что-то-там/bin/программа

      • оттуда и запускать
      • а путь до локали /home/пользователь/что-то-там/share/locale/… остаётся тот же самый: ../share/locale

Использование множественных форм

В английском их две, в русском — три: 1¹ / 2,3,4² / 5-20³ / 21¹ и т. д.

Страшная формула в строке Plural-Forms:

Если увеличить nplurals до 4 и добавить в начало формулы n==1? 3 :, получим четвёртую словоформу — для ровно одного объекта (в таких случаях можно число 1 не выводить)

Translation memory

Gettext и Autotools

В Autotools есть поддержка GNU Gettext

Исходники для autotools:

Остальные генераты не нужны (их приедет довольно много)

Создание и обновление перевода

/!\ Если увидите методичку с упоминанием явного запуска утилиты gettextize или intltool — они устарели

Что хранить и что не хранить в GIT-е

Пример

В этом примере изначально autotools использовались для всего, кроме переводов.

Под конец пример переключается на autotools, и каталоги с исходниками и с переводами разделяются

После каждого коммита я делал

Сборка пакета

В примере я использовал вариант, подходящий для хранения исходников пакета в git: все специфичные для ALT файлы (в частности, spec-файл) лежат прямо там же в подкаталоге .gear.

О том, что собираются и устанавливаются переводы, напоминает только autopoint и добавочный ключ к %autoreconf в секции %conf.

Протестировать собранный пакет (без root, в хешере!) можно так:

$ hsh --init
…
$ hsh-install ~/REPO/x86_64/RPMS.hasher/ahello-0.01-alt1.x86_64.rpm
…
$ hsh-shell
[builder@localhost .in]$ ahello
Hail thou the only Universe!

Hello, 0 Worlds!
Hello, 1 World!
Hello, 2 Worlds!
Hello, 3 Worlds!
Hello, 4 Worlds!
Hello, 5 Worlds!
[builder@localhost .in]$ LC_ALL=ru_RU.UTF-8 ahello
Привет тебе, о единая Вселенная!

Привет, 0 миров!
Привет, мир!
Привет, 2 мира!
Привет, 3 мира!
Привет, 4 мира!
Привет, 5 миров!
[builder@localhost .in]$

Поддержка Gettext в других системах сборки

Д/З

LecturesCMC/LinuxApplicationDevelopment2026/08_I18n (последним исправлял пользователь FrBrGeorge 2026-11-04 19:07:20)