gettext
— Multilingual internationalization services¶
Вихідний код: Lib/gettext.py
Модуль gettext
надає служби інтернаціоналізації (I18N) і локалізації (L10N) для ваших модулів і програм Python. Він підтримує як API каталогу повідомлень GNU gettext, так і API вищого рівня на основі класів, який може бути більш відповідним для файлів Python. Інтерфейс, описаний нижче, дозволяє вам писати повідомлення модуля та додатка однією природною мовою та надавати каталог перекладених повідомлень для роботи на різних природних мовах.
Також подано деякі підказки щодо локалізації ваших модулів і програм Python.
GNU gettext API¶
Модуль gettext
визначає наступний API, який дуже схожий на GNU gettext API. Якщо ви використовуєте цей API, ви вплинете на глобальний переклад усієї вашої програми. Часто це те, що вам потрібно, якщо ваша програма є одномовною, а вибір мови залежить від локалі вашого користувача. Якщо ви локалізуєте модуль Python або якщо вашій програмі потрібно миттєво перемикати мови, ви, ймовірно, захочете замість цього використовувати API на основі класів.
- gettext.bindtextdomain(domain, localedir=None)¶
Прив’яжіть домен до каталогу локалі localedir. Точніше,
gettext
шукатиме двійкові файли.mo
для вказаного домену за шляхом (в Unix):localedir/language/LC_MESSAGES/domain .mo
, де мова шукається в змінних середовищаLANGUAGE
,LC_ALL
,LC_MESSAGES
таLANG
відповідно.Якщо localedir пропущено або
None
, повертається поточне прив’язування для domain. [1]
- gettext.textdomain(domain=None)¶
Змініть або запитайте поточний глобальний домен. Якщо domain має значення
None
, тоді повертається поточний глобальний домен, інакше глобальний домен встановлюється на domain, який повертається.
- gettext.gettext(message)¶
Return the localized translation of message, based on the current global domain, language, and locale directory. This function is usually aliased as
_()
in the local namespace (see examples below).
- gettext.ngettext(singular, plural, n)¶
Як
gettext()
, але враховуйте форми множини. Якщо переклад знайдено, застосуйте формулу множини до n та поверніть отримане повідомлення (деякі мови мають більше двох форм множини). Якщо переклад не знайдено, поверніть singular, якщо n дорівнює 1; повернути множину інакше.Формула множини взята із заголовка каталогу. Це вираз C або Python, який має вільну змінну n; вираз обчислюється відповідно до індексу множини в каталозі. Перегляньте документацію GNU gettext для точного синтаксису, який буде використовуватися у файлах
.po
та формул для різних мов.
- gettext.dngettext(domain, singular, plural, n)¶
Як
ngettext()
, але шукайте повідомлення у вказаному доміні.
- gettext.pgettext(context, message)¶
- gettext.dpgettext(domain, context, message)¶
- gettext.npgettext(context, singular, plural, n)¶
- gettext.dnpgettext(domain, context, singular, plural, n)¶
Подібно до відповідних функцій без
p
у префіксі (тобтоgettext()
,dgettext()
,ngettext()
,dngettext()
), але переклад обмежено даним контекстом повідомлення.Нове в версії 3.8.
Note that GNU gettext also defines a dcgettext()
method, but
this was deemed not useful and so it is currently unimplemented.
Ось приклад типового використання цього API:
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))
API на основі класів¶
The class-based API of the gettext
module gives you more flexibility and
greater convenience than the GNU gettext API. It is the recommended
way of localizing your Python applications and modules. gettext
defines
a GNUTranslations
class which implements the parsing of GNU .mo
format
files, and has methods for returning strings. Instances of this class can also
install themselves in the built-in namespace as the function _()
.
- gettext.find(domain, localedir=None, languages=None, all=False)¶
Ця функція реалізує стандартний алгоритм пошуку файлів
.mo
. Для цього потрібно домен, ідентичний тому, що приймаєtextdomain()
. Необов’язковий localedir такий, як уbindtextdomain()
. Необов’язкові мови – це список рядків, де кожен рядок є кодом мови.Якщо localedir не вказано, використовується каталог локалі системи за замовчуванням. [2] Якщо мови не вказано, шукаються такі змінні середовища:
LANGUAGE
,LC_ALL
,LC_MESSAGES
іLANG
. Перше, що повертає непорожнє значення, використовується для змінної languages. Змінні середовища мають містити розділений двокрапкою список мов, який буде розділено на двокрапку для створення очікуваного списку рядків коду мови.find()
потім розширює та нормалізує мови, а потім перебирає їх, шукаючи існуючий файл, створений із цих компонентів:localedir/language/LC_MESSAGES/domain.mo
Перше таке ім’я файлу, яке існує, повертається
find()
. Якщо такий файл не знайдено, повертаєтьсяNone
. Якщо задано all, повертається список усіх імен файлів у порядку, у якому вони з’являються у списку мов або змінних середовища.
- gettext.translation(domain, localedir=None, languages=None, class_=None, fallback=False)¶
Return a
*Translations
instance based on the domain, localedir, and languages, which are first passed tofind()
to get a list of the associated.mo
file paths. Instances with identical.mo
file names are cached. The actual class instantiated is class_ if provided, otherwiseGNUTranslations
. The class’s constructor must take a single file object argument.Якщо знайдено декілька файлів, пізніші файли використовуються як запасні для попередніх. Щоб дозволити встановлення запасного варіанта,
copy.copy()
використовується для клонування кожного об’єкта перекладу з кешу; фактичні дані екземпляра все ще використовуються в кеші.Якщо файл
.mo
не знайдено, ця функція викликаєOSError
, якщо fallback має значення false (що є типовим), і повертає екземплярNullTranslations
, якщо fallback є правда.Змінено в версії 3.11: codeset parameter is removed.
- gettext.install(domain, localedir=None, *, names=None)¶
This installs the function
_()
in Python’s builtins namespace, based on domain and localedir which are passed to the functiontranslation()
.Для параметра names див. опис методу
install()
об’єкта перекладу.As seen below, you usually mark the strings in your application that are candidates for translation, by wrapping them in a call to the
_()
function, like this:print(_('This string will be translated.'))
For convenience, you want the
_()
function to be installed in Python’s builtins namespace, so it is easily accessible in all modules of your application.Змінено в версії 3.11: names is now a keyword-only parameter.
Клас NullTranslations
¶
Класи перекладу — це те, що фактично реалізує переклад рядків повідомлень вихідного файлу в перекладені рядки повідомлень. Базовим класом, який використовується всіма класами перекладу, є NullTranslations
; це забезпечує базовий інтерфейс, який можна використовувати для написання власних спеціалізованих класів перекладу. Ось методи NullTranslations
:
- class gettext.NullTranslations(fp=None)¶
Приймає необов’язковий file object fp, який ігнорується базовим класом. Ініціалізує «захищені» змінні екземпляра _info та _charset, які встановлюються похідними класами, а також _fallback, який встановлюється через
add_fallback()
. Потім він викликаєself._parse(fp)
, якщо fp не єNone
.- _parse(fp)¶
No-op у базовому класі, цей метод бере файловий об’єкт fp і читає дані з файлу, ініціалізуючи його каталог повідомлень. Якщо у вас є непідтримуваний формат файлу каталогу повідомлень, вам слід замінити цей метод для аналізу вашого формату.
- add_fallback(fallback)¶
Додайте резервний як резервний об’єкт для поточного об’єкта перекладу. Об’єкт перекладу має звернутися до резервного варіанту, якщо він не може надати переклад для даного повідомлення.
- gettext(message)¶
Якщо встановлено запасний варіант, перешліть
gettext()
на резервний варіант. В іншому випадку поверніть повідомлення. Перевизначено в похідних класах.
- ngettext(singular, plural, n)¶
Якщо встановлено запасний варіант, перешліть
ngettext()
до резервного варіанту. В іншому випадку поверніть singular, якщо n дорівнює 1; повернути множину інакше. Перевизначено в похідних класах.
- pgettext(context, message)¶
Якщо встановлено запасний варіант, перешліть
pgettext()
на резервний варіант. В іншому випадку поверніть перекладене повідомлення. Перевизначено в похідних класах.Нове в версії 3.8.
- npgettext(context, singular, plural, n)¶
Якщо встановлено запасний варіант, перешліть
npgettext()
резервному варіанту. В іншому випадку поверніть перекладене повідомлення. Перевизначено в похідних класах.Нове в версії 3.8.
- info()¶
Return a dictionary containing the metadata found in the message catalog file.
- charset()¶
Повернути кодування файлу каталогу повідомлень.
- install(names=None)¶
Цей метод встановлює
gettext()
у вбудований простір імен, прив’язуючи його до_
.If the names parameter is given, it must be a sequence containing the names of functions you want to install in the builtins namespace in addition to
_()
. Supported names are'gettext'
,'ngettext'
,'pgettext'
, and'npgettext'
.Note that this is only one way, albeit the most convenient way, to make the
_()
function available to your application. Because it affects the entire application globally, and specifically the built-in namespace, localized modules should never install_()
. Instead, they should use this code to make_()
available to their module:import gettext t = gettext.translation('mymodule', ...) _ = t.gettext
This puts
_()
only in the module’s global namespace and so only affects calls within this module.Змінено в версії 3.8: Додано
'pgettext'
і'npgettext'
.
Клас GNUTranslations
¶
The gettext
module provides one additional class derived from
NullTranslations
: GNUTranslations
. This class overrides
_parse()
to enable reading GNU gettext format .mo
files
in both big-endian and little-endian format.
GNUTranslations
parses optional metadata out of the translation
catalog. It is convention with GNU gettext to include metadata as
the translation for the empty string. This metadata is in RFC 822-style
key: value
pairs, and should contain the Project-Id-Version
key. If the
key Content-Type
is found, then the charset
property is used to
initialize the «protected» _charset
instance variable, defaulting to
None
if not found. If the charset encoding is specified, then all message
ids and message strings read from the catalog are converted to Unicode using
this encoding, else ASCII is assumed.
Since message ids are read as Unicode strings too, all *gettext()
methods
will assume message ids as Unicode strings, not byte strings.
The entire set of key/value pairs are placed into a dictionary and set as the
«protected» _info
instance variable.
Якщо магічне число файлу .mo
недійсне, основний номер версії неочікуваний або якщо під час читання файлу виникають інші проблеми, створення екземпляра класу GNUTranslations
може викликати OSError
.
- class gettext.GNUTranslations¶
Наступні методи перевизначені з реалізації базового класу:
- gettext(message)¶
Знайдіть ідентифікатор повідомлення в каталозі та поверніть відповідний рядок повідомлення як рядок Unicode. Якщо в каталозі немає запису для ідентифікатора message і встановлено резервний варіант, пошук пересилається до резервного методу
gettext()
. В іншому випадку повертається ідентифікатор повідомлення.
- ngettext(singular, plural, n)¶
Виконайте пошук у формі множини ідентифікатора повідомлення. singular використовується як ідентифікатор повідомлення для цілей пошуку в каталозі, тоді як n використовується, щоб визначити, яку форму множини використовувати. Повернений рядок повідомлення є рядком Unicode.
Якщо ідентифікатор повідомлення не знайдено в каталозі та вказано запасний варіант, запит пересилається до резервного методу
ngettext()
. В іншому випадку, коли n дорівнює 1, повертається однина, а множина повертається в усіх інших випадках.Ось приклад:
n = len(os.listdir('.')) cat = GNUTranslations(somefile) message = cat.ngettext( 'There is %(num)d file in this directory', 'There are %(num)d files in this directory', n) % {'num': n}
- pgettext(context, message)¶
Знайдіть контекст і ідентифікатор повідомлення в каталозі та поверніть відповідний рядок повідомлення як рядок Unicode. Якщо в каталозі немає запису для ідентифікатора повідомлення та контексту, і було встановлено резервний варіант, пошук пересилається до резервного методу
pgettext()
. В іншому випадку повертається ідентифікатор повідомлення.Нове в версії 3.8.
- npgettext(context, singular, plural, n)¶
Виконайте пошук у формі множини ідентифікатора повідомлення. singular використовується як ідентифікатор повідомлення для цілей пошуку в каталозі, тоді як n використовується, щоб визначити, яку форму множини використовувати.
Якщо ідентифікатор повідомлення для контексту не знайдено в каталозі, і вказано резервний варіант, запит пересилається на резервний метод
npgettext()
. В іншому випадку, коли n дорівнює 1, повертається однина, а множина повертається в усіх інших випадках.Нове в версії 3.8.
Підтримка каталогу повідомлень Solaris¶
Операційна система Solaris визначає власний двійковий формат файлу .mo
, але оскільки документацію щодо цього формату немає, він наразі не підтримується.
Конструктор каталогу¶
GNOME використовує версію модуля gettext
від Джеймса Хенстріджа, але ця версія має дещо інший API. Його задокументоване використання:
import gettext
cat = gettext.Catalog(domain, localedir)
_ = cat.gettext
print(_('hello world'))
For compatibility with this older module, the function Catalog()
is an
alias for the translation()
function described above.
Одна відмінність між цим модулем і модулем Хенстріджа: його об’єкти каталогу підтримували доступ через API відображення, але він, здається, не використовується, тому наразі не підтримується.
Інтернаціоналізація ваших програм і модулів¶
Інтернаціоналізація (I18N) відноситься до операції, за допомогою якої програма дізнається про декілька мов. Локалізація (L10N) означає адаптацію вашої програми після її інтернаціоналізації до місцевої мови та культурних звичок. Щоб надати багатомовні повідомлення для своїх програм на Python, потрібно виконати наступні кроки:
підготуйте свою програму або модуль, спеціально позначивши рядки для перекладу
запустіть набір інструментів над позначеними файлами, щоб створити каталоги необроблених повідомлень
створювати переклади каталогів повідомлень на певну мову
використовуйте модуль
gettext
, щоб рядки повідомлень були правильно перекладені
In order to prepare your code for I18N, you need to look at all the strings in
your files. Any string that needs to be translated should be marked by wrapping
it in _('...')
— that is, a call to the function _
. For example:
filename = 'mylog.txt'
message = _('writing a log message')
with open(filename, 'w') as fp:
fp.write(message)
У цьому прикладі рядок «writing a log message» позначено як кандидат на переклад, тоді як рядки «mylog.txt» і «w» — ні.
There are a few tools to extract the strings meant for translation.
The original GNU gettext only supported C or C++ source
code but its extended version xgettext scans code written
in a number of languages, including Python, to find strings marked as
translatable. Babel is a Python
internationalization library that includes a pybabel
script to
extract and compile message catalogs. François Pinard’s program
called xpot does a similar job and is available as part of
his po-utils package.
(Python також включає версії цих програм на чистому Python, які називаються pygettext.py і msgfmt.py; деякі дистрибутиви Python встановлять їх для вас. pygettext.py схоже до xgettext, але розуміє лише вихідний код Python і не може працювати з іншими мовами програмування, такими як C або C++. pygettext.py підтримує інтерфейс командного рядка, подібний до xgettext; для детальніше про його використання, запустіть pygettext.py --help
. msgfmt.py бінарно сумісний із GNU msgfmt. З цими двома програмами вам може не знадобитися GNU gettext пакет для інтернаціоналізації ваших програм Python.)
xgettext, pygettext та подібні інструменти створюють файли .po
, які є каталогами повідомлень. Це структуровані зрозумілі для людини файли, які містять кожен позначений рядок у вихідному коді разом із заповнювачем для перекладених версій цих рядків.
Потім копії цих файлів .po
передаються окремим перекладачам, які пишуть переклади для кожної підтримуваної природної мови. Вони надсилають назад завершені версії для певної мови у вигляді файлу <language-name> .po
, який скомпільовано в машиночитаний файл бінарного каталогу .mo
за допомогою програми msgfmt. Файли .mo
використовуються модулем gettext
для фактичної обробки перекладу під час виконання.
Те, як ви використовуєте модуль gettext
у своєму коді, залежить від того, чи інтернаціоналізуєте ви один модуль чи всю програму. У наступних двох розділах буде розглянуто кожен випадок.
Локалізація вашого модуля¶
Якщо ви локалізуєте свій модуль, ви повинні подбати про те, щоб не вносити глобальних змін, напр. до вбудованого простору імен. Вам слід використовувати не GNU gettext API, а замість нього API на основі класів.
Припустімо, що ваш модуль називається «спамом», і різні файли перекладу природної мови модуля .mo
містяться в /usr/share/locale
у форматі GNU gettext. Ось що ви б розмістили у верхній частині свого модуля:
import gettext
t = gettext.translation('spam', '/usr/share/locale')
_ = t.gettext
Локалізація вашої програми¶
If you are localizing your application, you can install the _()
function
globally into the built-in namespace, usually in the main driver file of your
application. This will let all your application-specific files just use
_('...')
without having to explicitly install it in each file.
У простому випадку вам потрібно лише додати наступний біт коду до основного файлу драйвера вашої програми:
import gettext
gettext.install('myapplication')
Якщо вам потрібно встановити каталог локалі, ви можете передати його у функцію install()
:
import gettext
gettext.install('myapplication', '/usr/share/locale')
Зміна мов на льоту¶
Якщо ваша програма повинна підтримувати багато мов одночасно, ви можете створити кілька екземплярів перекладу, а потім явно перемикатися між ними, наприклад:
import gettext
lang1 = gettext.translation('myapplication', languages=['en'])
lang2 = gettext.translation('myapplication', languages=['fr'])
lang3 = gettext.translation('myapplication', languages=['de'])
# start by using language1
lang1.install()
# ... time goes by, user selects language 2
lang2.install()
# ... more time goes by, user selects language 3
lang3.install()
Відкладені переклади¶
У більшості ситуацій кодування рядки перекладаються там, де вони закодовані. Однак інколи вам потрібно позначити рядки для перекладу, але відкласти фактичний переклад на потім. Класичний приклад:
animals = ['mollusk',
'albatross',
'rat',
'penguin',
'python', ]
# ...
for a in animals:
print(a)
Тут ви хочете позначити рядки у списку animals
як такі, що можна перекладати, але насправді ви не хочете їх перекладати, поки вони не будуть надруковані.
Ось один із способів вирішення цієї ситуації:
def _(message): return message
animals = [_('mollusk'),
_('albatross'),
_('rat'),
_('penguin'),
_('python'), ]
del _
# ...
for a in animals:
print(_(a))
This works because the dummy definition of _()
simply returns the string
unchanged. And this dummy definition will temporarily override any definition
of _()
in the built-in namespace (until the del
command). Take
care, though if you have a previous definition of _()
in the local
namespace.
Note that the second use of _()
will not identify «a» as being
translatable to the gettext program, because the parameter
is not a string literal.
Ще один спосіб вирішити це за допомогою наступного прикладу:
def N_(message): return message
animals = [N_('mollusk'),
N_('albatross'),
N_('rat'),
N_('penguin'),
N_('python'), ]
# ...
for a in animals:
print(_(a))
In this case, you are marking translatable strings with the function
N_()
, which won’t conflict with any definition of _()
.
However, you will need to teach your message extraction program to
look for translatable strings marked with N_()
. xgettext,
pygettext, pybabel extract
, and xpot all
support this through the use of the -k
command-line switch.
The choice of N_()
here is totally arbitrary; it could have just
as easily been MarkThisStringForTranslation()
.
Подяки¶
Наступні люди надали код, відгуки, пропозиції щодо дизайну, попередні реалізації та цінний досвід для створення цього модуля:
Пітер Функ
Джеймс Хенстрідж
Хуан Давид Ібаньес Паломар
Марк-Андре Лембург
Мартін фон Льовіс
Франсуа Пінар
Баррі Варшава
Густаво Німейєр
Виноски