Internationalization and localization of the python applications with gettext by Alexander Belchenko
1. Интернационализация и локализация
python-приложений
с использованием gettext
Александр Бельченко (bialix)
http://bialix.com/pycamp/gettext.pdf
v.1.2
2. Вступительное слово
Это будет еще один доклад про Джанго
Это доклад про GUI desktop приложения.
Частично может быть применимо для web
Локализация нужна пользователям
Серебряной пули нет (и ложки тоже нет)
Пример одного из возможных вариантов
использования gettext. Мы используем его
в Bazaar GUI
3. Стандартный модуль gettext
в Python
Предоставляет два вида API:
Функции GNU gettext API
Класс GNUTranslations
Функциональное API лишь обертка вокруг
классов; в общем случае работает несколько
медленнее
4. Функции gettext.py
Пара функций-переводчиков:
gettext — перевод простых строк
ngettext — перевод с выбором между
единственным и множественным числом
Варианты функций с различными
префиксами:
u — возвращает перевод как unicode строку
l — перевод в нужной кодировке
d — перевод ищется в указанном домене
5. Файлы с переводами
Где gettext ищет файлы переводов
(sys.prefix/share/locale):
Linux: /usr/local/share/locale
Windows: C:PythonXYsharelocale
Путь поиска можно указать вручную
Стандартная локация:
Linux: /usr/share/locale
Windows: ???
{app}/locale
6. Язык пользователя
Язык для перевода:
Можно указать вручную
По умолчанию берется из переменных
окружения:
LANGUAGE, LC_ALL, LC_MESSAGES, LANG
Эти переменные окружения отсутствуют на
Windows (сюрприз-сюрприз!)
7. Кратко о GNU gettext, PO и MO
Библиотека общего назначения: годится для
консоли, GUI и web
Стандарт де-факто
Существует развитая инфраструктура
инструментов: специальные редакторы,
поддержка в web-сервисах для перевода
Файлы:
POT — шаблон для перевода
PO — файлы перевода на конкретные языки
MO — бинарные файлы перевода (runtime)
8. Формат PO-файлов
1) Заголовок файла (информация о
переводчике, кодировка, выражение для
множественного числа)
2) Тело файла состоит из записей вида:
#: foo.py:3
msgid "Hello"
msgstr ""
9. Работа с GNU gettext утилитами
Сбор строк для перевода (py → pot):
xgettext myapp.py myapplib/*.py -o myapp.pot
Создание файла перевода для конкретного
языка (pot → po):
msginit -l ru -i myapp.pot -o myapp-ru.po
Трансляция в бинарный формат (po → mo):
msgfmt -o locale/ru/LC_MESSAGES/myapp.mo
myapp-ru.po
Обновление файлов с переводами (pot→po):
msgmerge myapp-ru.po myapp.pot -o new.po
10. Python-утилиты
В стандартной поставке Python:
pygettext.py
msgfmt.py
В production использовать НЕ рекомендую
Единственное видимое достоинство
pygettext: умение извекать docstrings
Недостатки: не знает про ngettext, dgettext
Для Windows: http://gnuwin32.sf.net
11. Кавалерийская атака на танки
Документация на модуль gettext рекомендует
очень простой способ включения:
import gettext
gettext.install('myapp', unicode=True)
В коде приложения не надо ничего
импортировать и можно делать:
s = _('Hello, world!')
В чем подвох?
12. В чем подвох gettext.install
Такой короткий код нормально работает на
Linux и в большинстве случаев НЕ работает
на Windows
Нарушается принцип: явное лучше неявного
Перевод строк сразу «включается» для
языка пользователя (LANG)
Что в свою очередь влияет на юнит-тесты, если
вы проверяете строки
14. Мы пойдём другим путём
Будем использовать функции и методы
модуля gettext напрямую и импортировать
имена явно
Включать перевод когда это нам нужно
Следовать уставу в чужом монастыре
15. Использование gettext
в среде Windows
Кто украл $LANG? (Известно, кто)
locale.getdefaultlocale()[0]
Получение идентификатора локали LCID
(через pywin32 или ctypes):
GetUserDefaultLCID()
GetSystemDefaultLCID()
Преобразование LCID в строку при помощи
стандартного модуля locale:
locale.windows_locale[lcid]
17. Использование методов gettext
Работаем с API класса(-ов) GNUTranslations:
import gettext as _gettext
_t = _gettext.NullTranslations()
_t = _gettext.translation('myapp',
localedir=xxx,
fallback=True)
19. Использование в основном коде
import i18n
...
print i18n.gettext('Hello, world!')
Либо:
from i18n import gettext
...
print gettext('Hello, world!')
20. Выбор формы
множественного числа
«Найдено %d документов»
Английский:
Found 1 document
Found 2 documents
Русский:
Найден 1 документ
Найдено 2 документа
Найдено 5 документов
22. gettext и unit-тесты
Всегда включать перевод явно для основного
режима и не включать для режима тестов
_t = _gettext.NullTranslations()
def install():
global _t
if sys.platform == 'win32':
_check_win32_locale()
_t = _gettext.translation('myapp',
localedir=_get_locale_dir(),
fallback=True)
23. Тестирование
интернационализации
Используем специальный класс
ZzzTranslations(), который декорирует
строки
Включаем явно через командную строку:
python myapp.py --zzz
24. Класс ZzzTranslations
class _ZzzTranslations(object):
def zzz(self, s):
return 'zz{{%s}}' % s
def ugettext(self, s):
return self.zzz(
_null_t.ugettext(s))
def ungettext(self, s, p, n):
return self.zzz(
_null_t.ungettext(s, p, n))
27. Нужен ли перевод с дефолтного
языка на английский?
● Это не шутка, он реально нужен
(LANG=en:ja)
● Генерируется автоматически
из POT-шаблона утилитой msginit
либо msgen
28. Строки форматирования
Неправильно:
s = gettext('Page ' + number +
' of ' + count + ' pages')
s = gettext('Page %d of %d pages' %
(number, count))
Плохо:
s = gettext('Page %d of %d pages') %
(number, count)
Хорошо:
s = gettext('Page %(number)d of '
'%(count)d pages') %
dict(number=number,
count=count)
29. Web-сервисы для совместной
работы над переводами
Один из сервисов: переводы на
https://translations.launchpad.net/
●Удобно для разработчиков: все языки в одном
месте
●Удобно для переводчиков: подсказки о
переводах таких же фраз из других проектов
30. Применение gettext в PyQt4?
В собственном коде использовать gettext()
вместо tr()
Формы/диалоги создаваемые в QtDesigner:
трансляция *.ui → ui_*.py
используется скрипт для автоматической
замены вызовов
QtGui.QApplication.translate()
на gettext()
31. Ссылки
GNU gettext: http://www.gnu.org/software/gettext
Утилиты для Windows:
http://gnuwin32.sf.net/packages/gettext.htm
Код поддержки gettext для Windows:
https://launchpad.net/gettext-py-windows
Примеры основаны на коде проектов:
https://launchpad.net/qbzr
https://launchpad.net/bzr-explorer