为了使django项目具有可翻译性,必须向Python代码和模板添加最少数量的钩子。这些钩子叫做 translation strings . 他们告诉Django:“如果可以使用该语言翻译该文本,则应将该文本翻译为最终用户的语言。”标记可翻译字符串是您的责任;系统只能翻译它知道的字符串。
然后Django提供了将翻译字符串提取为 message file . 此文件是翻译人员提供目标语言中的翻译字符串等价物的方便方法。一旦翻译人员填写了消息文件,就必须对其进行编译。这个过程依赖于gnu gettext工具集。
一旦完成,Django会根据用户的语言偏好,将网络应用程序即时翻译成每种可用的语言。
Django的国际化钩子在默认情况下是打开的,这意味着在框架的某些地方有一些与i18n相关的开销。如果您不使用国际化,您应该用两秒钟来设置 USE_I18N = False
在设置文件中。然后,Django将进行一些优化,以避免加载国际化机器。
备注
确保您已经为项目激活了翻译(最快的方法是检查 MIDDLEWARE
包括 django.middleware.locale.LocaleMiddleware
)如果你还没有,看 Django如何发现语言偏好 .
使用函数指定翻译字符串 gettext()
. 按照惯例,将其作为一个较短的别名导入, _
,保存键入内容。
备注
python的标准库 gettext
模块安装 _()
作为全局命名空间的别名 gettext()
. 在Django,我们选择不遵循这种做法,原因有两个:
有时,你应该使用 gettext_lazy()
作为特定文件的默认翻译方法。没有 _()
在全局名称空间中,开发人员必须考虑哪一个是最合适的翻译函数。
下划线字符 (_
)用于在Python的交互式shell和doctest测试中表示“上一个结果”。安装全局 _()
功能导致干扰。显式导入 gettext()
作为 _()
避免这个问题。
哪些函数可以别名为 _
是吗?
因为怎样 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的标准名为string interpolation语法指定的占位符。例子::
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的支持。特别是Python f-strings 尚未得到支持 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应用程序本地化为语言时,此函数非常有用,因为这些语言的数量和复杂性 plural forms 大于英语中使用的两种形式(“object”表示单数形式,“objects”表示所有情况,其中 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
期权价值¶例如,要翻译 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
选项,而不是依赖于以英文为中心的回退,并且Django通过查看模型的类名来确定冗长的名称:
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
装饰器¶对于模型方法,您可以使用 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()
只要使用字符串(A),就可以使用调用 str
对象)在其他Django代码中,但它可能不能与任意的Python代码一起工作。例如,以下代码将不起作用,因为 requests 库不能处理 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
字符串定义时的参数。因此,您被授权传递密钥名称而不是一个integer作为 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()
¶Python 的 str.format()
当 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
它本身用在字符串中(通常在模板呈现时)。
对于您希望延迟转换但必须将可翻译字符串作为参数传递给另一个函数的任何其他情况,您可以将此函数包装在一个懒惰的调用中。例如::
from django.utils.functional import lazy
from django.utils.translation import gettext_lazy as _
def to_lower(string):
return string.lower()
to_lower_lazy = lazy(to_lower, str)
稍后:
lazy_string = to_lower_lazy(_("My STRING!"))
这个 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 templates 使用两个模板标记和与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 %}
还支持 contextual markers 使用 context
关键词:
{% translate "May" context "month name" %}
blocktranslate
模板标签¶与之相反, translate
标签,即 blocktranslate
Tag允许您通过使用占位符标记由直译和可变内容组成的复杂句子进行翻译:
{% 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
电话这意味着相同 notes regarding ngettext variables apply.
反向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 %}
还支持 contextual markers 使用 context
关键词:
{% blocktranslate with name=user.username context "greeting" %}Hi {{ name }}{% endblocktranslate %}
另一项功能 {% blocktranslate %}
支持的是 trimmed
选择。此选项将从内容的开头和结尾删除换行符 {% blocktranslate %}
标记,替换行首和行尾的任何空格,并使用空格字符将所有行合并为一行。这对于缩进 {% blocktranslate %}
标记中的相应条目中没有缩进字符的 .po
文件,这使得翻译过程变得更容易。
例如,以下内容 {% blocktranslate %}
标签:
{% blocktranslate trimmed %}
First sentence.
Second paragraph.
{% endblocktranslate %}
将导致条目 "First sentence. Second paragraph."
在 .po
文件,与 "\n First sentence.\n Second paragraph.\n"
,如果 trimmed
尚未指定选项。
就像 Python code ,可以使用注释为翻译人员指定这些注释,也可以使用 comment
标签:
{% comment %}Translators: View verb{% endcomment %}
{% translate "View" %}
{% comment %}Translators: Short intro blurb{% endcomment %}
<p>{% blocktranslate %}A multiline translatable
literal.{% endblocktranslate %}</p>
或与 {{#
… #}}
one-line comment constructs :
{# 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 %}
当第一次出现“欢迎进入我们的页面”时,使用的是当前语言,第二次总是使用英语。
向javascript添加翻译会带来一些问题:
javascript代码无法访问 gettext
实施。
javascript代码无权访问 .po
或 .mo
文件;它们需要由服务器传递。
JavaScript的翻译目录应尽可能小。
Django为这些问题提供了一个集成的解决方案:它将翻译转换为javascript,这样您就可以调用 gettext
等等,在javascript中。
这些问题的主要解决办法是 JavaScriptCatalog
视图,它生成一个JavaScript代码库,其中包含模拟 gettext
接口,加上一个翻译字符串数组。
JavaScriptCatalog
看法¶一个视图,它生成一个带有模拟 gettext
接口,加上一个翻译字符串数组。
Attributes
包含要添加到视图输出中的字符串的转换域。默认为 'djangojs'
.
列表 application names
在已安装的应用程序中。这些应用程序应该包含 locale
目录。所有这些目录加上 LOCALE_PATHS
(始终包括在内)合并到一个目录中。默认为 None
这意味着所有可用的翻译 INSTALLED_APPS
在javascript输出中提供。
带默认值的示例 ::
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
在站点上查看,其中一些定义相同的字符串,最后加载的目录中的字符串优先。
要使用目录,请像这样引入动态生成的脚本:
<script src="{% url 'javascript-catalog' %}"></script>
这将使用反向URL查找来查找javascript目录视图的URL。加载目录后,您的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'
它可以访问以下设置:
这对于保持格式与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()
),提供了一个 pluralized 上下文翻译的单词:
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
(应该) not 复数)值。
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
每个请求的文件。因为它的输出是恒定的,至少对于一个给定版本的站点来说,它是一个很好的缓存候选者。
服务器端缓存将减少CPU负载。它很容易用 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="jsi18n-%s" % get_version())(
JavaScriptCatalog.as_view()
),
name="javascript-catalog",
),
]
客户端缓存将节省带宽并使站点加载更快。如果你使用电子标签 (ConditionalGetMiddleware
)你已经被覆盖了。否则,您可以申请 conditional decorators . 在下面的示例中,每当重新启动应用程序服务器时,缓存都会失效:
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.
Django提供了两种将URL模式国际化的机制:
将语言前缀添加到URL模式的根目录中,以便 LocaleMiddleware
检测要从请求的URL激活的语言。
使URL模式本身可以通过 django.utils.translation.gettext_lazy()
功能。
警告
使用这些功能之一需要为每个请求设置活动语言;换句话说,您需要 django.middleware.locale.LocaleMiddleware
在你 MIDDLEWARE
设置。
此函数可以在根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将自动将语言前缀添加到由 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模式。
也可以使用 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/'
警告
在大多数情况下,最好只在语言代码前缀的模式块(使用 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
标记要求语言代码是唯一的参数。
一旦应用程序的字符串文本被标记为以后的翻译,就需要编写(或获取)翻译本身。这就是工作原理。
第一步是创建 message file 为了一种新的语言。消息文件是一个纯文本文件,表示一种语言,它包含所有可用的翻译字符串,以及它们在给定语言中的表示方式。消息文件具有 .po
文件扩展名。
Django带着一个工具, django-admin makemessages
自动创建和维护这些文件。
GetText实用程序
这个 makemessages
命令(和) compilemessages
稍后讨论)使用来自GNU GetText工具集的命令: xgettext
, msgfmt
, msgmerge
和 msguniq
.
的最小版本 gettext
支持的实用程序为0.15。
要创建或更新消息文件,请运行以下命令:
django-admin makemessages -l de
…在哪里 de
是 locale name 对于要创建的消息文件。例如, 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
警告
什么时候? creating message files from JavaScript source code 你需要用这个特别的 djangojs
域, not -e js
.
使用jinja2模板?
makemessages
不理解jinja2模板的语法。要从包含jinja2模板的项目中提取字符串,请使用 Message Extracting 从 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
. 有关更多信息,请阅读其文档 working with message catalogs .
没有文本吗?
如果你没有 gettext
公用事业已安装, makemessages
将创建空文件。如果是这种情况,请安装 gettext
实用程序或复制英文消息文件 (locale/en/LC_MESSAGES/django.po
)如果可用的话,并将其用作起点,这是一个空的翻译文件。
在Windows上工作?
如果您使用的是Windows并且需要安装GNU GetText实用程序,那么 makemessages
作品,见 gettext 在Windows上 更多信息。
每个 .po
文件包含少量元数据,例如翻译维护者的联系信息,但文件的大部分是 messages --特定语言的翻译字符串和实际翻译文本之间的映射。
例如,如果您的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源代码字符串,所以您 must 使用UTF-8作为您的 .po
文件(默认设置为 .po
创建文件)。这意味着每个人都将使用相同的编码,这在Django处理 .po
档案。
模糊条目
makemessages
有时会生成标记为模糊的翻译条目,例如当从之前翻译的字符串中推断翻译时。默认情况下,模糊条目为 not 处理 compilemessages
。
要重新检查新翻译字符串的所有源代码和模板,并更新 all 语言,请运行以下命令:
django-admin makemessages -a
在创建了消息文件之后——每次对其进行更改——您需要将其编译成一个更有效的形式,以供使用。 gettext
. 用这个做 django-admin compilemessages
实用工具。
此工具适用于所有可用的 .po
文件和创建 .mo
文件,这些文件是为使用而优化的二进制文件 gettext
。在运行时所在的同一目录中 django-admin makemessages
,奔跑 django-admin compilemessages
如下所示:
django-admin compilemessages
就是这样。您的翻译可以使用了。
在Windows上工作?
如果您使用的是Windows并且需要安装GNU GetText实用程序,那么 django-admin compilemessages
作品见 gettext 在Windows上 更多信息。
.po
文件:编码和BOM使用。
仅Django支持 .po
文件以UTF-8编码,没有任何BOM(字节顺序标记),因此如果文本编辑器默认情况下在文件开头添加此类标记,则需要重新配置它。
gettext()
检测不正确 python-format
在带有百分号的字符串中¶在某些情况下,例如带有百分号、空格和 string conversion type (例如) _("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")
创建和更新消息文件的方式与其他Django消息文件相同--使用 django-admin makemessages
工具。唯一的区别是您需要显式指定在gettext术语中称为域的内容,在本例中为 djangojs
域,通过提供一个 -d djangojs
参数,如下所示:
django-admin makemessages -d djangojs -l de
这将创建或更新德语JavaScript的消息文件。更新消息文件后,运行 django-admin compilemessages
与处理普通Django消息文件相同。
gettext
在Windows上¶仅对于想要提取消息ID或编译消息文件的人才需要这 (.po
).翻译工作本身涉及编辑此类现有文件,但如果您想创建自己的消息文件,或想测试或编译更改后的消息文件,请下载 a precompiled binary installer 。
您也可以使用 gettext
您在其他地方获得的二进制文件,只要 xgettext --version
命令工作正常。请勿尝试将Django翻译实用程序与 gettext
如果命令为 xgettext --version
在Windows命令提示符下输入会导致弹出窗口,显示“``xgetext.exe``已生成错误,将由Windows关闭”。
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
重定向视图¶为了方便起见,Django提供了一个视图, django.views.i18n.set_language()
设置用户的语言首选项并重定向到给定的URL,或者在默认情况下返回到上一页。
通过将以下行添加到您的urlconf来激活此视图:
path("i18n/", include("django.conf.urls.i18n")),
(请注意,此示例使视图在 /i18n/setlang/
)
警告
确保您不在 i18n_patterns()
-它需要独立于语言才能正常工作。
该视图应通过调用 POST
方法,用 language
请求中设置的参数。如果启用了会话支持,则视图将保存用户会话中的语言选择。它还将语言选择保存在一个名为 django_language
默认情况下。(可以通过 LANGUAGE_COOKIE_NAME
设置)
在设置语言选项后,Django查找 next
中的参数 POST
或 GET
数据。如果找到了该URL,并且Django认为它是一个安全的URL(即,它不指向其他主机并使用安全方案),则将执行对该URL的重定向。否则,django可能会返回到将用户重定向到 Referer
头,如果未设置,则为 /
,取决于请求的性质:
如果请求接受HTML内容(基于其 Accept
HTTP标头),则始终会执行回退。
如果请求不接受HTML,则只有在 next
参数已设置。否则将返回204状态代码(无内容)。
以下是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查找用户将在 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")
姜戈的翻译机器使用标准 gettext
python附带的模块。如果你知道 gettext
你可以用Django翻译的方式注意到这些专业:
字符串域是 django
或 djangojs
. 此字符串域用于区分将其数据存储在公共消息文件库中的不同程序(通常 /usr/share/locale/
)这个 django
域用于Python和模板转换字符串,并加载到全局转换目录中。这个 djangojs
域仅用于JavaScript翻译目录,以确保这些目录尽可能小。
Django不使用 xgettext
独自一人。它在周围使用python包装 xgettext
和 msgfmt
. 这主要是为了方便。
准备好翻译后--或者,如果您想使用Django附带的翻译--您将需要为您的应用程序激活翻译。
在幕后,Django有一个非常灵活的模型来决定应该使用哪种语言——针对特定用户的安装范围,或者同时使用这两种语言。
要设置安装范围的语言首选项,请设置 LANGUAGE_CODE
. Django使用这种语言作为默认翻译——如果通过语言环境中间件使用的方法之一找不到更好的匹配翻译,则是最后一次尝试(见下文)。
如果你只想用你的母语运行django,你所需要做的就是设置 LANGUAGE_CODE
并确保相应的 message files 以及他们的编译版本 (.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",
]
(有关中间件的更多信息,请参见 middleware documentation )
LocaleMiddleware
尝试通过以下算法确定用户的语言首选项:
首先,它在请求的URL中查找语言前缀。仅当使用 i18n_patterns
在根urlconf中的函数。见 国际化:在URL模式中 有关语言前缀和如何国际化URL模式的详细信息。
如果失败了,它会寻找一个饼干。
所用cookie的名称由 LANGUAGE_COOKIE_NAME
设置。(默认名称为 django_language
)
如果失败了,它会看到 Accept-Language
HTTP报头。此标题由浏览器发送,并按优先级顺序告诉服务器您喜欢哪种语言。Django尝试头中的每种语言,直到找到一种具有可用翻译的语言。
如果失败,它将使用 LANGUAGE_CODE
设置。
笔记:
在这些地方,语言偏好应该在标准中。 language format ,作为字符串。例如,巴西葡萄牙语是 pt-br
.
如果基础语言可用,但指定的子语言不可用,Django将使用基础语言。例如,如果用户指定 de-at
(奥地利德语)但姜戈只有 de
可用,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构建了一个内存中统一的文本翻译目录。为了实现这一点,它通过遵循此算法来查找翻译,该算法将检查不同的文件路径以加载编译的 message files (.mo
)以及同一文本的多个翻译的优先顺序:
中列出的目录 LOCALE_PATHS
具有最高的优先级,先出现的优先级高于后出现的优先级。
然后,如果它存在一个 locale
中列出的每个已安装应用程序的目录 INSTALLED_APPS
. 先出现的优先级高于后出现的优先级。
最后,Django提供的基本翻译在 django/conf/locale 被用作后备手段。
参见
javascript资产中包含的文本翻译是按照类似但不相同的算法查找的。见 JavaScriptCatalog
了解更多详细信息。
你也可以把 custom format files 在 LOCALE_PATHS
如果还设置了目录 FORMAT_MODULE_PATH
.
在所有情况下,包含翻译的目录的名称都应使用 locale name 表示法。例如。 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
设置为西班牙语,用俄语编写的原始字符串将看到俄语文本而不是西班牙语。
7月 22, 2024