1、如何指定待翻译字符串

翻译字符串指定这段需要被翻译的文本。 这些字符串可以出现在您的Python代码和模板中。 而标记出这些翻译字符串则是您的责任;系统仅能翻译出它所知道的东西。

在Python 代码中

标准翻译

使用函数 ugettext() 来指定一个翻译字符串。 作为惯例,使用短别名 _ 来引入这个函数以节省键入时间.

在下面这个例子中,文本 "Welcome to my site" 被标记为待翻译字符串:

  1. from django.utils.translation import ugettext as _
  2. def my_view(request):
  3. output = _("Welcome to my site.")
  4. return HttpResponse(output)

显然,你也可以不使用别名来编码。 下面这个例子和前面两个例子相同:

  1. from django.utils.translation import ugettext
  2. def my_view(request):
  3. output = ugettext("Welcome to my site.")
  4. return HttpResponse(output)

翻译字符串对于计算出来的值同样有效。 下面这个例子等同前面一种:

  1. def my_view(request):
  2. words = ['Welcome', 'to', 'my', 'site.']
  3. output = _(' '.join(words))
  4. return HttpResponse(output)

翻译对变量也同样有效。 这里是一个同样的例子:

  1. def my_view(request):
  2. sentence = 'Welcome to my site.'
  3. output = _(sentence)
  4. return HttpResponse(output)

(以上两个例子中,对于使用变量或计算值,需要注意的一点是Django的待翻译字符串检测工具, make-messages.py ,将不能找到这些字符串。 稍后,在 makemessages 中会有更多讨论。)

你传递给 _()gettext() 的字符串可以接受占位符,由Python标准命名字符串插入句法指定的。 例如:

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

这项技术使得特定语言的译文可以对这段文本进行重新排序。 比如,一段英语译文可能是 "Today is November 26." ,而一段西班牙语译文会是 "Hoy es 26 de Noviembre." 使用占位符(月份和日期)交换它们的位置。

由于这个原因,无论何时当你有多于一个单一参数时,你应当使用命名字符串插入(例如: %(day)s )来替代位置插入(例如: %s or %d )。 如果你使用位置插入的话,翻译动作将不能重新排序占位符文本。

标记字符串为不操作

使用 django.utils.translation.gettext_noop() 函数来标记一个不需要立即翻译的字符串。 这个串会稍后从变量翻译。

使用这种方法的环境是,有字符串必须以原始语言的形式存储(如储存在数据库中的字符串)而在最后需要被翻译出来(如显示给用户时)。

惰性翻译

使用 django.utils.translation.gettext_lazy() 函数,使得其中的值只有在访问时才会被翻译,而不是在 gettext_lazy() 被调用时翻译。

例如:要翻译一个模型的 help_text,按以下进行:

  1. from django.utils.translation import ugettext_lazy
  2. class MyThing(models.Model):
  3. name = models.CharField(help_text=ugettext_lazy('This is the help text'))

在这个例子中, ugettext_lazy() 将字符串作为惰性参照存储,而不是实际翻译。 翻译工作将在字符串在字符串上下文中被用到时进行,比如在Django管理页面提交模板时。

在Python中,无论何处你要使用一个unicode 字符串(一个unicode 类型的对象),您都可以使用一个 ugettext_lazy() 调用的结果。 一个ugettext_lazy()对象并不知道如何把它自己转换成一个字节串。如果你尝试在一个需要字节串的地方使用它,事情将不会如你期待的那样。 同样,你也不能在一个字节串中使用一个 unicode 字符串。所以,这同常规的Python行为是一致的。 例如:

  1. # This is fine: putting a unicode proxy into a unicode string.
  2. u"Hello %s" % ugettext_lazy("people")
  3. # This will not work, since you cannot insert a unicode object
  4. # into a bytestring (nor can you insert our unicode proxy there)
  5. "Hello %s" % ugettext_lazy("people")

如果你曾经见到到像"hello"这样的输出,你就可能在一个字节串中插入了ugettext_lazy()的结果。 在您的代码中,那是一个漏洞。

如果觉得 gettextlazy 太过冗长,可以用 (下划线)作为别名,就像这样:

  1. from django.utils.translation import ugettext_lazy as _
  2. class MyThing(models.Model):
  3. name = models.CharField(help_text=_('This is the help text'))

在Django模型中总是无一例外的使用惰性翻译。 为了翻译,字段名和表名应该被标记。(否则的话,在管理界面中它们将不会被翻译) 这意味着在Meta类中显式地编写verbose_naneverbose_name_plural选项,而不是依赖于Django默认的verbose_nameverbose_name_plural(通过检查model的类名得到)。

  1. from django.utils.translation import ugettext_lazy as _
  2. class MyThing(models.Model):
  3. name = models.CharField(_('name'), help_text=_('This is the help text'))
  4. class Meta:
  5. verbose_name = _('my thing')
  6. verbose_name_plural = _('mythings')

复数的处理

使用django.utils.translation.ungettext()来指定以复数形式表示的消息。 例如:

  1. from django.utils.translation import ungettext
  2. def hello_world(request, count):
  3. page = ungettext('there is %(count)d object',
  4. 'there are %(count)d objects', count) % {
  5. 'count': count,
  6. }
  7. return HttpResponse(page)

ngettext 函数包括三个参数: 单数形式的翻译字符串,复数形式的翻译字符串,和对象的个数(将以 count 变量传递给需要翻译的语言)。

模板代码

Django模板使用两种模板标签,且语法格式与Python代码有些许不同。 为了使得模板访问到标签,需要将 {% load i18n %} 放在模板最前面。

这个{% trans %}模板标记翻译一个常量字符串 (括以单或双引号) 或 可变内容:

  1. <title>{% trans "This is the title." %}</title>
  2. <title>{% trans myvar %}</title>

如果有noop 选项,变量查询还是有效但翻译会跳过。 当空缺内容要求将来再翻译时,这很有用。

  1. <title>{% trans "myvar" noop %}</title>

在一个带 {% trans %} 的字符串中,混进一个模板变量是不可能的。如果你的译文要求字符串带有变量(占位符placeholders),请使用 {% blocktrans %}

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

使用模板过滤器来翻译一个模板表达式,需要在翻译的这段文本中将表达式绑定到一个本地变量中:

  1. {% blocktrans with value|filter as myvar %}
  2. This will have {{ myvar }} inside.
  3. {% endblocktrans %}

如果需要在 blocktrans 标签内绑定多个表达式,可以用 and 来分隔:

  1. {% blocktrans with book|title as book_t and author|title as author_t %}
  2. This is {{ book_t }} by {{ author_t }}
  3. {% endblocktrans %}

为了表示单复数相关的内容,需要在 {% blocktrans %}{% endblocktrans %} 之间使用 {% plural %} 标签来指定单复数形式,例如:

  1. {% blocktrans count list|length as counter %}
  2. There is only one {{ name }} object.
  3. {% plural %}
  4. There are {{ counter }} {{ name }} objects.
  5. {% endblocktrans %}

其内在机制是,所有的块和内嵌翻译调用相应的 gettextngettext

每一个RequestContext可以访问三个指定翻译变量:

  • {{ LANGUAGES }} 是一系列元组组成的列表,每个元组的第一个元素是语言代码,第二个元素是用该语言表示的语言名称。

  • 作为一二字符串,LANGUAGE_CODE是当前用户的优先语言。 例如: en-us。(请参见下面的Django如何发现语言偏好)

  • LANGUAGE_BIDI就是当前地域的说明。 如果为真(True),它就是从右向左书写的语言,例如: 希伯来语,阿拉伯语。 如果为假(False),它就是从左到右书写的语言,如: 英语,法语,德语等。

如果你不用这个RequestContext扩展,你可以用3个标记到那些值:

  1. {% get_current_language as LANGUAGE_CODE %}
  2. {% get_available_languages as LANGUAGES %}
  3. {% get_current_language_bidi as LANGUAGE_BIDI %}

这些标记亦要求一个 {% load i18n %}

翻译的hook在任何接受常量字符串的模板块标签内也是可以使用的。 此时,使用 _() 表达式来指定翻译字符串,例如:

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

在这种情况下,标记和过滤器两个都会看到已经翻译的字符串,所有它们并不需要提防翻译操作。

备注:

在这个例子中,翻译结构将放过字符串"yes,no",而不是单独的字符串"yes""no"。翻译的字符串将需要包括逗号以便过滤器解析代码明白如何分割参数。 例如, 一个德语翻译器可能会翻译字符串 "yes,no""ja,nein" (保持逗号原封不动)。

与惰性翻译对象一道工作

在模型和公用函数中,使用ugettext_lazy()ungettext_lazy()来标记字符串是很普遍的操作。 当你在你的代码中其它地方使用这些对象时,你应当确定你不会意外地转换它们成一个字符串,因为它们应被尽量晚地转换(以便正确的地域生效) 这需要使用及个帮助函数。

拼接字符串: string_concat()

标准Python字符串拼接(''.join([…]) ) 将不会工作在包括惰性翻译对象的列表上。 作为替代,你可以使用django.utils.translation.stringconcat(), 这个函数创建了一个惰性对象,其连接起它的内容 并且_ 仅当结果被包括在一个字符串中时转换它们为字符串 。 例如:

  1. from django.utils.translation import string_concat
  2. # ...
  3. name = ugettext_lazy(u'John Lennon')
  4. instrument = ugettext_lazy(u'guitar')
  5. result = string_concat([name, ': ', instrument])

System Message: ERROR/3 (&lt;string&gt;, line 519)

Error in “cnid” directive: no content permitted.

  1. .. cnid:: 109
  2. 在这种情况下,当

System Message: WARNING/2 (&lt;string&gt;, line 523)

Explicit markup ends without a blank line; unexpected unindent.

result 自己被用与一个字符串时, result 中的惰性翻译将仅被转换为字符串(通常在模板渲染时间)。

allow_lazy() 修饰符

Django提供很多功能函数(如:取一个字符串作为他们的第一个参数并且对那个字符串做些什么)。(尤其在 django.utils 中) 这些函数被模板过滤器像在其他代码中一样直接使用。

如果你写你自己的类似函数并且与翻译打交道,当第一个参数是惰性翻译对象时,你会面临“做什么”的难题。 因为你可能在视图之外使用这个函数(并且因此当前线程的本地设置将会不正确),所以你不想立即转换其为一个字符串。

象这种情况,请使用 django.utils.functional.allowlazy() 修饰符。 它修改这个函数以便 假如_第一个参数是一个惰性翻译, 这个函数的赋值会被延后直到它需要被转化为一个字符串为止。

例如:

  1. from django.utils.functional import allow_lazy
  2. def fancy_utility_function(s, ...):
  3. # Do some conversion on string 's'
  4. # ...
  5. fancy_utility_function = allow_lazy(fancy_utility_function, unicode)

allow_lazy() 装饰符 采用了另外的函数来装饰,以及一定量的,原始函数可以返回的特定类型的额外参数 (*args ) 。 通常,在这里包括 unicode 就足够了并且确定你的函数将仅返回Unicode字符串。

使用这个修饰符意味着你能写你的函数并且假设输入是合适的字符串,然后在末尾添加对惰性翻译对象的支持。