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

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