Перевод

Предварительный просмотр

Чтобы проект Django можно было переводить, необходимо добавить минимум маркеров в код Python и в шаблоны. Эти маркеры называются строками перевода . Они говорят Django, что «этот текст должен быть переведен на язык пользователя, если есть перевод этого текста на этот язык». Вы несете ответственность за пометку переводимых строк; система может переводить только указанные ей элементы.

Затем Django предоставляет утилиты для извлечения строк для перевода в файл сообщения . Затем этот файл используется переводчиками, которые могут выполнять свою работу, записывая эквиваленты строк для перевода на свой язык. Когда эта работа будет завершена, файл должен быть скомпилирован. Этот процесс основан на инструментах GNU gettext.

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

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

Заметка

Существует также другой, но связанный параметр с именем, USE_L10N который определяет, включены ли форматы регионализации. См. Дополнительные сведения в разделе « Регионализация форматов» .

Заметка

Проверьте, включен ли перевод в вашем проекте (самый быстрый способ - проверить наличие django.middleware.locale.LocaleMiddleware in MIDDLEWARE ). Если вы еще этого не сделали, прочтите Django's Language Preference Discovery Process .

Интернационализация: в коде Python

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

Определите строку для перевода с помощью функции gettext() . По соглашению, его обычно импортируют с более коротким псевдонимом _ , чтобы избежать нажатия клавиш.

Заметка

gettext Стандартный модуль библиотеки Python устанавливается _() в глобальном пространстве имен как псевдоним gettext() . В Django мы решили не следовать этой практике по нескольким причинам:

  1. Иногда лучше использовать gettext_lazy() как метод перевода по умолчанию в определенном файле. В случае отсутствия _() в глобальном пространстве имен разработчик должен подумать о том, что больше всего подходит для функции перевода.
  2. Символ подчеркивания ( _ ) используется для представления «предыдущего результата» в интерактивной оболочке Python и при тестировании doctest . Общая установка _() мешает предыдущей. Явный импорт gettext() as _() позволяет избежать этой проблемы.

Какие функции они могут иметь в _ качестве псевдонимов?

Из-за того, как xgettext (используется makemessages ) работает, только функции, которые принимают один текстовый параметр, могут быть импортированы с псевдонимом _ :

В этом примере текст помечен как строка для перевода:"Welcome to my site."

from django.http import HttpResponse
from django.utils.translation import gettext as _

def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

Мы могли бы написать это без использования псевдонима. Этот пример идентичен предыдущему:

from django.http import HttpResponse
from django.utils.translation import gettext

def my_view(request):
    output = gettext("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 makemessages makemessages

Строки, которые вы помещаете _() или gettext() заменяете в виде стандартного Python синтаксиса интерполяции именованных параметров. Пример:

def my_view(request, m, d):
    output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
    return HttpResponse(output)

Этот метод позволяет различным переводам изменять порядок заместителей. Например, для английского текста перевод на испанский может быть с заменой месяца и дня наоборот."Today is November 26." "Hoy es 26 de noviembre."

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

Поскольку извлечение строки выполняется командой xgettext , gettext Django поддерживает только синтаксис , поддерживаемый. В частности, f-строки Python в настоящее время не поддерживаются, xgettext а строки шаблонов JavaScript требуют версии gettext от 0.21.

Комментарии для переводчиков

Если вы хотите дать переводчику подсказку о переводимой строке, вы можете добавить комментарий с префиксом ключевого слова Translators к строке перед строкой; например :

def my_view(request):
    # Translators: This message appears on the home page only
    output = gettext("Welcome to my site.")

После этого комментарий появится в файле в .po результате извлечения строк, непосредственно перед блоком переводимой строки, и большинство инструментов перевода также отображают его в своем интерфейсе.

Заметка

Для любопытных вот соответствующий фрагмент в .po получившемся файле :

#. Translators: This message appears on the home page only
# path/to/python/file.py:123
msgid "Welcome to my site."
msgstr ""

Он также работает в шаблонах. Подробнее см. Комментарии для переводчиков в шаблонах .

Маркировка строк «пустыми»

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

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

Множественное число

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

ngettext() принимает три параметра: строку для перевода в единственном числе, строку для перевода во множественном числе и количество объектов.

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

Например :

from django.http import HttpResponse
from django.utils.translation import ngettext

def hello_world(request, count):
    page = ngettext(
        'there is %(count)d object',
        'there are %(count)d objects',
    count) % {
        'count': count,
    }
    return HttpResponse(page)

В этом примере количество объектов передается языку перевода с помощью переменной count .

Обратите внимание, что множественное число сложное и работает по-разному для каждого языка. Сравнение count с 1 - не всегда правильное правило. Этот код выглядит сложным, но для некоторых языков будет давать неверные результаты:

from django.utils.translation import ngettext
from myapp.models import Report

count = Report.objects.count()
if count == 1:
    name = Report._meta.verbose_name
else:
    name = Report._meta.verbose_name_plural

text = ngettext(
    'There is %(count)d %(name)s available.',
    'There are %(count)d %(name)s available.',
    count
) % {
    'count': count,
    'name': name
}

Не пытайтесь реализовать свою собственную логику единственного / множественного числа, у вас ничего не получится. В таком случае попробуйте сделать что-нибудь вроде этого:

text = ngettext(
    'There is %(count)d %(name)s object available.',
    'There are %(count)d %(name)s objects available.',
    count
) % {
    'count': count,
    'name': Report._meta.verbose_name,
}

Заметка

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

text = ngettext(
    'There is %(count)d %(name)s available.',
    'There are %(count)d %(plural_name)s available.',
    count
) % {
    'count': Report.objects.count(),
    'name': Report._meta.verbose_name,
    'plural_name': Report._meta.verbose_name_plural
}

Вы получите ошибку при запуске :django-admin compilemessages

a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'

Контекстные маркеры

Может случиться так, что слова имеют несколько значений, например, "May" в английском языке, которые могут относиться к названию месяца или глаголу. Чтобы переводчики могли правильно переводить эти слова в разных контекстах, можно использовать функцию django.utils.translation.pgettext() или, django.utils.translation.npgettext() если строка содержит множественное число. Оба принимают контекстную строку в качестве первого параметра.

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

Например :

from django.utils.translation import pgettext

month = pgettext("month name", "May")

или :

from django.db import models
from django.utils.translation import pgettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=pgettext_lazy(
        'help text for MyThing model', 'This is the help text'))

появится в файле .po как:

msgctxt "month name"
msgid "May"
msgstr ""

Контекстные маркеры также поддерживаются тегами шаблона translate и blocktranslate .

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

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

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

Этот процесс важен, когда вызовы этих функций расположены в тех местах кода, которые выполняются при загрузке модулей.

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

Значения опций verbose_name и help_text полей и отношения моделей

Например, чтобы перевести текст справки для поля name в следующем шаблоне, сделайте следующее:

from django.db import models
from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_('This is the help text'))

Вы можете отметить имена отношений ForeignKey , ManyToManyField или OneToOneField как строки для перевода , используя свой вариант verbose_name :

class MyThing(models.Model):
    kind = models.ForeignKey(
        ThingKind,
        on_delete=models.CASCADE,
        related_name='kinds',
        verbose_name=_('kind'),
    )

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

Подробные значения имени модели

Рекомендуются , чтобы вы всегда предоставить варианты явными verbose_name и verbose_name_plural вместо падения спины к англо-ориентированной и несколько наивной определенной версии многословного имени Джанго создает на основе имени класса модели:

from django.db import models
from django.utils.translation import gettext_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 = _('my things')

Значения атрибутов short_description методов модели

Для методов модели вы можете указать переводимые описания Django и сайта администратора в атрибуте short_description :

from django.db import models
from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    kind = models.ForeignKey(
        ThingKind,
        on_delete=models.CASCADE,
        related_name='kinds',
        verbose_name=_('kind'),
    )

    def is_mouse(self):
        return self.kind.type == MOUSE_TYPE
    is_mouse.short_description = _('Is it a mouse?')

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

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

body = gettext_lazy("I \u2764 Django")  # (Unicode :heart:)
requests.post('https://example.com/send', data={'body': body})

Вы можете избежать такого рода проблем, заставив объекты gettext_lazy() преобразовывать текстовые строки перед их передачей в код, отличный от Django:

requests.post('https://example.com/send', data={'body': str(body)})

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

from django.db import models
from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_('This is the help text'))

Использование gettext_lazy() и ngettext_lazy() для разметки строк в шаблонах и служебных функциях - обычная операция. При работе с этими объектами в другом месте вашего кода вы должны позаботиться о том, чтобы никогда случайно не преобразовать их в строки, поскольку они должны быть преобразованы как можно позже (чтобы был активен правильный язык). Для этого необходимо использовать служебную функцию, описанную ниже.

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

При использовании отложенного перевода со строкой, содержащей множественное число ( n[p]gettext_lazy ), вы обычно не знаете параметр number при определении строки. Следовательно, в этом случае вы можете передать имя ключа вместо числа в качестве параметра number . Затем этот ключ number будет найден в словаре во время экстраполяции строки. Вот пример:

from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ngettext_lazy

class MyForm(forms.Form):
    error_message = ngettext_lazy("You only provided %(num)d argument",
        "You only provided %(num)d arguments", 'num')

    def clean(self):
        # ...
        if error:
            raise ValidationError(self.error_message % {'num': number})

Если строка содержит единственный безымянный заполнитель, вы можете напрямую интерполировать с помощью параметра number :

class MyForm(forms.Form):
    error_message = ngettext_lazy(
        "You provided %d argument",
        "You provided %d arguments",
    )

    def clean(self):
        # ...
        if error:
            raise ValidationError(self.error_message % number)

Строки форматирования: format_lazy()

Метод str.format() Python не работает, если строка format_string или один из параметров str.format() содержит объекты отложенного перевода. django.utils.text.format_lazy() Вместо этого вы должны использовать , который создаст отложенный объект, который позаботится о выполнении метода str.format() в тот момент, когда результат будет включен в строку. Например :

from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy
...
name = gettext_lazy('John Lennon')
instrument = gettext_lazy('guitar')
result = format_lazy('{name}: {instrument}', name=name, instrument=instrument)

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

Другое использование отложенных переводов с lazy

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

from django.utils.functional import lazy
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

mark_safe_lazy = lazy(mark_safe, str)

Тогда позже :

lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))

Районированные названия языка

get_language_info()

Функция get_language_info() предоставляет подробную информацию о языках:

>>> from django.utils.translation import activate, get_language_info
>>> activate('fr')
>>> li = get_language_info('de')
>>> print(li['name'], li['name_local'], li['name_translated'], li['bidi'])
German Deutsch Allemand False

Атрибуты name , name_local и name_translated dictionary содержат название языка на английском языке, сам язык и текущий активный язык, соответственно. Атрибут bidi действителен True только для языков с написанием справа налево.

Источник информации о языках можно найти в модуле django.conf.locale . Эта информация также доступна в коде шаблонов. Увидеть ниже.

Интернационализация: в коде шаблона

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

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

Переведенные строки не экранируются при введении в шаблон. Это позволяет включать HTML в переводы, например, для выделения, но потенциально опасные символы также будут вставлены как есть.

translate тег шаблона

Шаблонный тег переводит либо постоянную строку (заключенную в одинарные или двойные кавычки) или содержимое переменной:{% translate %}

<title>{% translate "This is the title." %}</title>
<title>{% translate myvar %}</title>

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

<title>{% translate "myvar" noop %}</title>

Внутри этот метод перевода использует gettext() .

В случае, когда myvar в тег передается переменная шаблона (см. Выше), тег сначала преобразовывает переменную в строку во время выполнения, а затем обращается к каталогам сообщений для перевода.

Невозможно смешать переменную шаблона внутри строки внутри . Если для ваших переводов требуются строки с переменными (заполнители), используйте вместо них.{% translate %} {% blocktranslate %}

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

{% translate "This is the title" as the_title %}

<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">

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

{% translate "starting point" as start %}
{% translate "end point" as end %}
{% translate "La Grande Boucle" as race %}

<h1>
  <a href="/" title="{% blocktranslate %}Back to '{{ race }}' homepage{% endblocktranslate %}">{{ race }}</a>
</h1>
<p>
{% for stage in tour_stages %}
    {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br>{% else %}, {% endif %}
{% endfor %}
</p>

{% translate %} также поддерживает контекстные маркеры с использованием context ключевого слова:

{% translate "May" context "month name" %}
Изменено в Django 3.1:

trans Тег был переименован в translate . trans Тег до сих пор поддерживается в качестве псевдонима для обратной совместимости.

blocktranslate тег шаблона

В отличие от translate тега, blocktranslate тег позволяет вам помечать сложные предложения, состоящие из литералов и переменного содержимого для перевода, используя заполнители:

{% blocktranslate %}This string will have {{ value }} inside.{% endblocktranslate %}

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

{% blocktranslate with amount=article.price %}
That will cost $ {{ amount }}.
{% endblocktranslate %}

{% blocktranslate with myvar=value|filter %}
This will have {{ myvar }} inside.
{% endblocktranslate %}

Вы можете использовать несколько выражений внутри одного blocktranslate тега:

{% blocktranslate with book_t=book|title author_t=author|title %}
This is {{ book_t }} by {{ author_t }}
{% endblocktranslate %}

Заметка

По-прежнему поддерживается предыдущий более подробный формат: {% blocktranslate with book|title as book_t and author|title as author_t %}

Другие блочные теги (например, или ) не допускаются внутри тега.{% for %} {% if %} blocktranslate

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

Этот тег также позволяет использовать множественное число. Чтобы использовать это:

  • Назначьте и привяжите именованное значение счетчика count . Это значение будет использоваться для выбора правильной формы множественного числа.
  • Укажите как единственного и множественного числа , разделив их с тегом в пределах и тегов.{% plural %} {% blocktranslate %} {% endblocktranslate %}

Пример :

{% blocktranslate count counter=list|length %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktranslate %}

Более сложный пример:

{% blocktranslate with amount=article.price count years=i.length %}
That will cost $ {{ amount }} per year.
{% plural %}
That will cost $ {{ amount }} per {{ years }} years.
{% endblocktranslate %}

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

Обратный поиск URL-адресов не может выполняться в пределах blocktranslate и должен быть получен (и сохранен) заранее:

{% url 'path.to.view' arg arg2 as the_url %}
{% blocktranslate %}
This is a URL: {{ the_url }}
{% endblocktranslate %}

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

{% blocktranslate asvar the_title %}The title is {{ title }}.{% endblocktranslate %}
<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">

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

{% blocktranslate %} также поддерживает контекстные маркеры с использованием context ключевого слова:

{% blocktranslate with name=user.username context "greeting" %}Hi {{ name }}{% endblocktranslate %}

Еще одна поддерживаемая функция - это опция. Эта опция удалит символы новой строки из начала и конца содержимого тега, заменит любые пробелы в начале и конце строки и объединит все строки в одну, используя пробел для их разделения. Это очень полезно для отступа содержимого тега, чтобы символы отступа не попадали в соответствующую запись в файле PO, что упрощает процесс перевода.{% blocktranslate %} trimmed {% blocktranslate %} {% blocktranslate %}

Например, следующий тег:{% blocktranslate %}

{% blocktranslate trimmed %}
  First sentence.
  Second paragraph.
{% endblocktranslate %}

дает как результат в файле PO, по сравнению с тем, если бы опция не использовалась."First sentence. Second paragraph." "\n First sentence.\n Second sentence.\n" trimmed

Изменено в Django 3.1:

blocktrans Тег был переименован в blocktranslate . blocktrans Тег до сих пор поддерживается в качестве псевдонима для обратной совместимости.

Буквальный текст передается в теги и фильтры

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

{% some_tag _("Page not found") value|yesno:_("yes,no") %}

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

Заметка

В этом примере инфраструктура перевода получит строку "yes,no" , а не отдельные строки "yes" и "no" . Строка для перевода должна содержать запятую, чтобы код синтаксического анализа фильтра знал, где разделять параметры. Например, немецкий переводчик может перевести строку "yes,no" как "ja,nein" (с сохранением запятой).

Комментарии для переводчиков в шаблонах

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

{% comment %}Translators: View verb{% endcomment %}
{% translate "View" %}

{% comment %}Translators: Short intro blurb{% endcomment %}
<p>{% blocktranslate %}A multiline translatable
literal.{% endblocktranslate %}</p>

или с синтаксисом однострочного комментария {##} :

{# Translators: Label of a button that triggers search #}
<button type="submit">{% translate "Go" %}</button>

{# Translators: This is a text of the base template #}
{% blocktranslate %}Ambiguous translatable block of text{% endblocktranslate %}

Заметка

Для любопытных вот соответствующие фрагменты в .po получившемся файле :

#. Translators: View verb
# path/to/template/file.html:10
msgid "View"
msgstr ""

#. Translators: Short intro blurb
# path/to/template/file.html:13
msgid ""
"A multiline translatable"
"literal."
msgstr ""

# ...

#. Translators: Label of a button that triggers search
# path/to/template/file.html:100
msgid "Go"
msgstr ""

#. Translators: This is a text of the base template
# path/to/template/file.html:103
msgid "Ambiguous translatable block of text"
msgstr ""

Смена языка в шаблонах

Если вам нужно изменить язык внутри шаблона, вы можете использовать тег шаблона language :

{% load i18n %}

{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<p>{% translate "Welcome to our page" %}</p>

{% language 'en' %}
    {% get_current_language as LANGUAGE_CODE %}
    <!-- Current language: {{ LANGUAGE_CODE }} -->
    <p>{% translate "Welcome to our page" %}</p>
{% endlanguage %}

В то время как первая фраза «Добро пожаловать на нашу страницу» использует активный язык, вторая всегда будет на английском языке.

Другие теги

Эти теги также требуют загрузки .{% load i18n %}

get_available_languages

{% get_available_languages as LANGUAGES %} возвращает список кортежей, первым элементом которых является код языка, а вторым - имя языка (переведенное на текущий активный язык).

get_current_language

{% get_current_language as LANGUAGE_CODE %} возвращает предпочтительный язык текущего пользователя в текстовой форме. Пример: en-us . См. Процесс обнаружения языковых предпочтений Django .

get_current_language_bidi

{% get_current_language_bidi as LANGUAGE_BIDI %} возвращает направление текста на текущем языке. Да True , это язык, написанный справа налево, например, иврит или арабский. Да False , это язык, который пишется слева направо, например английский, французский, немецкий и т. Д.

Контекстный процессор i18n

Если включить контекстный процессор django.template.context_processors.i18n , каждый RequestContext будет иметь доступ к LANGUAGES , LANGUAGE_CODE и , LANGUAGE_BIDI как описано выше.

get_language_info

Вы также можете получить любую информацию о доступных языках, используя встроенные теги и фильтры. Чтобы получить информацию на одном языке, используйте тег :{% get_language_info %}

{% get_language_info for LANGUAGE_CODE as lang %}
{% get_language_info for "pl" as lang %}

Затем вы можете получить доступ к этой информации:

Language code: {{ lang.code }}<br>
Name of language: {{ lang.name_local }}<br>
Name in English: {{ lang.name }}<br>
Bi-directional: {{ lang.bidi }}
Name in the active language: {{ lang.name_translated }}

get_language_info_list

Вы также можете использовать тег шаблона для получения информации из списка языков (например, активных языков, перечисленных в ). См. Раздел о представлении перенаправления set_language для примера того, как отображать переключатель языка с помощью .{% get_language_info_list %} LANGUAGES {% get_language_info_list %}

В дополнение к списку кортежей style of LANGUAGES , принимает списки языковых кодов. Если вы сделаете это на ваш взгляд:{% get_language_info_list %}

context = {'available_languages': ['en', 'es', 'fr']}
return render(request, 'mytemplate.html', context)

вы можете просмотреть эти языки в шаблоне:

{% get_language_info_list for available_languages as langs %}
{% for lang in langs %} ... {% endfor %}

Шаблонные фильтры

Также для вашего удобства есть несколько фильтров:

  • {{ LANGUAGE_CODE|language_name }} ("Немецкий")
  • {{ LANGUAGE_CODE|language_name_local }} ( "Deutsch")
  • {{ LANGUAGE_CODE|language_bidi }} (Ложь)
  • {{ LANGUAGE_CODE|language_name_translated }} («Německy», когда текущий язык - чешский)

Интернационализация: в коде JavaScript

Добавление переводов в Javascript создает несколько проблем:

  • Код JavaScript не имеет доступа к реализации gettext .
  • Код JavaScript не имеет доступа к файлам .po или .mo ; они должны быть предоставлены сервером.
  • Каталоги переводов для JavaScript должны быть максимально компактными.

Django предоставляет встроенное решение этих проблем: он отображает переводы в JavaScript, чтобы вы могли вызывать функции типов gettext в своем коде JavaScript.

Основное решение этих проблем - это JavaScriptCatalog следующее представление , которое генерирует библиотеку кода JavaScript с функциями, имитирующими интерфейс gettext , а также массив строк перевода.

Вид JavaScriptCatalog

класс JavaScriptCatalog

Представление, которое генерирует библиотеку кода JavaScript с функциями, имитирующими интерфейс gettext , а также массив строк перевода.

Атрибуты

domain

Домен перевода, содержащий строки, добавляемые к результату представления. 'djangojs' По умолчанию содержит .

packages

Список среди установленных приложений. Эти приложения должны содержать папку . Все эти каталоги, а также те, которые находятся в (которые всегда включены), объединены в один каталог. По умолчанию это означает, что все доступные переводы всех приложений присутствуют в выводе JavaScript.noms d'applications locale LOCALE_PATHS None INSTALLED_APPS

Пример со значениями по умолчанию  :

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]

Пример с персонализированными пакетами  :

urlpatterns = [
    path('jsi18n/myapp/',
         JavaScriptCatalog.as_view(packages=['your.app.label']),
         name='javascript-catalog'),
]

Если ваша конфигурация корневого URL-адреса использует i18n_patterns() , он JavaScriptCatalog также должен быть заключен в оболочку i18n_patterns() для правильного создания каталога.

Пример с i18n_patterns() :

from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
)

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

Если вы используете более одного представления JavaScriptCatalog на сайте и более одного определяют одни и те же строки, цепочки в каталоге, загруженном последними, имеют приоритет.

Использование каталога переводов JavaScript

Чтобы использовать каталог, вставьте динамически сгенерированный скрипт следующим образом:

<script src="{% url 'javascript-catalog' %}"></script>

Мы используем обратное разрешение URL-адресов, чтобы найти URL-адрес представления каталога JavaScript. Когда каталог загружен, ваш код JavaScript может использовать следующие методы:

  • gettext
  • ngettext
  • interpolate
  • get_format
  • gettext_noop
  • pgettext
  • npgettext
  • pluralidx

gettext

Функция gettext работает аналогично gettext стандартному интерфейсу, доступному из кода Python:

document.write(gettext('this is to be translated'));

ngettext

Функция ngettext предоставляет интерфейс для множественного числа слов и фраз:

const objectCount = 1 // or 0, or 2, or 3, ...
const string = ngettext(
    'literal for the singular case',
    'literal for the plural case',
    objectCount
);

interpolate

Функция interpolate позволяет динамически заполнять строку форматирования. Синтаксис интерполяции заимствован из Python; таким образом, функция interpolate поддерживает как именованные параметры, так и позиционные параметры:

  • Позиционная интерполяция: obj содержит объект массива JavaScript, значения элементов которого интерполируются в порядке появления fmt соответствующих заполнителей . Например :

    const formats = ngettext(
      'There is %s object. Remaining: %s',
      'There are %s objects. Remaining: %s',
      11
    );
    const string = interpolate(formats, [11, 20]);
    // string is 'There are 11 objects. Remaining: 20'
    
  • Именованная интерполяция: этот режим выбирается путем передачи true необязательного логического параметра named . obj содержит объект JavaScript или ассоциативный массив. Например :

    const data = {
      count: 10,
      total: 50
    };
    
    const formats = ngettext(
        'Total: %(total)s, there is %(count)s object',
        'there are %(count)s of a total of %(total)s objects',
        data.count
    );
    const string = interpolate(formats, data, true);
    

Однако не следует злоупотреблять интерполяцией строк: это все еще JavaScript, поэтому код выполняет повторяющиеся подстановки для каждого регулярного выражения. Это не так быстро, как интерполяция строк в Python, поэтому нужно зарезервировать это использование для случаев, когда это действительно необходимо (например, в сочетании с `` ngettext '' для генерации правильного множественного числа) ,

get_format

Функция get_format получает доступ к параметрам регионального форматирования и может получить строку формата с заданным именем параметра:

document.write(get_format('DATE_FORMAT'));
// 'N j, Y'

Он может получить доступ к следующим настройкам:

Это очень полезно для поддержания согласованности форматирования по отношению к значениям, создаваемым кодом Python.

gettext_noop

Это эмулирует функцию gettext , но не делает ничего, кроме возврата переданного ей содержимого:

document.write(gettext_noop('this will not be translated'));

Это полезно для определения частей кода, которые нужно будет перевести позже.

pgettext

Функция pgettext работает аналогично своему эквиваленту Python ( pgettext() ), предоставляя переведенный контент в зависимости от контекста:

document.write(pgettext('month name', 'May'));

npgettext

Функция npgettext также работает как ее эквивалент Python ( npgettext() ), предоставляя множественный контент, переведенный в зависимости от контекста.

document.write(npgettext('group', 'party', 1));
// party
document.write(npgettext('group', 'party', 2));
// parties

pluralidx

Эта функция pluralidx работает аналогично шаблонному фильтру pluralize , определяя, count должно ли данное число использовать слово множественное число или нет:

document.write(pluralidx(0));
// true
document.write(pluralidx(1));
// false
document.write(pluralidx(2));
// true

В простейшем случае, если множественное число не требуется, эта функция возвращает значение false для числа 1 и true для всех остальных чисел.

Однако множественное число не во всех языках так просто. Если язык не поддерживает множественное число, возвращается пустое значение.

Кроме того, если множественное число основано на сложных правилах, представление каталога создает условное выражение. Его результатом является либо значением true (множественное число необходимо) или значение false (множественное число не требуется).

Вид JSONCatalog

класс JSONCatalog

Чтобы иметь возможность использовать другую клиентскую библиотеку для управления переводами, может быть полезно воспользоваться преимуществом представления JSONCatalog . Результат близок к результату, JavaScriptCatalog но содержимое возвращается в виде ответа JSON.

Обратитесь к документации, JavaScriptCatalog чтобы узнать о возможных значениях и использовании атрибутов domain и packages .

Формат ответа следующий:

{
    "catalog": {
        # Translations catalog
    },
    "formats": {
        # Language formats for date, time, etc.
    },
    "plural": "..."  # Expression for plural forms, or null.
}

Примечание по производительности

Различные представления i18n JavaScript / JSON создают свой каталог из файлов .mo для каждого запроса. Поскольку результат постоянен, по крайней мере, для данной версии сайта, это хорошая возможность использовать кеш.

Кэш на стороне сервера снижает нагрузку на процессор. Декоратор cache_page() позволяет легко это сделать. Чтобы сделать кеш недействительным при изменении переводов, добавьте префикс ключа, зависящий от версии, как показано в примере ниже, или сопоставьте представление с URL-адресом, зависящим от версии:

from django.views.decorators.cache import cache_page
from django.views.i18n import JavaScriptCatalog

# The value returned by get_version() must change when translations change.
urlpatterns = [
    path('jsi18n/',
         cache_page(86400, key_prefix='js18n-%s' % get_version())(JavaScriptCatalog.as_view()),
         name='javascript-catalog'),
]

Кэширование на стороне клиента экономит пропускную способность и ускоряет загрузку вашего сайта. Если вы используете ETags ( ConditionalGetMiddleware ), вы больше ничего не можете сделать. В противном случае вы можете применить условные декораторы . В следующем примере кеш становится недействительным каждый раз при перезапуске сервера приложений:

from django.utils import timezone
from django.views.decorators.http import last_modified
from django.views.i18n import JavaScriptCatalog

last_modified_date = timezone.now()

urlpatterns = [
    path('jsi18n/',
         last_modified(lambda req, **kw: last_modified_date)(JavaScriptCatalog.as_view()),
         name='javascript-catalog'),
]

Можно даже предварительно сгенерировать каталог JavaScript как часть процесса развертывания и использовать его как статический файл. Этот радикальный прием реализован в django-statici18n .

Интернационализация: в шаблонах url

Django предоставляет два механизма для интернационализации шаблонов URL:

  • Путем добавления языкового префикса в корень шаблонов URL-адресов, чтобы LocaleMiddleware можно было определить язык для активации по запрошенному URL-адресу.
  • Сделав сами шаблоны URL-адресов переводимыми с помощью функции django.utils.translation.gettext_lazy() .

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

Использование каждого из этих методов требует определения активного языка для каждого запроса; другими словами, ваша настройка MIDDLEWARE должна содержать django.middleware.locale.LocaleMiddleware .

Префикс языка в шаблонах URL

i18n_patterns( * URL-адреса , prefix_default_language = True )

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

Установив prefix_default_language на False префикс для языка по умолчанию ( LANGUAGE_CODE ) удаляется. Это может быть полезно при добавлении переводов на существующий сайт, чтобы текущие URL-адреса не менялись.

Примеры шаблонов URL:

from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path

from about import views as about_views
from news import views as news_views
from sitemap.views import sitemap

urlpatterns = [
    path('sitemap.xml', sitemap, name='sitemap-xml'),
]

news_patterns = ([
    path('', news_views.index, name='index'),
    path('category/<slug:slug>/', news_views.category, name='category'),
    path('<slug:slug>/', news_views.details, name='detail'),
], 'news')

urlpatterns += i18n_patterns(
    path('about/', about_views.main, name='about'),
    path('news/', include(news_patterns, namespace='news')),
)

После определения этих шаблонов URL-адресов Django автоматически добавляет языковой префикс в шаблоны URL-адресов, которые были добавлены с функцией i18n_patterns . Пример:

>>> from django.urls import reverse
>>> from django.utils.translation import activate

>>> activate('en')
>>> reverse('sitemap-xml')
'/sitemap.xml'
>>> reverse('news:index')
'/en/news/'

>>> activate('nl')
>>> reverse('news:detail', kwargs={'slug': 'news-slug'})
'/nl/news/news-slug/'

С помощью prefix_default_language=False и LANGUAGE_CODE='en' URL-адреса будут:

>>> activate('en')
>>> reverse('news:index')
'/news/'

>>> activate('nl')
>>> reverse('news:index')
'/nl/news/'

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

i18n_patterns() может появляться только в конфигурации корневого URL. Если вы попытаетесь использовать его во включенной конфигурации URL, вы получите исключение ImproperlyConfigured .

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

Убедитесь, что у вас нет шаблонов URL без префиксов, которые могут быть ошибочно приняты за шаблоны, содержащие автоматический префикс языка.

Перевод шаблона URL

Шаблоны URL-адресов также можно пометить как переводимые с помощью функции gettext_lazy() . Пример:

from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path
from django.utils.translation import gettext_lazy as _

from about import views as about_views
from news import views as news_views
from sitemaps.views import sitemap

urlpatterns = [
    path('sitemap.xml', sitemap, name='sitemap-xml'),
]

news_patterns = ([
    path('', news_views.index, name='index'),
    path(_('category/<slug:slug>/'), news_views.category, name='category'),
    path('<slug:slug>/', news_views.details, name='detail'),
], 'news')

urlpatterns += i18n_patterns(
    path(_('about/'), about_views.main, name='about'),
    path(_('news/'), include(news_patterns, namespace='news')),
)

После выполнения переводов функция reverse() вернет URL-адрес на активном языке. Пример:

>>> from django.urls import reverse
>>> from django.utils.translation import activate

>>> activate('en')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/en/news/category/recent/'

>>> activate('nl')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/nl/nieuws/categorie/recent/'

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

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

Обратное разрешение в шаблонах

При разрешении региональных URL-адресов в шаблонах всегда будет использоваться активный язык. Чтобы создать ссылку на URL-адрес на другом языке, используйте тег шаблона language . Он активирует язык, указанный в соответствующем разделе шаблона:

{% load i18n %}

{% get_available_languages as languages %}

{% translate "View this category in:" %}
{% for lang_code, lang_name in languages %}
    {% language lang_code %}
    <a href="{% url 'category' slug=category.slug %}">{{ lang_name }}</a>
    {% endlanguage %}
{% endfor %}

Тег language принимает в качестве параметра только код языка.

Регионализация: как создавать языковые файлы

После того, как вы отметили строки для перевода в коде приложения, пора выполнить перевод самостоятельно. Вот как это работает.

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

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

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

Утилиты Gettext

Команды makemessages (как compilemessages показано ниже) использует команду из набора инструментов GNU Gettext: xgettext , msgfmt , msgmerge и msguniq .

Минимальная поддерживаемая gettext версия утилиты - 0.15.

Чтобы создать или обновить файл сообщения, выполните эту команду:

django-admin makemessages -l de

… Где de находится локальное имя файла сообщения, который вы хотите создать. Например, бразильский португальский представлен pt_BR австрийским немецким de_AT или даже id индонезийским.

Скрипт должен запускаться из одного из следующих двух мест:

  • Корневой каталог вашего проекта Django (тот, в котором он находится manage.py ).
  • Корневой каталог одного из ваших приложений Django.

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

При запуске makemessages из корневой папки проекта извлеченные строки автоматически распространяются в соответствующие файлы сообщений. То есть строка, извлеченная из файла приложения, содержащего каталог, locale будет помещена в файл сообщения в этом каталоге. Строка, извлеченная из файла приложения без каталога, locale будет помещена в файл сообщения в каталог, указанный первой, LOCALE_PATHS или вызовет ошибку, если параметр LOCALE_PATHS пуст.

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

django-admin makemessages -l de -e txt

Разделите несколько расширений запятыми или используйте несколько вхождений -e или --extension :

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

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

При создании файлов сообщений из кода JavaScript вы должны использовать конкретный домен djangojs , а не .-e js

Использование шаблонов Jinja2

makemessages не понимает синтаксис шаблонов Jinja2. Чтобы извлечь строки из проекта, содержащего шаблоны Jinja2, рассмотрите возможность использования " извлечения сообщений " Babel .

Вот пример файла конфигурации babel.cfg :

# Extraction from Python source files
[python: **.py]

# Extraction from Jinja2 templates
[jinja2: **.jinja]
extensions = jinja2.ext.with_

Обязательно укажите все расширения, которые вы используете! В противном случае Babel не распознает теги, определенные этими расширениями, и полностью проигнорирует шаблоны Jinja2, содержащие такие теги.

Вавилонская программа предоставляет аналогичные функции makemessages и может заменить ее. Это не зависит от gettext . Для получения дополнительной информации прочтите его документацию об обработке каталогов сообщений .

Нет текста?

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

Вы используете Windows?

Если вы являетесь пользователем Windows и вам необходимо установить утилиты GNU gettext для работы makemessages , см. Gettext и Windows для получения дополнительной информации.

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

Например, если ваше приложение Django содержит строку перевода для текста , например:"Welcome to my site."

_("Welcome to my site.")

... затем создаст файл, содержащий следующий отрывок (сообщение):django-admin makemessages .po

#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""

Краткое объяснение:

  • msgid строка для перевода, появляющаяся в источнике. Не трогай это.
  • msgstr это место для получения перевода на целевой язык. Вначале он пуст, поэтому вы обязаны добавить к нему переведенный контент. Старайтесь не удалять кавычки вокруг перевода.
  • Каждое сообщение содержит полезную информацию в виде строки комментария с префиксом # и расположенной над ней msgid ; этот комментарий содержит имя файла и номер строки, соответствующий файлу, из которого была извлечена эта строка для перевода.

Длинные сообщения - это особые случаи. Первое выражение сразу после msgstr (или msgid ) - это пустая строка. Само содержимое записывается в следующих строках на нескольких строках, которые будут объединены при получении перевода. Так что не забывайте пробелы в конце строки внутри текста, иначе строки будут помещены в конец без пробелов!

Обратите внимание на кодировку символов

Из-за внутренней работы инструментов gettext и желания ядра Django принимать символы вне ASCII, заданного в исходных строках, вы должны использовать UTF-8 в качестве кодировки для ваших PO-файлов (по умолчанию, когда файлы ПО созданы). Это означает, что все используют одинаковую кодировку символов, что важно для Django при обработке файлов PO.

«Нечеткие» линии

makemessages Иногда генерирует элементы перевода, помеченные как «нечеткие» (приблизительные), например, когда перевод частично взят из других ранее переведенных строк. По умолчанию эти приблизительные строки не включаются в результат compilemessages .

Чтобы повторно проверить весь исходный код и шаблоны на предмет новых строк для перевода и обновить все файлы сообщений для всех языков, выполните следующее:

django-admin makemessages -a

Компиляция файлов сообщений

После создания файла сообщений и каждого изменения этого файла его необходимо компилировать в более эффективный формат, который может использоваться gettext . Это делается с помощью команды .django-admin compilemessages

Этот инструмент просматривает все .po доступные файлы и создает файлы, для .mo которых оптимизированы двоичные файлы gettext . В том же каталоге, из которого вы запустили , выполните следующее:django-admin makemessages django-admin compilemessages

django-admin compilemessages

Вот и все. Ваши переводы готовы к использованию.

Вы используете Windows?

Если вы являетесь пользователем Windows и вам необходимо установить утилиты GNU gettext для работы , см. Gettext и Windows для получения дополнительной информации.django-admin compilemessages

.Po файлы: кодировка и наличие спецификации

Django обрабатывает файлы только .po в кодировке UTF-8 и без BOM (Byte Order Mark); если ваш текстовый редактор по умолчанию добавляет такие метки в начало файлов, вам нужно будет перенастроить его.

Устранение неполадок: gettext() обнаружено python-format ошибочно в строках, содержащих символы процентов

В некоторых случаях, например в строках с символом процента, за которым следует пробел и маркером преобразования строки (например ), строка ложно помечается значком ._("10% interest") gettext() python-format

Если вы попытаетесь скомпилировать файлы сообщений с ошибочно помеченными строками, вы получите сообщение об ошибке, например или .le nombre de spécifications de format dans 'msgid' et 'msgstr' ne correspondent pas 'msgstr' n'est pas une chaîne de format Python valide, au contraire de 'msgid'

Чтобы обойти эту проблему, вы можете избежать символов процента, добавив второй знак процента:

from django.utils.translation import gettext as _
output = _("10%% interest")

Или также можно добавить маркер, no-python-format чтобы все символы процентов считались буквальным содержанием:

# xgettext:no-python-format
output = _("10% interest")

Создание файлов сообщений из кода JavaScript

Создание и обновление файлов сообщений выполняется так же, как и другие файлы сообщений Django, с использованием этого инструмента . Единственное отличие состоит в том, что вы должны явно определить, что на жаргоне называется доменом, в данном случае доменом , указав такой параметр :django-admin makemessages gettext djangojs -d djangojs

django-admin makemessages -d djangojs -l de

Это создаст или обновит файл сообщений JavaScript на немецком языке. После обновления файлов сообщений выполните тот же принцип, что и для других файлов сообщений Django.django-admin compilemessages

gettext и Windows

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

Также возможно использовать двоичные файлы, gettext полученные из другого источника, если команда работает правильно. Не пытайтесь использовать утилиты перевода Django с пакетом, если команда, введенная в командной строке Windows, выдает окно с сообщением типа «xgettext.exe вызвал ошибку и будет закрыт Windows».xgettext --version gettext xgettext --version

Настройка команды makemessages

Если вы хотите передать дополнительные параметры xgettext , вам необходимо создать makemessages собственную команду и переопределить ее атрибут xgettext_options :

from django.core.management.commands import makemessages

class Command(makemessages.Command):
    xgettext_options = makemessages.Command.xgettext_options + ['--keyword=mytrans']

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

from django.core.management.commands import makemessages

class Command(makemessages.Command):

    def add_arguments(self, parser):
        super().add_arguments(parser)
        parser.add_argument(
            '--extra-keyword',
            dest='xgettext_keywords',
            action='append',
        )

    def handle(self, *args, **options):
        xgettext_keywords = options.pop('xgettext_keywords')
        if xgettext_keywords:
            self.xgettext_options = (
                makemessages.Command.xgettext_options[:] +
                ['--keyword=%s' % kwd for kwd in xgettext_keywords]
            )
        super().handle(*args, **options)

Разное

Вид перенаправления set_language

set_language( запрос )

Для удобства Django предоставляет представление django.views.i18n.set_language() ,, которое устанавливает языковые предпочтения пользователя и перенаправляет его на заданный URL-адрес или, по умолчанию, возвращает на предыдущую страницу.

Активируйте представление, добавив следующую строку в свою конфигурацию URL:

path('i18n/', include('django.conf.urls.i18n')),

(Обратите внимание, что в этом примере представление доступно для /i18n/setlang/ .)

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

Убедитесь, что указанный выше URL-адрес не добавлен i18n_patterns() , поскольку для правильной работы он должен быть независимым от языка.

Представление ожидает вызова методом POST с параметром, language определенным в запросе. Если поддержка сеанса активна, представление сохраняет выбор языка в сеансе пользователя. Он также сохраняет выбор языка в файле cookie с именем по умолчанию django_language (имя может быть изменено настройкой LANGUAGE_COOKIE_NAME ).

После установки выбора языка Django ищет параметр next в данных POST или GET . Если он есть, и Django считает его безопасным URL-адресом (т.е. он не указывает на другой хост и использует безопасный протокол), он перенаправляет запрос на этот URL-адрес. , В противном случае Django вернется к перенаправлению на URL-адрес заголовка Referer или, если он отсутствует, в / зависимости от характера запроса:

  • Если запрос принимает HTML-контент (на основе его Accept HTTP-заголовка), откат всегда будет выполняться.
  • Если запрос не принимает HTML, откат будет выполнен только в том случае, если next параметр был установлен. В противном случае будет возвращен код состояния 204 (без содержимого).
Изменено в Django 3.1:

В более старых версиях различие для отката зависит от того, установлено ли в X-Requested-With заголовке значение XMLHttpRequest . Это устанавливается методом jQuery ajax() .

Вот пример кода HTML-шаблона:

{% load i18n %}

<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
    <input name="next" type="hidden" value="{{ redirect_to }}">
    <select name="language">
        {% get_current_language as LANGUAGE_CODE %}
        {% get_available_languages as LANGUAGES %}
        {% get_language_info_list for LANGUAGES as languages %}
        {% for language in languages %}
            <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
                {{ language.name_local }} ({{ language.code }})
            </option>
        {% endfor %}
    </select>
    <input type="submit" value="Go">
</form>

В этом примере Django ищет URL-адрес страницы, на которую будет перенаправлен пользователь, в переменной контекста redirect_to .

Явное определение активного языка

Может быть желательно явно определить активный язык текущего сеанса. Например, можно представить, что языковые предпочтения пользователя получены из другой системы. Функция django.utils.translation.activate() уже представлена ​​вам. Это применимо только к текущему потоку. Если вы хотите изменить язык на более длительный срок для всего сеанса в файле cookie, вы должны определить cookie LANGUAGE_COOKIE_NAME в ответе:

from django.conf import settings
from django.http import HttpResponse
from django.utils import translation
user_language = 'fr'
translation.activate(user_language)
response = HttpResponse(...)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)

Как правило, полезно использовать оба: django.utils.translation.activate() изменить язык для текущего потока и установить cookie, чтобы подтвердить это предпочтение для последующих запросов.

Изменено в Django 3.0:

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

Переводы вне представлений и шаблонов

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

Например :

from django.utils import translation

def welcome_translated(language):
    cur_language = translation.get_language()
    try:
        translation.activate(language)
        text = translation.gettext('welcome')
    finally:
        translation.activate(cur_language)
    return text

Вызов этой функции со значением 'de' будет производить "Willkommen" независимо от значения LANGUAGE_CODE или языка, установленного промежуточным программным обеспечением.

Интересны некоторые особенности, django.utils.translation.get_language() которые возвращают язык, используемый в текущем потоке, django.utils.translation.activate() активируют каталог переводов для текущего потока и django.utils.translation.check_for_language() проверяют, поддерживается ли указанный язык Django.

Чтобы помочь написать более краткий код, существует также диспетчер контекста, django.utils.translation.override() который сохраняет текущий язык как ввод и восстанавливает его как вывод. При этом приведенный выше пример становится:

from django.utils import translation

def welcome_translated(language):
    with translation.override(language):
        return translation.gettext('welcome')

Замечания по реализации

Специальности переводов Django

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

  • Текст домена - django или djangojs . Этот текст используется для различения различных программ, которые хранят свои данные в месте, общем для файлов сообщений (обычно /usr/share/locale/ ). Домен django используется для строк перевода для кода и шаблонов Python и загружается в глобальные каталоги переводов. Домен djangojs используется только для каталогов перевода JavaScript, чтобы они были как можно меньше.
  • Django напрямую не использует xgettext , но адаптеры Python вокруг xgettext и msgfmt . Это в основном из практических соображений.

Процесс обнаружения языковых предпочтений Django

После того, как вы подготовили переводы, или если вы хотите использовать переводы, поступающие из Django, включите переводы для своего приложения.

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

Чтобы настроить общие языковые настройки проекта, установите LANGUAGE_CODE . Django использует этот язык в качестве перевода по умолчанию, что является окончательным выбором, если ни один из методов, используемых промежуточным программным обеспечением языка, не обнаруживает другого подходящего перевода (см. Ниже).

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

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

Чтобы использовать LocaleMiddleware , добавьте 'django.middleware.locale.LocaleMiddleware' в свою настройку MIDDLEWARE . Поскольку промежуточное программное обеспечение чувствительно к порядку, в котором оно происходит, следуйте этим рекомендациям:

  • Убедитесь, что это одно из первых установленных промежуточных программ.
  • Он должен появиться после SessionMiddleware , потому что LocaleMiddleware использует данные сеанса. И он должен появиться раньше CommonMiddleware , потому CommonMiddleware что для разрешения запрошенного URL-адреса требуется активный язык.
  • Если вы используете CacheMiddleware , поместите его раньше LocaleMiddleware .

Например, так могут выглядеть ваши настройки MIDDLEWARE :

MIDDLEWARE = [
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.locale.LocaleMiddleware',
   'django.middleware.common.CommonMiddleware',
]

(Для получения дополнительной информации о промежуточном программном обеспечении см. Документацию по промежуточному программному обеспечению .)

LocaleMiddleware пытается определить языковые предпочтения пользователя, следуя этому алгоритму:

  • Во-первых, он ищет языковой префикс в запрошенном URL. Это действительно только тогда, когда вы используете функцию i18n_patterns в своей конфигурации корневого URL. См. Раздел Интернационализация: в шаблонах URL для получения дополнительной информации о языковых префиксах и способах интернационализации шаблонов URL.

  • Если ничего не находит, ищет файл cookie.

    Имя этого файла cookie определяется настройкой LANGUAGE_COOKIE_NAME (по умолчанию django_language ).

  • Если ничего не находит, проверяет заголовок HTTP Accept-Language . Этот заголовок отправляется браузером и сообщает серверу предпочтительные языки пользователя, отсортированные в порядке предпочтения. Django рассматривает каждый язык в этом заголовке, пока не найдет язык с доступными переводами.

  • Если ничего не находит, используется глобальная настройка LANGUAGE_CODE .

Ноты:

  • В каждом из этих мест предполагается, что языковые предпочтения представлены в стандартном языковом формате в текстовой форме. Например, бразильский португальский представлен как pt-br .

  • Если базовый язык доступен, но указанный вариант отсутствует, Django использует базовый язык. Например, если пользователь говорит fr-be (французский из Бельгии), но Django знает только это fr , он будет использовать fr .

  • LANGUAGES Можно выбрать только те языки, которые присутствуют в настройке . Если вы хотите ограничить возможный выбор языков подмножеством доступных языков (поскольку ваше приложение не поддерживает все эти языки), установите LANGUAGES список языков. Например :

    LANGUAGES = [
      ('de', _('German')),
      ('en', _('English')),
    ]
    

    В этом примере языки, доступные во время автоматического выбора, ограничиваются немецким и английским (и любыми вариантами, например de-ch или en-us ).

  • Если вы определяете LANGUAGES пользовательский параметр, как описано в пункте выше, можно пометить имена языков как строки для перевода, но затем использовать gettext_lazy() вместо них, gettext() чтобы избежать циклического импорта.

    Вот пример файла настроек:

    from django.utils.translation import gettext_lazy as _
    
    LANGUAGES = [
        ('de', _('German')),
        ('en', _('English')),
    ]
    

После LocaleMiddleware определения языковых предпочтений пользователя они становятся доступными для request.LANGUAGE_CODE каждой переменной HttpRequest . Это значение доступно вам в коде ваших представлений. Вот пример:

from django.http import HttpResponse

def hello_world(request, count):
    if request.LANGUAGE_CODE == 'de-at':
        return HttpResponse("You prefer to read Austrian German.")
    else:
        return HttpResponse("You prefer to read another language.")

Обратите внимание, что при статическом переводе (без промежуточного программного обеспечения) язык используется, settings.LANGUAGE_CODE а при динамическом переводе (с промежуточным программным обеспечением) он находится request.LANGUAGE_CODE .

Процесс обнаружения переводов Django

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

  1. Каталоги, перечисленные в, LOCALE_PATHS имеют наивысший приоритет, а те, которые появляются первыми, имеют приоритет над следующими.
  2. Затем он ищет и использует каталог locale в каждом из установленных приложений, перечисленных в INSTALLED_APPS . Те, которые появляются первыми, имеют приоритет перед следующими.
  3. И, наконец, в django/conf/locale крайнем случае используется базовый перевод, предоставляемый Django .

Смотрите также

Строковые переводы, содержащиеся в файлах JavaScript, проверяются аналогичным, но не идентичным алгоритмом. Подробнее JavaScriptCatalog см.

Вы также можете размещать файлы пользовательских форматов в каталогах, LOCALE_PATHS если вы это тоже установите FORMAT_MODULE_PATH .

Во всех случаях имя каталога, содержащего перевод, должно соответствовать формату именования с обозначением имени локали . Например. : de , pt_BR , es_AR , И т.д. Непереведенные строки для территориальных вариантов языков используют переводы общего языка. Например, для pt_BR непереведенных строк используются переводы pt .

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

Все репозитории файлов сообщений имеют одинаковую структуру. То есть:

  • Django ищет все пути, указанные в LOCALE_PATHS вашем файле настроек, в поисках<code_de_langue>/LC_MESSAGES/django.(po|mo)
  • $CHEMIN_APP/locale/<code_de_langue>/LC_MESSAGES/django.(po|mo)
  • $PYTHONPATH/django/conf/locale/<code_de_langue>/LC_MESSAGES/django.(po|mo)

Чтобы создать файлы сообщений, вы должны использовать инструмент . А для создания бинарных файлов, используемых вами, вы должны использовать .django-admin makemessages .mo gettext django-admin compilemessages

Вы также можете запустить, чтобы компилятор позаботился обо всех каталогах, перечисленных в настройке .django-admin compilemessages --settings=chemin.vers.settings LOCALE_PATHS

Использование базового языка, отличного от английского

Django предполагает, что исходные строки переводимого проекта написаны на английском языке. Можно выбрать другой язык, но следует иметь в виду ряд ограничений:

  • gettext предоставляет только две формы множественного числа для исходных сообщений, что означает, что вам также необходимо будет предоставить перевод для базового языка, чтобы включить все формы множественного числа, если правила множественного числа основного языка отличаются от английского.
  • Если включен вариант на английском языке и отсутствуют английские строки, резервным языком будет не язык LANGUAGE_CODE проекта, а язык исходных строк. Например, английский пользователь, посещающий LANGUAGE_CODE испанский сайт, исходные строки которого написаны на русском, получит русский, а не испанский.

Copyright ©2020 All rights reserved