Django
интернационализация
Поиск…
Синтаксис
- Gettext (сообщение)
- ngettext (единственное число, число, число)
- ugettext (сообщение)
- ungettext (единственное число, множественное число, число)
- pgettext (контекст, сообщение)
- npgettext (контекст, единственное число, множественное число, число)
- gettext_lazy (сообщение)
- ngettext_lazy (единственное число, множественное число, число = нет)
- ugettext_lazy (сообщение)
- ungettext_lazy (единственное число, множественное число, число = нет)
- pgettext_lazy (контекст, сообщение)
- npgettext_lazy (контекст, единственное число, множественное число, число = нет)
- gettext_noop (сообщение)
- ugettext_noop (сообщение)
Введение в интернационализацию
Настройка
settings.py
from django.utils.translation import ugettext_lazy as _
USE_I18N = True # Enable Internationalization
LANGUAGE_CODE = 'en' # Language in which original texts are written
LANGUAGES = [ # Available languages
('en', _("English")),
('de', _("German")),
('fr', _("French")),
]
# Make sure the LocaleMiddleware is included, AFTER SessionMiddleware
# and BEFORE middlewares using internationalization (such as CommonMiddleware)
MIDDLEWARE_CLASSES = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
]
Маркировка строк как переводимых
Первым шагом в переводе является маркировка строк как переводимых . Это передается через одну из функций gettext
(см. Раздел « Синтаксис» ). Например, вот пример модели:
from django.utils.translation import ugettext_lazy as _
# It is common to import gettext as the shortcut `_` as it is often used
# several times in the same file.
class Child(models.Model):
class Meta:
verbose_name = _("child")
verbose_name_plural = _("children")
first_name = models.CharField(max_length=30, verbose_name=_("first name"))
last_name = models.CharField(max_length=30, verbose_name=_("last name"))
age = models.PositiveSmallIntegerField(verbose_name=_("age"))
Все строки, заключенные в _()
, теперь помечены как переводимые. При печати они всегда будут отображаться в виде инкапсулированной строки независимо от выбранного языка (так как перевод еще не доступен).
Перевод строк
Этот пример достаточно для начала перевода. В большинстве случаев вы хотите только отметить строки как переведенные, чтобы предвидеть предполагаемую интернационализацию вашего проекта. Таким образом, это рассматривается в другом примере .
Перевод с ленивого на нежирный
При использовании нелазного перевода строки сразу переводятся.
>>> from django.utils.translation import activate, ugettext as _
>>> month = _("June")
>>> month
'June'
>>> activate('fr')
>>> _("June")
'juin'
>>> activate('de')
>>> _("June")
'Juni'
>>> month
'June'
При использовании лень перевод происходит только при фактическом использовании.
>>> from django.utils.translation import activate, ugettext_lazy as _
>>> month = _("June")
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> str(month)
'June'
>>> activate('fr')
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> "month: {}".format(month)
'month: juin'
>>> "month: %s" % month
'month: Juni'
Вы должны использовать ленивый перевод в тех случаях, когда:
- Перевод не может быть активирован (язык не выбран), когда
_("some string")
оценивается - Некоторые строки могут оцениваться только при запуске (например, в атрибутах класса, таких как определения полей модели и формы)
Перевод в шаблоны
Чтобы включить перевод в шаблонах, вы должны загрузить библиотеку i18n
.
{% load i18n %}
Основной перевод выполняется с тегом trans
template.
{% trans "Some translatable text" %}
{# equivalent to python `ugettext("Some translatable text")` #}
Тег trans
template поддерживает контекст:
{% trans "May" context "month" %}
{# equivalent to python `pgettext("May", "month")` #}
Чтобы включить заполнители в строку перевода, как в:
_("My name is {first_name} {last_name}").format(first_name="John", last_name="Doe")
Вам нужно будет использовать blocktrans
шаблона blocktrans
:
{% blocktrans with first_name="John" last_name="Doe" %}
My name is {{ first_name }} {{ last_name }}
{% endblocktrans %}
Конечно, вместо "John"
и "Doe"
вас могут быть переменные и фильтры:
{% blocktrans with first_name=user.first_name last_name=user.last_name|title %}
My name is {{ first_name }} {{ last_name }}
{% endblocktrans %}
Если first_name
и last_name
уже находятся в вашем контексте, вы можете даже опустить предложение with
:
{% blocktrans %}My name is {{ first_name }} {{ last_name }}{% endblocktrans %}
Однако могут использоваться только контекстные переменные верхнего уровня. Это не будет работать:
{% blocktrans %}
My name is {{ user.first_name }} {{ user.last_name }}
{% endblocktrans %}
Это происходит главным образом потому, что имя переменной используется в качестве заполнителя в файлах перевода.
blocktrans
шаблона blocktrans
также blocktrans
плюрализацию.
{% blocktrans count nb=users|length }}
There is {{ nb }} user.
{% plural %}
There are {{ nb }} users.
{% endblocktrans %}
Наконец, независимо от библиотеки i18n
, вы можете передавать переводимые строки в теги шаблонов с помощью синтаксиса _("")
.
{{ site_name|default:_("It works!") }}
{% firstof var1 var2 _("translatable fallback") %}
Это некоторая волшебная встроенная система шаблонов django для имитации синтаксиса вызова функции, но это не вызов функции. _("It works!")
Передается тегу шаблона по default
в виде строки '_("It works!")'
Которая затем анализируется переводимой строкой, так же, как name
будет анализироваться как переменная, а "name"
будет анализируется как строка.
Перевод строк
Чтобы перевести строки, вам придется создавать файлы переводов. Для этого django отправляется с командой управления makemessages
.
$ django-admin makemessages -l fr
processing locale fr
Вышеупомянутая команда обнаружит все строки, помеченные как переводимые в ваши установленные приложения, и создаст один языковой файл для каждого приложения для перевода на французский язык. Например, если у вас есть только одно приложение myapp
содержащее переводимые строки, это создаст файл myapp/locale/fr/LC_MESSAGES/django.po
. Этот файл может выглядеть так:
# SOME DESCRIPTIVE TITLE
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-24 14:01+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: myapp/models.py:22
msgid "user"
msgstr ""
#: myapp/models.py:39
msgid "A user already exists with this email address."
msgstr ""
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
Сначала вы должны заполнить заполнители (подчеркнуты с помощью верхних частей). Затем переведите строки. msgid
"строка, помеченная как переводимая в вашем коде. msgstr
, где вы должны написать перевод строки прямо выше.
Когда строка содержит заполнители, вам также придется включить их в свой перевод. Например, вы переведете последнее сообщение следующим образом:
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
"En vous inscrivant, vous acceptez nos <a href=\"%(terms_url)s\" "
"target=_blank>Conditions d'utilisation</a>"
Как только ваш файл перевода будет завершен, вам придется скомпилировать файлы .po
файлы .mo
. Это делается путем вызова compilemessages
управления compilemessages
:
$ django-admin compilemessages
Вот и все, теперь переводы доступны.
Чтобы обновить ваши файлы переводов при внесении изменений в свой код, вы можете повторно запустить django-admin makemessages -l fr
. Это будет обновлять файлы .po
, сохраняя ваши существующие переводы и добавляя новые. Удаленные строки по-прежнему будут доступны в комментариях. Чтобы обновить файлы .po
для всех языков, запустите django-admin makemessages -a
. После того, как ваши файлы .po
будут обновлены, не забудьте снова запустить django-admin compilemessages
для создания файлов .mo
.
Случай использования Noop
(u)gettext_noop
позволяет пометить строку как переводимую, не переведя ее.
Типичным примером использования является то, когда вы хотите зарегистрировать сообщение для разработчиков (на английском языке), но также хотите отобразить его клиенту (на запрошенном языке). Вы можете передать переменную gettext
, но ее содержимое не будет обнаружено как переводимая строка, потому что это переменная per definition. ,
# THIS WILL NOT WORK AS EXPECTED
import logging
from django.contrib import messages
logger = logging.getLogger(__name__)
error_message = "Oops, something went wrong!"
logger.error(error_message)
messages.error(request, _(error_message))
Сообщение об ошибке не появится в файле .po
и вам нужно будет запомнить его, чтобы добавить его вручную. Чтобы исправить это, вы можете использовать gettext_noop
.
error_message = ugettext_noop("Oops, something went wrong!")
logger.error(error_message)
messages.error(request, _(error_message))
Теперь строка "Oops, something went wrong!"
будет обнаружен и доступен в файле .po
при его создании. И ошибка будет по-прежнему регистрироваться на английском языке для разработчиков.
Обычные подводные камни
нечеткие переводы
Иногда makemessages
может думать, что строка, найденная для перевода, несколько похожа на уже существующий перевод. Он будет отмечать его в файле .po
специальным fuzzy
комментарием следующим образом:
#: templates/randa/map.html:91
#, fuzzy
msgid "Country"
msgstr "Länderinfo"
Даже если перевод верен или вы обновили его, чтобы исправить его, он не будет использоваться для перевода вашего проекта, если вы не удалите строку с fuzzy
комментариями.
Многострочные строки
makemessages
анализирует файлы в различных форматах, от простого текста до кода python и не предназначен для следования всем возможным правилам для наличия многострочных строк в этих форматах. Большую часть времени он будет отлично работать с однострочными строками, но если у вас есть такая конструкция:
translation = _("firstline"
"secondline"
"thirdline")
Это займет только firstline
для перевода. Решение этого - избегать использования многострочных строк, когда это возможно.