Internationalization and localization of the python applications with gettext by Alexander Belchenko

31
Интернационализация и локализация python-приложений с использованием gettext Александр Бельченко (bialix) http://bialix.com/pycamp/gettext.pdf v.1.2

description

Presentation from the Alexander Belchenko (@bialix) on the PyCamp Kyiv, 2010.01.30

Transcript of Internationalization and localization of the python applications with gettext by Alexander Belchenko

Page 1: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Интернационализация и локализация python-приложений

с использованием gettext

Александр Бельченко (bialix)

http://bialix.com/pycamp/gettext.pdf

v.1.2

Page 2: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Вступительное слово

Это будет еще один доклад про ДжангоЭто доклад про GUI desktop приложения. Частично может быть применимо для webЛокализация нужна пользователямСеребряной пули нет (и ложки тоже нет)Пример одного из возможных вариантов использования gettext. Мы используем его в Bazaar GUI

Page 3: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Стандартный модуль gettext в Python

Предоставляет два вида API:Функции GNU gettext APIКласс GNUTranslations

Функциональное API лишь обертка вокруг классов; в общем случае работает несколько медленнее

Page 4: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Функции gettext.py

Пара функций-переводчиков:gettext — перевод простых строкngettext — перевод с выбором между единственным и множественным числом

Варианты функций с различными префиксами:

u — возвращает перевод как unicode строкуl — перевод в нужной кодировкеd — перевод ищется в указанном домене

Page 5: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Файлы с переводами

Где gettext ищет файлы переводов (sys.prefix/share/locale):

Linux: /usr/local/share/localeWindows: C:\PythonXY\share\locale

Путь поиска можно указать вручнуюСтандартная локация:

Linux: /usr/share/localeWindows: ???

{app}/locale

Page 6: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Язык пользователя

Язык для перевода:Можно указать вручнуюПо умолчанию берется из переменных окружения:LANGUAGE, LC_ALL, LC_MESSAGES, LANG

Эти переменные окружения отсутствуют на Windows (сюрприз-сюрприз!)

Page 7: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Кратко о GNU gettext, PO и MO

Библиотека общего назначения: годится для консоли, GUI и webСтандарт де-факто

Существует развитая инфраструктура инструментов: специальные редакторы, поддержка в web-сервисах для перевода

Файлы:POT — шаблон для переводаPO — файлы перевода на конкретные языкиMO — бинарные файлы перевода (runtime)

Page 8: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Формат PO-файлов

1) Заголовок файла (информация о переводчике, кодировка, выражение для множественного числа)

2) Тело файла состоит из записей вида: #: foo.py:3 msgid "Hello" msgstr ""

Page 9: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Работа с 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

Page 10: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Python-утилитыВ стандартной поставке Python:

pygettext.pymsgfmt.py

В production использовать НЕ рекомендуюЕдинственное видимое достоинство pygettext: умение извекать docstringsНедостатки: не знает про ngettext, dgettext

Для Windows: http://gnuwin32.sf.net

Page 11: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Кавалерийская атака на танки

Документация на модуль gettext рекомендует очень простой способ включения:

import gettextgettext.install('myapp', unicode=True)

В коде приложения не надо ничего импортировать и можно делать:

s = _('Hello, world!')

В чем подвох?

Page 12: Internationalization and localization of the python applications with gettext by Alexander Belchenko

В чем подвох gettext.install

Такой короткий код нормально работает на Linux и в большинстве случаев НЕ работает на WindowsНарушается принцип: явное лучше неявногоПеревод строк сразу «включается» для языка пользователя (LANG)

Что в свою очередь влияет на юнит-тесты, если вы проверяете строки

Page 13: Internationalization and localization of the python applications with gettext by Alexander Belchenko

В чем подвох _()

?

Page 14: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Мы пойдём другим путём

Будем использовать функции и методы модуля gettext напрямую и импортировать имена явноВключать перевод когда это нам нужноСледовать уставу в чужом монастыре

Page 15: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Использование gettext в среде Windows

Кто украл $LANG? (Известно, кто)locale.getdefaultlocale()[0]Получение идентификатора локали LCID (через pywin32 или ctypes):

GetUserDefaultLCID()GetSystemDefaultLCID()

Преобразование LCID в строку при помощи стандартного модуля locale:

locale.windows_locale[lcid]

Page 16: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Пример готового кода

launchpad.net/gettext-py-windowsКратко:

import ctypes, localelcid = ctypes.windll.kernel32.\ GetUserDefaultLCID()lang = locale.windows_locale[lcid]

Page 17: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Использование методов gettext

Работаем с API класса(-ов) GNUTranslations:

import gettext as _gettext_t = _gettext.NullTranslations()_t = _gettext.translation('myapp', localedir=xxx, fallback=True)

Page 18: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Функции-переводчики

bzr branch lp:qbzr (lib/i18n.py)

def gettext(s): return _t.ugettext(s)def N_(s): return s

def ngettext(s, p, n): return _t.ungettext(s, p, n)

Page 19: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Использование в основном коде

import i18n...print i18n.gettext('Hello, world!')Либо:

from i18n import gettext...print gettext('Hello, world!')

Page 20: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Выбор формы множественного числа

«Найдено %d документов»

Английский: Found 1 document Found 2 documents

Русский: Найден 1 документ Найдено 2 документа Найдено 5 документов

Page 21: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Функция ngettextСигнатура: ngettext(singular, plural, number)

print ngettext('Found %d document', 'Found %d documents', n) % nPOT-файл:

#: foo.py:7#, python-formatmsgid "Found %d document"msgid_plural "Found %d documents"msgstr[0] ""msgstr[1] ""

Page 22: Internationalization and localization of the python applications with gettext by Alexander Belchenko

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)

Page 23: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Тестирование интернационализации

Используем специальный класс ZzzTranslations(), который декорирует строкиВключаем явно через командную строку:

python myapp.py --zzz

Page 24: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Класс 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))

Page 25: Internationalization and localization of the python applications with gettext by Alexander Belchenko
Page 26: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Инфраструктура проекта

Структура каталогов:

myapplib/locale/ ← mo файлыpo/ ← pot, po файлыmyapp.pysetup.pysetup.py: build_pot, build_mo

Page 27: Internationalization and localization of the python applications with gettext by Alexander Belchenko

● Это не шутка, он реально нужен (LANG=en:ja)

● Генерируется автоматически из POT-шаблона утилитой msginit либо msgen

Нужен ли перевод с дефолтного языка на английский?

Page 28: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Строки форматированияНеправильно: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)

Page 29: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Web-сервисы для совместной работы над переводами

Один из сервисов: переводы на https://translations.launchpad.net/●Удобно для разработчиков: все языки в одном месте

●Удобно для переводчиков: подсказки о переводах таких же фраз из других проектов

Page 30: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Применение gettext в PyQt4?

В собственном коде использовать gettext() вместо tr() Формы/диалоги создаваемые в QtDesigner: трансляция *.ui → ui_*.py

используется скрипт для автоматической замены вызовов QtGui.QApplication.translate() на gettext()

Page 31: Internationalization and localization of the python applications with gettext by Alexander Belchenko

Ссылки

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/qbzrhttps://launchpad.net/bzr-explorer