Django模板中的复数显示及国际化

Django模板中的复数显示及国际化

在Django开发中,常常需要根据物体的单数和复数,而变换不同的表达方式,特别是在英语中,如单复数的显示。如下面的场景:

# 复数表达形式
There are 5 VMs
# 单数表达形式
There is 1 VM

在Django 模板中,有两种方式能解决类似的问题:

  1. pluralize过滤器

  2. blocktrans 块标签搭配plural标签

使用 pluralize 过滤器

pluralize 过滤器通过返回后缀的形式以支持单复数形式的显示,默认情况下当为复数时,会添加 “s” 后缀。如:

You have {{ num_messages }} message{{ num_messages|pluralize }}.

如果 num_messages 为1, 输出为“You have 1 message.”,如果为5,则输出“You have 5 messages.”

同样,也可指定复数情况下需要添加的后缀,如:

You have {{ num_walruses }} walrus{{ num_walruses|pluralize:"es" }}.

更深一点,你也可完全同时指定单数和复数形式下的后缀,如

You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}.

回到上面的问题,那用 pluralize 过滤器就成了下面这样的形式了

There {{ amount|pluralize:"is,are" }} {{ amount }} VM{{ amount|pluralize }}

需要注意的,0 在英语中视作复数。

但需要注意的,上面这种方法虽然使用非常方便,但却无法对其进行国际化了。如果需要支持国际化,则需要用到下面的方法。

blocktrans 块标签 + plural标签

blocktrans 国际化用法

trans 标签不同,对于 blocktrans 模板标签,通过占位符它支持对复杂句式(同时包含字符串和变量)进行国际化。如下:

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

另外,如果需要使用模板表达式,即访问 对象的属性 或者使用 过滤器,就需要将这个表达式的值赋给一个局部变量,在blocktrans内部使用。原因见后面的注意说明。

# 访问对象属性
{% blocktrans with amount=article.price %}
That will cost $ {{ amount }}.
{% endblocktrans %}

# 使用过滤器
{% blocktrans with myvar=value|filter %}
This will have {{ myvar }} inside.
{% endblocktrans %}

# 使用多个局部变量
{% blocktrans with book_t=book|title author_t=author|title %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}

而对于django.po文件里,对应的翻译需要这样写

msgid "That will cost $ %(amount)s."
msgstr "那将花费 $ %(amount)s ."
  • 通过 with = 赋值方式是后来的django版本支持,当然新版本仍支持 with as 的赋值方式,如:
    python
    {% blocktrans with book|titleas book_t and author|title as author_t %}
  • 在blocktrans块标签内不能再嵌套使用其他的块标签,如{% for %} or {% if %}等。

blocktrans 复数化用法 – plural标签

另外blocktrans标签也支持复数化(pluralization),使用步骤如下:

  1. 通过count =指定需要需要判断的数量变量,这个 counter 将用来判断是显示单数形式还是显示复数形式
  2. 在 {%blocktrans %} 和 {% endblocktrans %}间,通过{% plural %}标签指定要显示的复数形式。

直接上例子说明:

{% blocktrans count counter=list|length %}
# 单数显示形式
There is only one {{ name }} object.
{% plural %}
# 复数显示形式
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}

#同时使用局部变量和复数化特性
{% blocktrans with amount=article.price count years=i.length %}
That will cost $ {{ amount }} per year.
{% plural %}
That will cost $ {{ amount }} per {{ years }} years.
{% endblocktrans %}

注意blocktrans 内部会调用ungettext方法以支持国际化,所以同使用ungettext一样,在blocktrans块标签内只能用单一变量名进行数据的渲染,所以对于表达式和过滤器的使用,需要将先其赋值到一个单一的局部变量,使其能在blocktrans进行数据渲染。

经过上面的探讨后,回到最初的问题,那么用blocktrans不仅可以解决复数化的问题,还能优雅地支持国际化:

# template
{% blocktrans count amount=amount %}
   There is {{ amount }} VM.
{% plural %}
   There are {{ amount }} VMs.
{% endblocktrans %}

# django.po
msgid ""
"\n"
"    There is %(amount)s VM.\n"
msgid_plural ""
"\n"
"    There are %(amount)s VMs.\n"
msgstr[0] ""
"\n"
"有 %(amount)s 台虚拟机\n"

这里尤其要注意在 po 文件中做转译时,排版一定要严格根据 template 中的格式来,尤其要注意换行和空格,要保持绝对的一致,下面再给几个模式以便进行比较分析:

# example 1
# -----template------
<div>
   {% blocktrans count amount=amount %}
       There is {{ amount }} VM.
   {% plural %}
       There are {{ amount }} VMs.
   {% endblocktrans %}
</div>

# -----django.po-------
msgid ""  # `blocktrans`开始
"\n"    # `blocktrans`与转译文本之间的换行
"        There is %(amount)s VM.\n"    # 上次换行到转译文本结束,包括换行
"    "    # 上次换行到`plural`标签的字符(空格)`
msgid_plural ""    # `plural`开始
"\n"    # `plural`与转译文本之间的换行
"        There are %(amount)s VMs.\n"    #上次换行到转译文本结束,包括换行
"        "    # 上次换行到`endblocktrans`标签的字符(空格)
msgstr[0] "" 
"\n"
"有 %(amount)s 台虚拟机"

# 其实,msgstr[0] 只要保证转译后的文本开关与结尾和msgid中的开头和结尾的"\n"一致就行,所以下面这行也使用于对上面的转译
# msgstr[0] "\n有 %(amount)s 台虚拟机"

# example 2
# -----template------
{% blocktrans count amount=amount %}There is {{ amount }} VM.{% plural %}There are {{ amount }} VMs.{% endblocktrans %}

# -----django.po-------
msgid "There is %(amount)s VM."
msgid_plural "There are %(amount)s VMs."
msgstr[0] "有 %(amount)s 台虚拟机"

从上面的代码分析对比,一般还是建议用第二种方式显示,除非在前台需要预处理格式的排版。

另外关于msgstr[0], msgstr[1],……,以后再深究,可以参考这里


参考
1. Built-in template tags and filters | Django documentation | Django
2. Translation | Django documentation | Django

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章