Документация Python неофициальный перевод

gettext.md

468 строк · 45.6 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.9/library/gettext.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) – Многоязычные сервисы интернационализации89**Исходный код:** [Lib/gettext.py](https://python-all.ru/src/3.9/Lib/gettext.py)1011---1213Модуль [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) предоставляет службы интернационализации (I18N) и локализации (L10N) для модулей и приложений Python. Он поддерживает как API каталогов сообщений GNU **gettext**, так и более высокоуровневый API на основе классов, который может лучше подходить для файлов Python. Описанный ниже интерфейс позволяет писать сообщения модуля и приложения на одном естественном языке и предоставлять каталог переведённых сообщений для работы на разных естественных языках.1415Также даются некоторые советы по локализации модулей и приложений Python.1617## GNU **gettext** API1819Модуль [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) определяет следующий API, очень похожий на API GNU **gettext**. Использование этого API повлияет на перевод всего приложения глобально. Часто это желательно, если приложение одноязычное и выбор языка зависит от локали пользователя. Если требуется локализовать модуль Python или приложению нужно переключать языки на лету, вероятно, следует использовать API на основе классов.2021#### `gettext.bindtextdomain(domain, localedir=None)`2223Привязывает *domain* к каталогу локали *localedir*. Конкретнее, [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) будет искать двоичные файлы `.mo` для указанного домена, используя путь (в Unix): `localedir/language/LC_MESSAGES/domain.mo`, где *language* ищется в переменных окружения `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` и `LANG` соответственно.2425Если *localedir* опущен или равен `None`, то возвращается текущая привязка для *domain*. [1](https://python-all.ru/3.9/library/gettext.html#id3)2627#### `gettext.bind_textdomain_codeset(domain, codeset=None)`2829Привязывает *domain* к *codeset*, изменяя кодировку байтовых строк, возвращаемых функциями [`lgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.lgettext), [`ldgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.ldgettext), [`lngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.lngettext) и [`ldngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.ldngettext). Если *codeset* опущен, возвращается текущая привязка.3031Устарело с версии 3.8, будет удалено в версии 3.10.3233#### `gettext.textdomain(domain=None)`3435Изменяет или запрашивает текущий глобальный домен. Если *domain* равен `None`, возвращается текущий глобальный домен; в противном случае глобальный домен устанавливается в *domain*, который и возвращается.3637#### `gettext.gettext(message)`3839Возвращает локализованный перевод *message* на основе текущего глобального домена, языка и каталога локали. Эта функция обычно имеет псевдоним `_()` в локальном пространстве имён (см. примеры ниже).4041#### `gettext.dgettext(domain, message)`4243Как [`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.gettext), но ищет сообщение в указанном *domain*.4445#### `gettext.ngettext(singular, plural, n)`4647Как [`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.gettext), но учитывает формы множественного числа. Если перевод найден, применяет формулу множественного числа к *n* и возвращает результирующее сообщение (в некоторых языках более двух форм множественного числа). Если перевод не найден, возвращает *singular*, если *n* равно 1; в противном случае возвращает *plural*.4849Формула множественного числа берётся из заголовка каталога. Это выражение на C или Python со свободной переменной *n*; выражение вычисляет индекс формы множественного числа в каталоге. См. [документацию GNU gettext](https://python-all.ru/3.9/library/gettext.html) для точного синтаксиса, используемого в файлах `.po`, и формулы для различных языков.5051#### `gettext.dngettext(domain, singular, plural, n)`5253Как [`ngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.ngettext), но ищет сообщение в указанном *domain*.5455#### `gettext.pgettext(context, message)`5657#### `gettext.dpgettext(domain, context, message)`5859#### `gettext.npgettext(context, singular, plural, n)`6061#### `gettext.dnpgettext(domain, context, singular, plural, n)`6263Аналогично соответствующим функциям без `p` в префиксе (то есть [`gettext()`](https://python-all.ru/3.9/library/gettext.html#module-gettext), [`dgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.dgettext), [`ngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.ngettext), [`dngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.dngettext)), но перевод ограничен заданным *context* сообщения.6465Новое в версии 3.8.6667#### `gettext.lgettext(message)`6869#### `gettext.ldgettext(domain, message)`7071#### `gettext.lngettext(singular, plural, n)`7273#### `gettext.ldngettext(domain, singular, plural, n)`7475Эквивалентно соответствующим функциям без префикса `l` ([`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.gettext), [`dgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.dgettext), [`ngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.ngettext) и [`dngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.dngettext)), но перевод возвращается в виде байтовой строки, закодированной в предпочтительной системной кодировке, если другая кодировка не была явно задана с помощью [`bind_textdomain_codeset()`](https://python-all.ru/3.9/library/gettext.html#gettext.bind_textdomain_codeset).7677> **Предупреждение**78>79> Этих функций следует избегать в Python 3, так как они возвращают закодированные байты. Гораздо лучше использовать альтернативы, возвращающие вместо них строки Unicode, поскольку большинство приложений Python работают с читаемым текстом в виде строк, а не байтов. Кроме того, возможно возникновение неожиданных исключений, связанных с Unicode, при проблемах кодировки переведённых строк.8081Устарело с версии 3.8, будет удалено в версии 3.10.8283Обратите внимание, что GNU **gettext** также определяет метод `dcgettext()`, но он был признан бесполезным и на данный момент не реализован.8485Вот пример типичного использования этого API:8687```python88import gettext89gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')90gettext.textdomain('myapplication')91_ = gettext.gettext92# ...93print(_('This is a translatable string.'))94```9596## API на основе классов9798API на основе классов модуля [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) даёт больше гибкости и удобства, чем API GNU **gettext**. Это рекомендуемый способ локализации приложений и модулей Python. `gettext` определяет класс [`GNUTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations), который реализует разбор файлов формата GNU `.mo` и имеет методы для возврата строк. Экземпляры этого класса также могут устанавливать себя во встроенное пространство имён в качестве функции `_()`.99100#### `gettext.find(domain, localedir=None, languages=None, all=False)`101102Эта функция реализует стандартный алгоритм поиска файла `.mo`. Она принимает *domain*, идентичный тому, что принимает [`textdomain()`](https://python-all.ru/3.9/library/gettext.html#gettext.textdomain). Необязательный параметр *localedir* – как в [`bindtextdomain()`](https://python-all.ru/3.9/library/gettext.html#gettext.bindtextdomain). Необязательный *languages* – это список строк, где каждая строка – код языка.103104Если *localedir* не указан, используется системный каталог локали по умолчанию. [2](https://python-all.ru/3.9/library/gettext.html#id4) Если *languages* не указан, то проверяются следующие переменные окружения: `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` и `LANG`. Для переменной *languages* используется первая из них, возвращающая непустое значение. Переменные окружения должны содержать разделённый двоеточиями список языков; он будет разбит по двоеточиям для получения ожидаемого списка кодов языков.105106[`find()`](https://python-all.ru/3.9/library/gettext.html#gettext.find) затем расширяет и нормализует языки, а затем перебирает их в поисках существующего файла, построенного из следующих компонентов:107108`localedir/language/LC_MESSAGES/domain.mo`109110Первое существующее имя файла возвращается [`find()`](https://python-all.ru/3.9/library/gettext.html#gettext.find). Если такого файла не найдено, возвращается `None`. Если указан *all*, возвращается список всех имён файлов в том порядке, в котором они встречаются в списке языков или в переменных окружения.111112#### `gettext.translation(domain, localedir=None, languages=None, class_=None, fallback=False, codeset=None)`113114Возвращает экземпляр `*Translations` на основе *domain*, *localedir* и *languages*, которые сначала передаются в [`find()`](https://python-all.ru/3.9/library/gettext.html#gettext.find) для получения списка соответствующих путей к файлам `.mo`. Экземпляры с одинаковыми именами файлов `.mo` кэшируются. Фактически создаётся класс *class\_*, если он указан, иначе [`GNUTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations). Конструктор класса должен принимать единственный аргумент [file object](https://python-all.ru/3.9/glossary.html#term-file-object). Если указан *codeset*, он изменит кодировку, используемую для кодирования переведённых строк в методах [`lgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.lgettext) и [`lngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.lngettext).115116Если найдено несколько файлов, последующие файлы используются как запасные для предыдущих. Чтобы иметь возможность задать запасной вариант, [`copy.copy()`](https://python-all.ru/3.9/library/copy.html#copy.copy) используется для клонирования каждого объекта перевода из кэша; фактические данные экземпляра по-прежнему являются общими с кэшем.117118Если файл `.mo` не найден, эта функция вызывает [`OSError`](https://python-all.ru/3.9/library/exceptions.html#OSError), если *fallback* имеет значение false (по умолчанию), и возвращает экземпляр [`NullTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations), если *fallback* имеет значение true.119120Изменено в версии 3.3: [`IOError`](https://python-all.ru/3.9/library/exceptions.html#IOError) раньше вызывалось вместо [`OSError`](https://python-all.ru/3.9/library/exceptions.html#OSError).121122Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *codeset*.123124#### `gettext.install(domain, localedir=None, codeset=None, names=None)`125126Эта функция устанавливает функцию `_()` в пространство имён встроенных функций Python на основе *domain*, *localedir* и *codeset*, которые передаются в функцию [`translation()`](https://python-all.ru/3.9/library/gettext.html#gettext.translation).127128Описание параметра *names* см. в описании метода [`install()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.install) объекта перевода.129130Как показано ниже, строки в приложении, предназначенные для перевода, обычно помечаются обёртыванием их в вызов функции `_()`, например:131132```python133print(_('This string will be translated.'))134```135136Для удобства функцию `_()` устанавливают в пространство имён встроенных функций Python, чтобы она была легко доступна во всех модулях приложения.137138Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *codeset*.139140### Класс [`NullTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations)141142Классы перевода – это то, что фактически реализует перевод строк сообщений исходного файла в переведённые строки сообщений. Базовый класс, используемый всеми классами перевода, – [`NullTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations); он предоставляет базовый интерфейс, который можно использовать для написания собственных специализированных классов перевода. Ниже приведены методы `NullTranslations`:143144#### `class gettext.NullTranslations(fp=None)`145146Принимает необязательный [файловый объект](https://python-all.ru/3.9/glossary.html#term-file-object) *fp*, который игнорируется базовым классом. Инициализирует «защищённые» переменные экземпляра *\_info* и *\_charset*, которые устанавливаются производными классами, а также *\_fallback*, которая устанавливается через [`add_fallback()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.add_fallback). Затем вызывает `self._parse(fp)`, если *fp* не равен `None`.147148#### `_parse(fp)`149150В базовом классе это метод-заглушка; он принимает файловый объект *fp* и читает данные из файла, инициализируя свой каталог сообщений. Если у вас есть неподдерживаемый формат файла каталога сообщений, следует переопределить этот метод для разбора вашего формата.151152#### `add_fallback(fallback)`153154Добавляет *fallback* в качестве запасного объекта для текущего объекта перевода. Объект перевода должен обращаться к запасному объекту, если он не может предоставить перевод для данного сообщения.155156#### `gettext(message)`157158Если был установлен запасной объект, перенаправить `gettext()` к нему. В противном случае вернуть *message*. Переопределяется в производных классах.159160#### `ngettext(singular, plural, n)`161162Если был установлен запасной объект, перенаправить `ngettext()` к нему. В противном случае вернуть *singular*, если *n* равен 1; иначе вернуть *plural*. Переопределяется в производных классах.163164#### `pgettext(context, message)`165166Если был установлен запасной объект, перенаправить [`pgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.pgettext) к нему. В противном случае вернуть переведённое сообщение. Переопределяется в производных классах.167168Новое в версии 3.8.169170#### `npgettext(context, singular, plural, n)`171172Если был установлен запасной объект, перенаправить [`npgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.npgettext) к нему. В противном случае вернуть переведённое сообщение. Переопределяется в производных классах.173174Новое в версии 3.8.175176#### `lgettext(message)`177178#### `lngettext(singular, plural, n)`179180Эквивалентно [`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.gettext) и [`ngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.ngettext), но перевод возвращается в виде байтовой строки, закодированной в предпочтительной системной кодировке, если кодировка не была явно задана с помощью [`set_output_charset()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.set_output_charset). Переопределяется в производных классах.181182> **Предупреждение**183>184> Этих методов следует избегать в Python 3. См. предупреждение для функции [`lgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.lgettext).185186Устарело с версии 3.8, будет удалено в версии 3.10.187188#### `info()`189190Возвращает «защищённую» переменную `_info` – словарь, содержащий метаданные из файла каталога сообщений.191192#### `charset()`193194Возвращает кодировку файла каталога сообщений.195196#### `output_charset()`197198Возвращает кодировку, используемую для возврата переведённых сообщений в [`lgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.lgettext) и [`lngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.lngettext).199200Устарело с версии 3.8, будет удалено в версии 3.10.201202#### `set_output_charset(charset)`203204Изменяет кодировку, используемую для возврата переведённых сообщений.205206Устарело с версии 3.8, будет удалено в версии 3.10.207208#### `install(names=None)`209210Этот метод устанавливает [`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.gettext) во встроенное пространство имён, связывая его с `_`.211212Если задан параметр *names*, он должен быть последовательностью, содержащей имена функций, которые нужно установить в пространство имён builtins в дополнение к `_()`. Поддерживаемые имена: `'gettext'`, `'ngettext'`, `'pgettext'`, `'npgettext'`, `'lgettext'` и `'lngettext'`.213214Обратите внимание, что это лишь один из способов, хоть и самый удобный, сделать функцию `_()` доступной в приложении. Поскольку это влияет на всё приложение глобально, и в особенности на встроенное пространство имён, локализованные модули никогда не должны устанавливать `_()`. Вместо этого им следует использовать следующий код, чтобы сделать `_()` доступной в своём модуле:215216```python217import gettext218t = gettext.translation('mymodule', ...)219_ = t.gettext220```221222Это помещает `_()` только в глобальное пространство имён модуля и поэтому влияет только на вызовы внутри этого модуля.223224Изменено в версии 3.8: Добавлены `'pgettext'` и `'npgettext'`.225226### Класс [`GNUTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations)227228Модуль [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) предоставляет один дополнительный класс, производный от [`NullTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations): [`GNUTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations). Этот класс переопределяет `_parse()`, чтобы обеспечить чтение файлов `.mo` в формате GNU **gettext** как в формате big-endian, так и little-endian.229230[`GNUTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations) извлекает необязательные метаданные из каталога переводов. По соглашению в GNU **gettext** метаданные включаются как перевод пустой строки. Эти метаданные представлены в стиле [**RFC 822**](https://python-all.ru/3.9/library/gettext.html) парами `key: value` и должны содержать ключ `Project-Id-Version`. Если найден ключ `Content-Type`, то свойство `charset` используется для инициализации «защищённой» переменной экземпляра `_charset`, по умолчанию равной `None`, если не найдено. Если указана кодировка charset, то все идентификаторы сообщений и строки сообщений, прочитанные из каталога, преобразуются в Unicode с использованием этой кодировки; в противном случае предполагается ASCII.231232Поскольку идентификаторы сообщений также читаются как строки Unicode, все методы `*gettext()` будут считать идентификаторы сообщений строками Unicode, а не байтовыми строками.233234Весь набор пар ключ/значение помещается в словарь и устанавливается как «защищённая» переменная экземпляра `_info`.235236Если магическое число файла `.mo` недействительно, основной номер версии неожиданный, или возникают другие проблемы при чтении файла, создание экземпляра класса [`GNUTranslations`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations) может вызвать исключение [`OSError`](https://python-all.ru/3.9/library/exceptions.html#OSError).237238#### `class gettext.GNUTranslations`239240Следующие методы переопределены из реализации базового класса:241242#### `gettext(message)`243244Ищет идентификатор *message* в каталоге и возвращает соответствующую строку сообщения в виде строки Unicode. Если в каталоге нет записи для идентификатора *message* и задан резервный источник (fallback), поиск перенаправляется в метод [`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.gettext) резервного источника. В противном случае возвращается идентификатор *message*.245246#### `ngettext(singular, plural, n)`247248Выполняет поиск формы множественного числа по идентификатору сообщения. *singular* используется как идентификатор сообщения для поиска в каталоге, а *n* используется для определения того, какую форму множественного числа использовать. Возвращаемая строка сообщения является строкой Unicode.249250Если идентификатор сообщения не найден в каталоге и указан резервный источник, запрос перенаправляется в метод [`ngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.ngettext) резервного источника. В противном случае, когда *n* равно 1, возвращается *singular*, а в остальных случаях возвращается *plural*.251252Вот пример:253254```python255n = len(os.listdir('.'))256cat = GNUTranslations(somefile)257message = cat.ngettext(258    'There is %(num)d file in this directory',259    'There are %(num)d files in this directory',260    n) % {'num': n}261```262263#### `pgettext(context, message)`264265Ищет идентификаторы *context* и *message* в каталоге и возвращает соответствующую строку сообщения в виде строки Unicode. Если в каталоге нет записи для идентификатора *message* и *context*, и задан резервный источник, поиск перенаправляется в метод [`pgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.pgettext) резервного источника. В противном случае возвращается идентификатор *message*.266267Новое в версии 3.8.268269#### `npgettext(context, singular, plural, n)`270271Выполняет поиск формы множественного числа по идентификатору сообщения. *singular* используется как идентификатор сообщения для поиска в каталоге, а *n* используется для определения того, какую форму множественного числа использовать.272273Если идентификатор сообщения для *context* не найден в каталоге и указан резервный источник, запрос перенаправляется в метод [`npgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.npgettext) резервного источника. В противном случае, когда *n* равно 1, возвращается *singular*, а во всех остальных случаях возвращается *plural*.274275Новое в версии 3.8.276277#### `lgettext(message)`278279#### `lngettext(singular, plural, n)`280281Эквивалентно [`gettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations.gettext) и [`ngettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.GNUTranslations.ngettext), но перевод возвращается в виде байтовой строки, закодированной в предпочтительной системной кодировке, если кодировка не была явно задана с помощью [`set_output_charset()`](https://python-all.ru/3.9/library/gettext.html#gettext.NullTranslations.set_output_charset).282283> **Предупреждение**284>285> Этих методов следует избегать в Python 3. См. предупреждение для функции [`lgettext()`](https://python-all.ru/3.9/library/gettext.html#gettext.lgettext).286287Устарело с версии 3.8, будет удалено в версии 3.10.288289### Поддержка каталогов сообщений Solaris290291Операционная система Solaris определяет собственный двоичный формат файлов `.mo`, но, поскольку документации по этому формату найти не удалось, он в настоящее время не поддерживается.292293### Конструктор каталога294295GNOME использует версию модуля [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) от James Henstridge, но эта версия имеет несколько другой API. Её задокументированное использование было таким:296297```python298import gettext299cat = gettext.Catalog(domain, localedir)300_ = cat.gettext301print(_('hello world'))302```303304Для совместимости с этим старым модулем функция `Catalog()` является псевдонимом функции [`translation()`](https://python-all.ru/3.9/library/gettext.html#gettext.translation), описанной выше.305306Одно различие между этим модулем и модулем Хенстриджа: его объекты каталога поддерживали доступ через API отображения (mapping API), но, по-видимому, эта возможность не используется и поэтому в настоящее время не поддерживается.307308## Интернационализация программ и модулей309310Интернационализация (I18N) – это процесс, благодаря которому программа начинает работать с несколькими языками. Локализация (L10N) – это адаптация уже интернационализированной программы к местному языку и культурным особенностям. Чтобы добавить в программу на Python поддержку нескольких языков, нужно выполнить следующие шаги:3113121. подготовить программу или модуль, специально помечая переводимые строки3132. запустить набор инструментов над размеченными файлами для создания исходных каталогов сообщений3143. создать языковые переводы каталогов сообщений3154. использовать модуль [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) для корректного перевода строк сообщений316317Чтобы подготовить код к интернационализации, нужно просмотреть все строки в своих файлах. Любую строку, которую требуется перевести, следует пометить, обернув её в вызов `_('...')` – то есть в функцию `_()`. Например:318319```python320filename = 'mylog.txt'321message = _('writing a log message')322with open(filename, 'w') as fp:323    fp.write(message)324```325326В этом примере строка `'writing a log message'` помечена как кандидат на перевод, а строки `'mylog.txt'` и `'w'` – нет.327328Существует несколько инструментов для извлечения строк, предназначенных для перевода. Исходная программа GNU **gettext** поддерживала только исходный код на C или C++, но её расширенная версия **xgettext** сканирует код на многих языках, включая Python, чтобы найти строки, помеченные как переводимые. [Babel](https://python-all.ru/3.9/library/gettext.html) – это библиотека интернационализации для Python, в состав которой входит скрипт `pybabel` для извлечения и компиляции каталогов сообщений. Программа Франсуа Пинара **xpot** делает то же самое и доступна как часть его [пакета po-utils](https://python-all.ru/3.9/library/gettext.html).329330(В Python также есть чисто питоновские версии этих программ: **pygettext.py** и **msgfmt.py**; некоторые дистрибутивы Python устанавливают их автоматически. **pygettext.py** похожа на **xgettext**, но понимает только исходный код Python и не умеет работать с другими языками вроде C или C++. **pygettext.py** поддерживает интерфейс командной строки, аналогичный **xgettext**; подробнее о его использовании – в выводе `pygettext.py --help`. **msgfmt.py** двоично совместима с GNU **msgfmt**. С этими двумя программами для интернационализации приложений на Python пакет GNU **gettext** может и не понадобиться.)331332**xgettext**, **pygettext** и похожие инструменты создают файлы `.po` – каталоги сообщений. Это структурированные, человекочитаемые файлы, содержащие каждую помеченную строку из исходного кода вместе с местом для переведённых версий этих строк.333334Копии этих файлов `.po` затем передаются переводчикам-людям, которые пишут переводы для каждого поддерживаемого естественного языка. Они возвращают готовые языковые версии в виде файла `<language-name>.po`, который компилируется в машинно-читаемый двоичный каталог `.mo` с помощью программы **msgfmt**. Файлы `.mo` используются модулем [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) для непосредственного перевода во время выполнения.335336То, как используется модуль [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) в коде, зависит от того, интернационализируется ли один модуль или всё приложение. В следующих двух разделах будет рассмотрен каждый случай.337338### Локализация модуля339340Если вы локализуете свой модуль, нужно соблюдать осторожность, чтобы не вносить глобальные изменения, например во встроенное пространство имён. Следует использовать не API GNU **gettext**, а API на основе классов.341342Допустим, модуль называется «spam», а его файлы перевода `.mo` для разных естественных языков лежат в каталоге `/usr/share/locale` в формате GNU **gettext**. Вот что нужно поместить в начало модуля:343344```python345import gettext346t = gettext.translation('spam', '/usr/share/locale')347_ = t.gettext348```349350### Локализация приложения351352Если вы локализуете приложение, можно установить функцию `_()` глобально во встроенное пространство имён, обычно в главном файле приложения. Тогда во всех файлах приложения можно будет использовать `_('...')` без явной установки в каждом из них.353354В простейшем случае нужно добавить в главный файл приложения следующий код:355356```python357import gettext358gettext.install('myapplication')359```360361Если требуется указать каталог с языковыми файлами, можно передать его в функцию [`install()`](https://python-all.ru/3.9/library/gettext.html#gettext.install):362363```python364import gettext365gettext.install('myapplication', '/usr/share/locale')366```367368### Переключение языков на лету369370Если программа должна одновременно поддерживать много языков, можно создать несколько экземпляров перевода и переключаться между ними явно:371372```python373import gettext374375lang1 = gettext.translation('myapplication', languages=['en'])376lang2 = gettext.translation('myapplication', languages=['fr'])377lang3 = gettext.translation('myapplication', languages=['de'])378379# начните с использования language1380lang1.install()381382# ... проходит время, пользователь выбирает language 2383lang2.install()384385# ... проходит ещё больше времени, пользователь выбирает language 3386lang3.install()387```388389### Отложенные переводы390391В большинстве случаев строки переводятся там же, где и пишутся. Однако иногда нужно пометить строки для перевода, но отложить собственно перевод на потом. Классический пример:392393```python394animals = ['mollusk',395           'albatross',396           'rat',397           'penguin',398           'python', ]399# ...400for a in animals:401    print(a)402```403404Здесь требуется пометить строки в списке `animals` как переводимые, но на самом деле переводить их нужно только при выводе на печать.405406Вот один из способов справиться с этим:407408```python409def _(message): return message410411animals = [_('mollusk'),412           _('albatross'),413           _('rat'),414           _('penguin'),415           _('python'), ]416417del _418419# ...420for a in animals:421    print(_(a))422```423424Это работает, потому что фиктивное определение `_()` просто возвращает строку без изменений. И это фиктивное определение временно переопределяет любое определение `_()` во встроенном пространстве имён (до команды [`del`](https://python-all.ru/3.9/reference/simple_stmts.html#del)). Однако будьте осторожны, если во вложенном пространстве имён уже есть определение `_()`.425426Обратите внимание, что второе использование `_()` не будет определено программой **gettext** как переводимое, поскольку параметр не является строковым литералом.427428Другой способ – следующий пример:429430```python431def N_(message): return message432433animals = [N_('mollusk'),434           N_('albatross'),435           N_('rat'),436           N_('penguin'),437           N_('python'), ]438439# ...440for a in animals:441    print(_(a))442```443444В этом случае переводимые строки помечаются функцией `N_()`, которая не конфликтует ни с одним определением `_()`. Однако придётся научить программу извлечения сообщений искать строки, помеченные `N_()`. **xgettext**, **pygettext**, `pybabel extract` и **xpot** – все они поддерживают это через ключ командной строки `-k`. Выбор `N_()` здесь совершенно произволен; с тем же успехом можно было использовать `MarkThisStringForTranslation()`.445446## Благодарности447448Следующие люди внесли код, отзывы, предложения по оформлению, предыдущие реализации и ценный опыт в создание этого модуля:449450- Peter Funk451- James Henstridge452- Juan David Ibáñez Palomar453- Marc-André Lemburg454- Martin von Löwis455- François Pinard456- Barry Warsaw457- Gustavo Niemeyer458459Сноски460461**[1](https://python-all.ru/3.9/library/gettext.html#id1)**462463Директория локали по умолчанию зависит от системы; например, в RedHat Linux это `/usr/share/locale`, а в Solaris – `/usr/lib/locale`. Модуль [`gettext`](https://python-all.ru/3.9/library/gettext.html#module-gettext) не пытается поддерживать эти системно-зависимые значения по умолчанию; вместо этого его значение по умолчанию – `sys.base_prefix/share/locale` (см. [`sys.base_prefix`](https://python-all.ru/3.9/library/sys.html#sys.base_prefix)). По этой причине всегда лучше вызывать [`bindtextdomain()`](https://python-all.ru/3.9/library/gettext.html#gettext.bindtextdomain) с явным абсолютным путём в начале приложения.464465**[2](https://python-all.ru/3.9/library/gettext.html#id2)**466467См. сноску для [`bindtextdomain()`](https://python-all.ru/3.9/library/gettext.html#gettext.bindtextdomain) выше.468