Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Django_-_podrobnoe_rukovodstvo

.pdf
Скачиваний:
312
Добавлен:
01.03.2016
Размер:
4.88 Mб
Скачать

19

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

Фреймворк Django изначально разрабатывался буквально в центре Соединенных Штатов, ведь расстояние от города Лоуренс в штате Канзас до географического центра континентальной части США составляет меньше 55 км. Но, как и большинство проектов с открытым исходным кодом, сообщество Django разрослось и теперь включает людей со всего мира. По мере роста сообщества все большую значимость приобретают вопросы интернационализации и локализации. Поскольку многие разработчики имеют расплывчатое представление об этих терминах, дадим их краткие определения.

Интернационализация – это методика проектирования программ, рассчитанных на работу с любыми языками и культурными особенностями. Сюда относится реализация возможности перевода текста в элементах пользовательского интерфейса и сообщений об ошибках, абстрагирование отображения даты и времени, чтобы можно было адаптироваться к местным стандартам, поддержка часовых поясов и вообще такая организация кода, чтобы в нем не было никаких допущений о местонахождении пользователя. Слово интернационализация (internationalization) часто сокращают до I18N (здесь 18 – количество пропущенных букв между начальной I и конечной N).

Локализация – это процедура фактического перевода интернациональной программы на конкретный язык с учетом конкретных культурных особенностей (все вместе называется локалью). Иногда слово локализация (localization) сокращают до L10N.

Сам фреймворк Django полностью интернационализирован; для всех строк предусмотрена возможность перевода, а порядок отображения величин, зависящих от локали (например, даты и времени), контролируется параметрами настройки. В дистрибутив Django входит свыше 50 файлов локализации. Если ваш родной язык не английский, то с большой вероятностью Django уже включает соответствующий перевод.

371

Для локализации своего кода и шаблонов­ вы можете использовать эту же подсистему­ интернационализации.

Для этого необходимо расставить в коде и шаблонах­ совсем немного дополнительных элементов, которые называются переводимыми строками и сообщают Django: «Этот текст следует перевести на язык конечного пользователя, если перевод на этот язык существует».

Django будет переводить такие строки прямо в процессе выполнения, ориентируясь на языковые настройки пользователя.

При этом Django решает двойную задачу:

•• Позволяет разработчикам и авторам шаблонов­ определить, какие части приложения подлежат переводу.

•• Использует полученную информацию, чтобы перевести приложения Django на язык пользователя в соответствии с его языковыми настройками.

Примечание

Механизм перевода в Django основан на библиотеке GNU gettext (http://www. gnu.org/software/gettext/), интерфейс с которой реализован в стандартном модуле Python gettext.

Для интернационализации приложения Django следует выполнить следующие действия:

1.Вставить переводимые строки в Python-код и в шаблоны­.

2.Выполнить перевод этих строк на поддерживаемые языки.

3.Активировать дополнительный процессор локали в файле парамет­ ров.

Ниже мы подробно рассмотрим эти шаги.

Если вам не нужна интернационализация

По умолчанию поддержка интернационализации в Django включена, что приводит к небольшим накладным расходам. Если вы не собираетесь пользоваться механизмом интернационализации, то можете включить в файл параметров строку USE_I18N = False. В этом случае Django обойдет загрузку механизма интернацио-

нализации.

Возможно также желательно будет удалить строку ‘django.core. context_processors.i18n’ из параметра TEMPLATE_CONTEXT_PROCESSORS.

372

Глава 19. Интернационализация

Как определять переводимые строки

Переводимая строка означает, что «данный текст должен быть переведен». Такие строки могут встречаться как в коде, так и в шаблонах­. Пометить строки как переводимые вы должны сами; система­ может перевести лишь строки, о которых знает.

В коде на языке Python

Стандартный перевод

Определите переводимую строку с помощью функции ugettext(). По соглашению ее принято импортировать в виде короткого синонима _.

В следующем примере текст “Welcome to my site” помечен как переводимая строка:

from django.utils.translation import ugettext as _

def my_view(request):

output = _(“Welcome to my site.”) return HttpResponse(output)

Понятно, что можно было бы обойтись и без синонима:

from django.utils.translation import ugettext

def my_view(request):

output = ugettext(“Welcome to my site.”) return HttpResponse(output)

Переводиться могут также вычисляемые значения, поэтому оба примера выше эквивалентны следующему:

def my_view(request):

words = [‘Welcome’, ‘to’, ‘my’, ‘site.’] output = _(‘ ‘.join(words))

return HttpResponse(output)

Перевод применяется и к переменным. Вот еще одна эквивалентная форма:

def my_view(request):

sentence = ‘Welcome to my site.’ output = _(sentence)

return HttpResponse(output)

Предупреждение

Предусматривая перевод переменных или вычисляемых значений, имейте в виду, что входящая в дистрибутив Django утилита извлечения переводимых строк, django-admin.py makemessages, не распознает такие строки. Мы еще вернемся к этой утилите ниже.

Как определять переводимые строки

373

В строках, передаваемых _() или ugettext(), допускается использовать именованные маркеры, определяемые с помощью стандартного синтаксиса интерполяции строк. Например:

def my_view(request, m, d):

output = _(‘Today is %(month)s %(day)s.’) % {‘month’: m, ‘day’: d} return HttpResponse(output)

Этот прием позволяет изменять порядок следования маркеров при переводе. Так, английский текст “Today is November 26” по-русски выглядит так: “Сегодня 26 ноября”. Изменилось только взаимное расположение маркеров (месяца и дня).

По этой причине всегда следует пользоваться интерполяцией именованных строк (например, %(day)s), а не позиционной интерполяцией

(например, %s или %d), если количество параметров больше 1. При использовании позиционной интерполяции переводчик не сможет переставить маркеры местами.

Пометка строк без перевода

Функция django.utils.translation.ugettext_noop() помечает строку как переводимую, но не требующую перевода. Позже перевод такой строки будет взят из переменной.

Этот прием используется при наличии строк-констант, которые при передаче между системами­ или пользователями должны содержать текст на оригинальном языке, как, например, строки в базе данных, и должны переводиться лишь в самый последний момент, непосредственно перед отображением пользователю.

Отложенный перевод

Функция django.utils.translation.ugettext_lazy() позволяет переводить строки не в момент вызова самой функции, а в момент доступа к значению.

Например, чтобы перевести значение атрибута help_text модели, можно поступить следующим образом:

from django.utils.translation import ugettext_lazy

class MyThing(models.Model):

name = models.CharField(help_text=ugettext_lazy(‘This is the help text’))

В данном случае ugettext_lazy() сохранит ссылку на объект отложенного перевода1, а не на сам перевод. Перевод будет выполнен, когда строка встретится в строковом контексте, например, при отображении шаб­ лона в административном интерфейсе Django.

1Точнее, ссылку на вызываемый объект (функцию ugettext) с параметром, содержащим строку, предназначенную для перевода. – Прим. науч. ред.

374

Глава 19. Интернационализация

Результат ugettext_lazy() можно использовать всюду, где в Python допустима строка Unicode (объект типа Unicode). Попытка использовать его там, где ожидается байтовая строка (объект типа str) закончится неудачно, потому что ugettext_lazy() не знает, как преобразовать свой результат в байтовую строку. Но поскольку использовать строку Unicode внутри байтовой строки также не разрешается, то это ограничение согласуется с обычным поведением Python. Например:

#Правильно: прокси-объект unicode1 вставляется в строку unicode. u”Hello %s” % ugettext_lazy(“people”)

#Не работает, так как нельзя вставить объект unicode в байтовую

#строку (как нельзя вставить и прокси-объект unicode)

“Hello %s” % ugettext_lazy(“people”)

Если вы когда-нибудь увидите нечто вроде “hello <django.utils. functional...>”, знайте, что это результат попытки вставить в байтовую строку значение, возвращаемое ugettext_lazy(). Это ошибка в вашем коде.

Если вам не нравится длинное имя ugettext_lazy, можете воспользоваться синонимом _ (знак подчеркивания):

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):

name = models.CharField(help_text=_(‘This is the help text’))

В моделях Django всегда пользуйтесь только отложенным переводом. Имена полей и таблиц должны помечаться для перевода (иначе они останутся непереведенными в административном интерфейсе). Это означает, что в классе Meta следует определить атрибуты verbose_name и verbose_name_plural явно , а не полагаться на алгоритм их образования из имени класса модели, принятый в Django по умолчанию:

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):

name = models.CharField(_(‘name’), help_text=_(‘This is the help text’)) class Meta:

verbose_name = _(‘my thing’) verbose_name_plural = _(‘mythings’)

Образование множественного числа

Для определения текста сообщений, которые выглядят по-разному в единственном и множественном числе, служит функция django.utils. translation.ungettext(). Например:

from django.utils.translation import ungettext

1Имеется в виду вызываемый объект, возвращающий значение типа Uni­ code. – Прим. науч. ред.

Как определять переводимые строки

375

def hello_world(request, count):

page = ungettext(‘there is %(count)d object’, ‘there are %(count)d objects’, count) % {

‘count’: count,

}

return HttpResponse(page)

Функция ungettext принимает три аргумента: переводимую строку в единственном числе, переводимую строку во множественном числе

иколичество объектов (которое передается в виде переменной count)1.

Вшаблонах­

Для перевода текста в шаблонах­ Django применяются два шаблонных­ тега и синтаксис, несколько отличающийся от используемого в коде на Python. Чтобы получить доступ к этим тегам, поместите в начало файла шаблона­ директиву {% load i18n %}.

Тег {% trans %} переводит как литералы строк (заключенные в одиночные или двойные кавычки), так и содержимое переменных:

<title>{% trans “This is the title.” %}</title> <title>{% trans myvar %}</title>

Если задан параметр noop, то поиск переменной производится, но перевод пропускается. Это полезно, когда требуется поставить заглушку для содержимого, которое понадобится перевести позже:

<title>{% trans “myvar” noop %}</title>

В теге {% trans %} не допускается помещать шаблонную­ переменную внутрь строки. Если необходимо перевести строки, содержащие переменные, пользуйтесь тегом {% blocktrans %}:

{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}

Чтобы перевести результат шаблонного­ выражения (например, включающего фильтр), необходимо связать это выражение с локальной переменной перед входом в блок {% blocktrans %}:

{% blocktrans with value|filter as myvar %} This will have {{ myvar }} inside.

{% endblocktrans %}

Несколько связываемых в блоке выражений разделяются связкой and:

{% blocktrans with book|title as book_t and author|title as author_t %} This is {{ book_t }} by {{ author_t }}

1Хотя функция ungettext принимает всего две строки на оригинальном языке (в единственном числе и во множественном), тем не менее в файле перевода можно указать более двух форм склонений по числам (как это принято в русском языке) и получать корректный перевод. Эта особенность русского языка уже учтена в стандартном файле перевода Django. – Прим. науч. ред.

376

Глава 19. Интернационализация

{% endblocktrans %}

Для образования множественного числа определите обе формы (единственную и множественную) в теге {% plural %}, который должен находиться между {% blocktrans %} и {% endblocktrans %}. Например:

{% blocktrans count list|length as counter %} There is only one {{ name }} object.

{% plural %}

There are {{ counter }} {{ name }} objects. {% endblocktrans %}

В реализации перевода всех блочных и строчных фрагментов применяются функции ugettext/ungettext. Каждый объект RequestContext имеет доступ к трем переменным, касающимся перевода:

•• LANGUAGES – список кортежей, в каждом из которых первый элемент – код языка, а второй – название языка (переведенное на язык текущей активной локали).

•• LANGUAGE_CODE – код предпочтительного для пользователя языка в виде строки, например: en-us (см. следующий раздел «Как Django определяет языковые предпочтения»).

•• LANGUAGE_BIDI – направление чтения в текущей локали. True означает, что язык читается справа налево (например, иврит и арабский), а False – слева направо (английский, французский, немецкий и т. д.).

Если расширение RequestContext не используется, то получить эти значения можно с помощью следующих тегов:

{% get_current_language as LANGUAGE_CODE %} {% get_available_languages as LANGUAGES %}

{% get_current_language_bidi as LANGUAGE_BIDI %}

Эти теги требуют, чтобы была указана директива {% load i18n %}.

Подключать механизм перевода можно также внутри любого блочного тега, который принимает литералы строк. В таких случаях для определения переводимой строки можно воспользоваться синтаксисом _():

{% some_special_tag _(“Page not found”) value|yesno:_(“yes,no”) %}

В данном случае и тег, и фильтр увидят уже переведенную строку, поэтому нет нужды сообщать им о необходимости перевода.

Примечание

В этом примере механизму перевода будет передана строка “yes,no”, а не строки “yes” и “no” по отдельности. Переведенная строка должна содержать запятую, иначе код разбора фильтра не будет знать, как выделить аргументы. Например, на русский язык строку “yes,no” можно было бы перевести как “да,нет” с сохранением запятой.

Как определять переводимые строки

377

Объекты отложенного перевода

Функции ugettext_lazy() и ungettext_lazy() очень часто применяются для перевода строк в моделях и служебных функциях. При работе с такими объектами в других местах кода необходимо следить за тем, чтобы случайно не преобразовать их в строки, поскольку перевод должен быть произведен как можно позже (когда активна нужная локаль). Чтобы помочь в решении этой задачи, существуют две вспомогательные функции.

Конкатенация строк: string_concat()

Функция объединения строк из имеющейся стандартной библиотеки Python (‘’.join([...])) не годится для списков, содержащих объекты с отложенным переводом. Вместо нее можно использовать функцию django. utils.translation.string_concat(), создающую объект отложенного вызова, который объединяет свои аргументы и преобразует их в строки, только когда результат вычисляется в строковом контексте. Например:

from django.utils.translation import string_concat

# ...

name = ugettext_lazy(u’John Lennon’) instrument = ugettext_lazy(u’guitar’)

result = string_concat([name, ‘: ‘, instrument])

В данном случае объекты отложенного перевода, сохраненные в переменной result, будут преобразованы в строки, только когда result встретится внутри строки (обычно на этапе отображения шаблона)­ .

Декоратор allow_lazy()

В Django имеется множество служебных функций (особенно в пакете django.utils), которые принимают строку в первом аргументе и чтото с ней делают. Эти функции используются в шаблонных­ фильтрах, а также непосредственно в коде.

Если вы сами будете писать подобные функции, то столкнетесь со следующей проблемой: что делать, когда первый аргумент – объект отложенного перевода. Преобразовывать его в строку немедленно нежелательно, так как функция может использоваться вне представления (когда в текущем потоке выполнения установлена неправильная локаль).

В подобных случаях можно использовать декоратор django.utils. functional.allow_lazy(). Он модифицирует функцию таким образом, что если при ее вызове в первом аргументе передается объект отложенного перевода, то выполнение откладывается до того момента, когда его будет необходимо преобразовать в строку. Например:

from django.utils.functional import allow_lazy

def fancy_utility_function(s, ...):

# Какие-то операции со строкой ‘s’

378

Глава 19. Интернационализация

# ...

fancy_utility_function = allow_lazy(fancy_utility_function, unicode)

Помимо декорируемой функции, allow_lazy() принимает дополнительные аргументы (*args), определяющие, какие типы может возвращать исходная функция. Обычно достаточно включить в этот список unicode и гарантировать, что исходная функция будет возвращать только строки Unicode.

Наличие такого декоратора означает, что можно написать функцию в предположении, что на вход поступает обычная строка, а поддержку объектов с отложенным переводом добавить в самом конце.

Как создавать файлы переводов

После того как будут отмечены строки для перевода, нужно перевести их (или получить перевод от третьего лица). Ниже мы опишем, как это делается.

Ограничения на локаль

Django не поддерживает локализацию приложения для локали, на которую не был переведен сам фреймворк. В таких случаях файл перевода игнорируется. В противном случае пользователь неизбежно увидел бы мешанину переведенных строк (из вашего приложения) и английских строк (из самого Django).

Если вы хотите поддержать свое приложение для локали, еще не вошедшей в Django, то придется перевести хотя бы минимально необходимую часть ядра Django.

Файлы сообщений

Первым делом необходимо создать файл сообщений для нового языка. Это обычный текстовый файл, содержащий все переводимые строки

иих перевод на один язык. Файлы сообщений имеют расширение .po.

Всостав Django входит инструмент, django-admin.py makemessages, который автоматизирует создание и сопровождение таких файлов. Чтобы создать или обновить файл сообщений, выполните следующую команду (здесь de – код языка, для которого создается файл сообщений):

django-admin.py makemessages -l de

Код языка задается в формате локали. Например, pt_BR – бразильский диалект португальского языка, а de_AT – австрийский диалект немецкого.

Сценарий следует запускать в одном из трех мест:

Как создавать файлы переводов

379

•• Корневой каталог проекта Django.

•• Корневой каталог приложения Django.

•• Корневой каталог Django (не тот, что был извлечен из Subversion, а тот, на который указывает ссылка, включенная в $PYTHONPATH). Это относится только к случаю, когда вы переводите сам фреймворк Django.

Этот сценарий выполнит обход всего дерева каталогов проекта или приложения и извлечет строки, отмеченные для перевода. Затем он создаст (или обновит) файл сообщений в каталоге locale/LANG/LC_MESSAGES. Для примера выше файл будет называться locale/de/LC_MESSAGES/django.po.

По умолчанию django-admin.py makemessages просматривает все файлы с расширением .html. Чтобы изменить это соглашение, укажите расширения после флага –-extension или –e:

django-admin.py makemessages -l de -e txt

Если потребуется указать несколько расширений, их можно перечислить через запятую или повторив флаг -extension (или –e) несколько раз:

django-admin.py makemessages -l de -e html,txt -e xml

При создании каталогов переводов для JavaScript (см. ниже) следует использовать специальный флаг djangojs, а не -e js.

Gettext не установлен?

Если пакет gettext не установлен, то сценарий django-admin.py makemessages создаст пустые файлы.

В таком случае либо установите gettext, либо скопируйте английский файл сообщений (locale/en/LC_MESSAGES/django.po), если таковой имеется, и используйте его в качестве отправной точки. Это просто пустой файл сообщений.

Работаете в Windows?

Если вы работаете на платформе Windows и хотите установить утилиту GNU gettext, чтобы обеспечить нормальную работу сценария django-admin makemessages, то обратитесь к разделу «gettext для Windows» ниже.

Формат po-файлов достаточно прост. В каждом po-файле присутствует небольшой раздел метаданных, где указывается, например, информация о способе связи с переводчиком, а основная часть – это список сообщений. Каждое сообщение – это пара, состоящая из переводимой строки и ее перевода на выбранный язык.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]