Django 國際化和本地化
所謂的國際化,是指使用不同語言的使用者在訪問同一個網站頁面時能夠看到符合其自身語言的文字頁面。
國際化的基本原理是:
- 瀏覽器通過LANGUAGE_CODE在HTTP請求頭中告訴網站後臺伺服器使用者所需要的頁面語言;
- 網站伺服器在渲染頁面時,根據LANGUAGE_CODE查詢每個需要翻譯成對應語言的文字字串,並將其替換到網頁內,最後將網頁返回給使用者瀏覽器。
Django對文字翻譯、日期格式、時間格式、數字格式和時區具有很好的支援。這些內容是國際化的主要工作物件。
從本質上,Django做了這麼兩件事:
- 允許開發者和模板設計者指定在他們的app中哪些部分需要進行翻譯或者格式化成當地的語言、習慣、用法和習俗;
- 根據使用者的偏好習慣,使用鉤子,進行Web本地化。
下面我們看一下Django是如何國際化的:
一、在檢視中標識需要翻譯的文字
在檢視中和HTML模板中都可以標識要翻譯的文字。在檢視中,通過_()
或ugettext()
函式,指定某個變數需要翻譯,如下所示:
from django.utils.translation import ugettext as _ from django.http import HttpResponse def my_view(request): output = _("Welcome to my site.") return HttpResponse(output)
這等同於:
from django.utils.translation import ugettext
from django.http import HttpResponse def my_view(request): output = ugettext("Welcome to my site.") return HttpResponse(output)
也等同於:
def my_view(request):
sentence = 'Welcome to my site.' output = _(sentence) return HttpResponse(output)
還可以這麼用:
def my_view(request, m, d): output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d} return HttpResponse(output)
如果你想給翻譯人員一些提示,可以新增一個以Translators為字首的註釋,例如:
def my_view(request): # Translators: This message appears on the home page only output = ugettext("Welcome to my site.")
二、在模板中表示需要翻譯的文字
在模版檔案中,要標識一個待翻譯的文字,需要使用{% trans %}
模板標籤,但首先你要在模版的頂部載入{% load i18n %}
。比如:
{% load i18n %}
<title>{% trans "This is the title." %}</title>
<title>{% trans myvar %}</title>
要注意的是trans標籤內部不可以有內嵌的模板變數
如果你想提前翻譯字串但是不顯示出來,可以使用下面的方法:
{% trans "This is the title" as the_title %} <title>{{ the_title }}</title> <meta name="description" content="{{ the_title }}">
上面的做法實際上相當於定義了幾個模板變數,下面則是更加複雜的用法:
% trans "starting point" as start %}
{% trans "end point" as end %} {% trans "La Grande Boucle" as race %} <h1> <a href="/" title="{% blocktrans %}Back to '{{ race }}' homepage{% endblocktrans %}">{{ race }}</a> </h1> <p> {% for stage in tour_stages %} {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br />{% else %}, {% endif %} {% endfor %} </p>
三、blocktrans模板標籤
與{% trans %}
模板標籤不同,blocktrans標籤允許你通過使用佔位符來標記由文字和可變內容組成的複雜句子進行翻譯,如下例所示:
{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}
還可以像下面一樣使用:
{% blocktrans with amount=article.price %} That will cost $ {{ amount }}. {% endblocktrans %} {% blocktrans with myvar=value|filter %} This will have {{ myvar }} inside. {% endblocktrans %}
甚至在一個blocktrans標籤內內使用多個表示式:
{% blocktrans with book_t=book|title author_t=author|title %} This is {{ book_t }} by {{ author_t }} {% endblocktrans %}
四、本地化
一旦標記好需要翻譯的文字(也就是國際化)後,就需要進行本地化,也就是建立翻譯用的語言檔案。
語言檔案(Language File)是Django用於儲存翻譯關係的檔案,你的網站應該為每種支援的語言建立一個語言檔案。
建立語言檔案是通過django-admin makemessages
命令完成的。
在專案的根目錄下,也就是包含manage.py的目錄下,執行下面的命令:
django-admin makemessages -l de
其中的de
表示你要本地化的國家,例如pt_BR
表示巴西葡萄牙語,奧地利德語為de_AT
,印尼語為id。
或者使用下面的方式:
python manage.py makemessages -l zh-cn //中文簡體 python manage.py makemessages -l en //英文
執行命令後,Django會在根目錄及其子目錄下蒐集所有需要翻譯的字串,預設情況下它會搜尋.html、.txt和.py檔案,然後在根目錄的locale/LANG/LC_MESSAGES
目錄下建立一個django.po
檔案。對於上面的例子,目錄就是locale/de/LC_MESSAGES/
,檔案就是locale/de/LC_MESSAGES/django.po
。
注意:在Windows下,需要提前安裝GNU gettext工具!
否則會彈出下面的錯誤:
CommandError: Can't find msguniq. Make sure you have GNU gettext tools 0.15 or newer installed.
.po
檔案的格式非常簡單!
每個.po
檔案首先包含一小部分元資料,例如翻譯維護者的聯絡資訊,但檔案的大部分是翻譯對照:被翻譯字串和特定語言的實際翻譯文字之間的簡單對映。
例如,有一個像下面這樣的待翻譯字串:
_("Welcome to my site.")
在.po
檔案中將包含一條下面樣子的條目:
#: path/to/python/module.py:23 msgid "Welcome to my site." msgstr ""
這三行內容各自代表下面的意思:
- 第一行通過註釋表達該條要翻譯的字串在檢視或模版中的位置;
- msgid:要翻譯的字串。不要修改它。
- msgstr:翻譯後的文字。一開始它是空的,需要翻譯人員逐條填寫。
這是一個文字檔案,需要專業的翻譯人員將所有的msgstr空白‘填寫’齊全。如果你的專案比較大,這可能是個磨人的事。
五、編譯語言檔案
當完成語言檔案的建立和翻譯工作後,或者對語言檔案修改後,需要將其編譯成對應的*.mo
檔案,Django在執行時將使用*.mo
檔案對網站進行國際化翻譯。
進入專案根目錄,執行下面的命令,進行語言檔案編譯:
django-admin compilemessages
Django將自動搜尋所有的.po
檔案,將它們都翻譯成.mo
檔案。
至此,國際化和本地化就完成了。你的網站頁面將根據訪問者使用語言的不同,展示為不同的語言版本,比如中文、英文、法文、德文之類。
六、附件
下面列出了所有可用於各種系統設定的語言程式碼對照表:
- af 南非荷蘭語
- sq 阿爾巴尼亞語
- ar-sa 阿拉伯語(沙烏地阿拉伯)
- ar-iq 阿拉伯語(伊拉克)
- ar-eg 阿拉伯語(埃及)
- ar-ly 阿拉伯語(利比亞)
- ar-dz 阿拉伯語(阿爾及利亞)
- ar-ma 阿拉伯語(摩洛哥)
- ar-tn 阿拉伯語(突尼西亞)
- ar-om 阿拉伯語(阿曼)
- ar-ye 阿拉伯語(葉門)
- ar-sy 阿拉伯語(敘利亞)
- ar-jo 阿拉伯語(約旦)
- ar-lb 阿拉伯語(黎巴嫩)
- ar-kw 阿拉伯語(科威特)
- ar-ae 阿拉伯語(阿拉伯聯合大公國)
- ar-bh 阿拉伯語(巴林)
- ar-qa 阿拉伯語(卡達)
- eu 巴斯克語
- bg 保加利亞語
- be 貝勞語
- ca 加泰羅尼亞語
- zh-tw 中文(中國臺灣)
- zh-cn 中文(中華人民共和國)
- zh-hk 中文(中國香港特別行政區)
- zh-sg 中文(新加坡)
- hr 克羅埃西亞語
- cs 捷克語
- da 丹麥語
- nl 荷蘭語(標準)
- nl-be 荷蘭語(比利時)
- en 英語
- en-us 英語(美國)
- en-gb 英語(英國)
- en-au 英語(澳大利亞)
- en-ca 英語(加拿大)
- en-nz 英語(紐西蘭)
- en-ie 英語(愛爾蘭)
- en-za 英語(南非)
- en-jm 英語(牙買加)
- en 英語(加勒比)
- en-bz 英語(貝里斯)
- en-tt 英語(特立尼達)
- et 愛沙尼亞語
- fo 法羅語
- fa 波斯語
- fi 芬蘭語
- fr 法語(標準)
- fr-be 法語(比利時)
- fr-ca 法語(加拿大)
- fr-ch 法語(瑞士)
- fr-lu 法語(盧森堡)
- gd 蓋爾語(蘇格蘭)
- gd-ie 蓋爾語(愛爾蘭)
- de 德語(標準)
- de-ch 德語(瑞士)
- de-at 德語(奧地利)
- de-lu 德語(盧森堡)
- de-li 德語(列支敦斯登)
- el 希臘語
- he 希伯來語
- hi 北印度語
- hu 匈牙利語
- is 冰島語
- in 印度尼西亞語
- it 義大利語(標準)
- it-ch 義大利語(瑞士)
- ja 日語
- ko 朝鮮語
- ko 朝鮮語(韓國)
- lv 拉脫維亞語
- lt 立陶宛語
- mk FYRO 馬其頓語
- ms 馬來西亞語
- mt 馬耳他語
- no 挪威語(博克馬爾)
- no 挪威語(尼諾斯克)
- pl 波蘭語
- pt-br 葡萄牙語(巴西)
- pt 葡萄牙語(葡萄牙)
- rm 拉丁語系
- ro 羅馬尼亞語
- ro-mo 羅馬尼亞語(摩爾達維亞)
- ru 俄語
- ru-mo 俄語(摩爾達維亞)
- sz 薩摩斯語(拉普蘭)
- sr 塞爾維亞語(西里爾)
- sr 塞爾維亞語(拉丁)
- sk 斯洛伐克語
- sl 斯洛維尼亞語
- sb 索布語
- es 西班牙語(西班牙傳統)
- es-mx 西班牙語(墨西哥)
- es 西班牙語(西班牙現代)
- es-gt 西班牙語(瓜地馬拉)
- es-cr 西班牙語(哥斯大黎加)
- es-pa 西班牙語(巴拿馬)
- es-do 西班牙語(多明尼加共和國)
- es-ve 西班牙語(委內瑞拉)
- es-co 西班牙語(哥倫比亞)
- es-pe 西班牙語(祕魯)
- es-ar 西班牙語(阿根廷)
- es-ec 西班牙語(厄瓜多)
- es-cl 西班牙語(智利)
- es-uy 西班牙語(烏拉圭)
- es-py 西班牙語(巴拉圭)
- es-bo 西班牙語(玻利維亞)
- es-sv 西班牙語(薩爾瓦多)
- es-hn 西班牙語(宏都拉斯)
- es-ni 西班牙語(尼加拉瓜)
- es-pr 西班牙語(波多黎各)
- sx 蘇圖語
- sv 瑞典語
- sv-fi 瑞典語(芬蘭)
- th 泰語
- ts 湯加語
- tn 瓦納語
- tr 土耳其語
- uk 烏克蘭語
- ur 烏爾都語
- ve 文達語
- vi 越南語
- xh 科薩語
- ji 依地語
- zu 祖魯語