Перевод ¶
Обзор ¶
Чтобы сделать проект Django переводимым, вам нужно добавить минимальное количество хуков в свой код и шаблоны Python. Эти перехватчики называются строками перевода . Они говорят Django: «Этот текст должен быть переведен на язык конечного пользователя, если перевод для этого текста доступен на этом языке». Вы несете ответственность за пометку переводимых строк; система может переводить только те строки, которые ей известны.
Затем Django предоставляет утилиты для извлечения строк перевода в файл сообщения . Этот файл - удобный способ для переводчиков предоставить эквивалент строк перевода на целевой язык. После того, как переводчики заполнили файл сообщения, его нужно скомпилировать. В этом процессе используется набор инструментов GNU gettext.
Как только это будет сделано, Django позаботится о переводе веб-приложений на лету на каждый доступный язык в соответствии с языковыми предпочтениями пользователей.
Перехватчики интернационализации Django включены по умолчанию, а это означает, что в определенных местах фреймворка есть небольшие накладные расходы, связанные с i18n. Если вы не используете интернационализацию, вам потребуется две секунды, чтобы задать их
в файле настроек. Затем Django произведет некоторые оптимизации, чтобы не загружать механизм интернационализации.USE_I18N = False
Примечание
Существует также независимый, но связанный USE_L10N
параметр, который определяет, должен ли Django реализовывать локализацию формата. Подробнее см.
Локализация формата .
Примечание
Убедитесь, что вы активировали перевод для своего проекта (самый быстрый способ - проверить, MIDDLEWARE
включен
ли перевод django.middleware.locale.LocaleMiddleware
). Если вы еще этого не сделали, посмотрите, как Django обнаруживает языковые предпочтения .
Интернационализация: в коде Python ¶
Стандартный перевод ¶
Укажите строку перевода с помощью функции
gettext()
. Это соглашение импортировать это как более короткий псевдоним _
, чтобы сэкономить на вводе.
Примечание
gettext
Модуль стандартной библиотеки Python устанавливается _()
в глобальное пространство имен как псевдоним для gettext()
. В Django мы решили не следовать этой практике по нескольким причинам:
- Иногда вам следует использовать
gettext_lazy()
как метод перевода по умолчанию для определенного файла. Без_()
глобального пространства имен разработчик должен подумать о том, какая функция перевода является наиболее подходящей. - Символ подчеркивания (
_
) используется для представления «предыдущего результата» в интерактивной оболочке 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."
По этой причине вы должны использовать интерполяцию именованных строк (например, %(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()
убедитесь, что вы используете одно имя для каждой экстраполированной переменной, включенной в литерал. В приведенных выше примерах обратите внимание, как мы использовали name
переменную Python в обеих строках перевода. Этот пример, помимо того, что он неверен для некоторых языков, как указано выше, завершится ошибкой:
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
значения опций ¶
Например, чтобы перевести текст справки поля имени в следующей модели, выполните следующие действия:
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')
description
Аргумент методов модели @display
декоратору ¶
Для методов модели вы можете предоставить переводы в Django и на сайт администратора с description
аргументом display()
декоратора:
from django.contrib import admin
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'),
)
@admin.display(description=_('Is it a mouse?'))
def is_mouse(self):
return self.kind.type == MOUSE_TYPE
Работа с объектами отложенного перевода ¶
Результат 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()
для обозначения строк в моделях и служебных функциях - обычная операция. Когда вы работаете с этими объектами в другом месте вашего кода, вы должны убедиться, что вы случайно не преобразовали их в строки, потому что они должны быть преобразованы как можно позже (чтобы действовал правильный языковой стандарт). Это требует использования вспомогательной функции, описанной ниже.
Ленивые переводы и множественное число ¶
При использовании отложенного перевода для множественного числа string ( 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
любой из аргументов to 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 в отложенных переводах ¶
В любом другом случае, когда вы хотите отложить перевод, но должны передать переводимую строку в качестве аргумента другой функции, вы можете сами обернуть эту функцию внутри ленивого вызова. Например:
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
атрибуты словаря содержит название языка на английском языке, в самом языке, а в текущем активном языке соответственно. bidi
Атрибут Правда только для двунаправленных языков.
Источником языковой информации является 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
в тег передается шаблон var (см. Выше), тег сначала преобразует такую переменную в строку во время выполнения, а затем ищет эту строку в каталогах сообщений.
Невозможно смешать переменную шаблона внутри строки внутри
. Если для ваших переводов требуются строки с переменными (заполнители), используйте вместо них.{% 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" %}
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 paragraph.\n"
trimmed
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 %}
В дополнение к 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 }}
(«Немецкий», когда активный язык - чешский)
Интернационализация: в коде JavaScript ¶
Добавление переводов в JavaScript создает некоторые проблемы:
- Код JavaScript не имеет доступа к
gettext
реализации. - Код JavaScript не имеет доступа к файлам
.po
или.mo
; они должны быть доставлены сервером. - Каталоги переводов для JavaScript должны быть как можно меньше.
Django предоставляет интегрированное решение этих проблем: он передает переводы в JavaScript, чтобы вы могли вызывать gettext
и т. Д. Из JavaScript.
Основное решение этих проблем - это следующее JavaScriptCatalog
представление, которое генерирует библиотеку кода JavaScript с функциями, имитирующими
gettext
интерфейс, плюс массив строк перевода.
JavaScriptCatalog
Вид ¶
-
класс
JavaScriptCatalog
¶ Представление, которое создает библиотеку кода JavaScript с функциями, имитирующими
gettext
интерфейс, а также массив строк перевода.Атрибуты
-
domain
¶ Домен перевода, содержащий строки для добавления в вывод представления. По умолчанию
'djangojs'
.
-
packages
¶ Список установленных приложений. Эти приложения должны содержать каталог. Все эти каталоги плюс все каталоги (которые всегда включены) объединяются в один каталог. По умолчанию , это означает, что в выходных данных JavaScript предоставляются все доступные переводы .
application names
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'), ]
Если ваш корневой URLconf использует
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'
Именованная интерполяция: этот режим выбирается путем передачи необязательного логического
named
параметра какtrue
.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
Функция имеет доступ к настроенным i18n параметров форматирования и может извлекать строку формата для заданного имени настройки:
document.write(get_format('DATE_FORMAT'));
// 'N j, Y'
У него есть доступ к следующим настройкам:
DATE_FORMAT
DATE_INPUT_FORMATS
DATETIME_FORMAT
DATETIME_INPUT_FORMATS
DECIMAL_SEPARATOR
FIRST_DAY_OF_WEEK
MONTH_DAY_FORMAT
NUMBER_GROUPING
SHORT_DATE_FORMAT
SHORT_DATETIME_FORMAT
THOUSAND_SEPARATOR
TIME_FORMAT
TIME_INPUT_FORMATS
YEAR_MONTH_FORMAT
Это полезно для поддержания согласованности форматирования с отображаемыми 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. }
Примечание по производительности ¶
Различные представления JavaScript / JSON i18n генерируют каталог из .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()
функции.
Предупреждение
Использование любой из этих функций требует, чтобы для каждого запроса был установлен активный язык; другими словами, вам нужно иметь
django.middleware.locale.LocaleMiddleware
в своем
MIDDLEWARE
окружении.
Префикс языка в шаблонах URL ¶
-
i18n_patterns
( * URL-адреса , prefix_default_language = True ) ¶
Эту функцию можно использовать в корневом URLconf, и 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()
разрешено только в корневом URLconf. Использование его во включенном URLconf вызовет
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-адреса только в блоке шаблонов с префиксом языкового кода (с использованием
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.
Babel предоставляет аналогичные функции 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
инструменты работают внутри компании, и поскольку мы хотим разрешить исходные строки, отличные от ASCII, в ядре Django и ваших приложениях, вы
должны использовать UTF-8 в качестве кодировки для ваших PO-файлов (по умолчанию при создании 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, и без какой-либо спецификации (метка порядка байтов), поэтому, если ваш текстовый редактор по умолчанию добавляет такие метки в начало файлов, вам нужно будет перенастроить их.
Устранение неполадок: gettext()
неправильно определяет python-format
в строках со знаками процентов ¶
В некоторых случаях, например, в строках со знаком процента, за которым следует пробел и
тип преобразования строки (например
), строки неправильно помечаются значком ._("10% interest")
gettext()
python-format
Если вы попытаетесь скомпилировать файлы сообщений с неправильно помеченными строками, вы получите сообщение об ошибке, например или .number of format specifications in 'msgid' and
'msgstr' does not match
'msgstr' is not a valid Python format string,
unlike 'msgid'
Чтобы обойти это, вы можете избежать знаков процента, добавив второй знак процента:
from django.utils.translation import gettext as _
output = _("10%% interest")
Или вы можете использовать, no-python-format
чтобы все знаки процента обрабатывались как литералы:
# xgettext:no-python-format
output = _("10% interest")
Создание файлов сообщений из исходного кода JavaScript ¶
Вы создаете и обновляете файлы сообщений так же, как и другие файлы сообщений Django - с помощью инструмента. Единственная разница в том, что вам нужно явно указать, что на языке gettext называется доменом, в данном случае доменом, предоставив параметр, например:django-admin makemessages
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-адрес или, по умолчанию, обратно на предыдущую страницу.
Активируйте это представление, добавив следующую строку в свой URLconf:
path('i18n/', include('django.conf.urls.i18n')),
(Обратите внимание, что в этом примере представление доступно по адресу /i18n/setlang/
.)
Предупреждение
Убедитесь, что вы не включили указанный выше URL-адрес
i18n_patterns()
- для правильной работы он должен быть независимым от языка.
Представление ожидает вызова через POST
метод с language
параметром, установленным в запросе. Если поддержка сеанса включена, представление сохраняет выбор языка в сеансе пользователя. Он также сохраняет выбор языка в файле cookie с именем django_language
по умолчанию. (Имя можно изменить в LANGUAGE_COOKIE_NAME
настройках.)
После установки выбора языка Django ищет next
параметр в файле
POST
или GET
data. Если он найден и Django считает его безопасным URL-адресом (т.е. он не указывает на другой хост и использует безопасную схему), будет выполнено перенаправление на этот URL-адрес. В противном случае Django может вернуться к перенаправлению пользователя на URL-адрес из Referer
заголовка или, если он не задан, в /
зависимости от характера запроса:
- Если запрос принимает HTML-контент (на основе его
Accept
HTTP-заголовка), откат всегда будет выполняться. - Если запрос не принимает HTML, откат будет выполнен, только если
next
параметр был установлен. В противном случае будет возвращен код состояния 204 (без содержимого).
В более старых версиях различие для отката зависит от того, установлено ли в
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, установите LANGUAGE_COOKIE_NAME
файл cookie в ответе:
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 предоставляет богатый набор инструментов i18n для использования в представлениях и шаблонах, он не ограничивает использование специфичным для 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')
Языковой файл cookie ¶
Для настройки языковых файлов cookie можно использовать ряд настроек:
Примечания по реализации ¶
Особенности перевода 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
позволяет выбрать язык на основе данных из запроса. Он настраивает контент для каждого пользователя.
Чтобы использовать 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
функцию в корневом URLconf. См. Раздел Интернационализация: в шаблонах URL-адресов для получения дополнительной информации о языковом префиксе и способах интернационализации шаблонов URL-адресов.В противном случае он ищет файл cookie.
Имя используемого файла cookie устанавливается
LANGUAGE_COOKIE_NAME
настройкой. (Имя по умолчаниюdjango_language
.)В противном случае он просматривает
Accept-Language
заголовок HTTP. Этот заголовок отправляется вашим браузером и сообщает серверу, какие языки вы предпочитаете, в порядке приоритета. Django пробует каждый язык в заголовке, пока не найдет язык с доступными переводами.В противном случае он использует глобальную
LANGUAGE_CODE
настройку.
Заметки:
В каждом из этих мест предпочтение языка ожидается в стандартном языковом формате в виде строки. Например, бразильский португальский
pt-br
.Если базовый язык доступен, но указанный подъязык отсутствует, Django использует базовый язык. Например, если пользователь указывает
de-at
(австрийский немецкий), ноde
доступен только Django, Django используетde
.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
), и приоритета нескольких переводов для одного и того же литерала:
- Каталоги, перечисленные в,
LOCALE_PATHS
имеют наивысший приоритет, причем те, которые появляются первыми, имеют более высокий приоритет, чем те, которые появляются позже. - Затем он ищет и использует, если он существует,
locale
каталог в каждом из установленных приложений, перечисленных вINSTALLED_APPS
. Те, которые появляются первыми, имеют более высокий приоритет, чем те, которые появляются позже. - Наконец, базовый перевод, предоставленный Django,
django/conf/locale
используется в качестве запасного варианта.
Смотрите также
Переводы литералов, включенных в ресурсы JavaScript, ищутся по аналогичному, но не идентичному алгоритму. Подробнее
JavaScriptCatalog
см.
Вы также можете поместить файлы пользовательского формата в
LOCALE_PATHS
каталоги, если вы также установили
FORMAT_MODULE_PATH
.
Во всех случаях ожидается, что имя каталога, содержащего перевод, будет называться с использованием нотации имени локали . Например de
, pt_BR
, es_AR
и т.д. Непереведенные Струны для территориальных языковых вариантов использование перевода родового языка. Например, для непереведенных pt_BR
строк используются pt
переводы.
Таким образом, вы можете писать приложения, которые включают свои собственные переводы, и вы можете переопределить базовые переводы в своем проекте. Или вы можете создать большой проект из нескольких приложений и поместить все переводы в один большой общий файл сообщений, специфичный для проекта, который вы составляете. Выбор за вами.
Все репозитории файлов сообщений имеют одинаковую структуру. Они есть:
- Ищутся все пути, указанные в
LOCALE_PATHS
вашем файле настроек.<language>/LC_MESSAGES/django.(po|mo)
$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)
Для создания файлов сообщений вы используете
инструмент. И вы используете
для создания двоичных файлов, которые используются .django-admin makemessages
django-admin compilemessages
.mo
gettext
Вы также можете запустить, чтобы компилятор обработал все каталоги в ваших настройках.django-admin compilemessages
--settings=path.to.settings
LOCALE_PATHS
Использование неанглийского базового языка ¶
Django делает общее предположение, что исходные строки в переводимом проекте написаны на английском языке. Вы можете выбрать другой язык, но должны помнить об определенных ограничениях:
gettext
предоставляет только две формы множественного числа для исходных сообщений, поэтому вам также потребуется предоставить перевод для базового языка, чтобы включить все формы множественного числа, если правила множественного числа для основного языка отличаются от английского.- Если активирован английский вариант и отсутствуют английские строки, резервным языком будет не язык
LANGUAGE_CODE
проекта, а исходные строки. Например, англичанин, посещающий сайт сLANGUAGE_CODE
установленным испанским языком и исходными строками, написанными на русском языке, увидит русский текст, а не испанский.