Django 國際化(一)- 在 template 、views、models 新增 i18n 標籤生成 .po & .mo 檔

Jo-Yu Liao
8 min readSep 13, 2019

--

本篇介紹 Django (2.2 版本) 如何實現依照語言顯示對應網站的功能。適用讀者:對 Django 有基礎認識的工程師。

國際化(i18n,internationalization

i18n

國際化又稱為 i18n (internationalization 取頭尾,中間的 18 代表 i 與 n 中間有 18 個英文字母),根據維基百科的定義:「國際化是指在設計軟體,將軟體與特定語言及地區脫鉤的過程。當軟體被移植到不同的語言及地區時,軟體本身不用做內部工程上的改變或修正。」可以理解為網站呈現的內容不是硬寫進程式,而是會依據設置的語言轉換,常體現在網頁的語言選取部分,當選取「English」,則網站呈現英文內容,選取「繁體中文」則呈現繁體中文的內容。

Django i18n

Django 是用 python 撰寫、成熟完整的服務器端網站框架,目前的版本為 2.2 (2019/09/13),如果不會 Django 建議先閱讀官方文檔。

Django 本身的 i18n 功能成熟,但不同版本的撰寫方式略有不同,需要注意版本選用適合的寫法,本篇適用的版本為 2.2 版本。

程式的目錄架構如下:

<project>/
- manager.py
- locale/ # 新增
- zh_Hant/
- 其他語言/
- settings.py # 修改
...略...
  1. 在 manager.py 同級目錄下新增 locale,並在 settings.py 新增「‘django.middleware.locale.LocaleMiddleware’」 Middleware (依照 request 設置語言)、「‘django.template.context_processors.i18n’」、設置網站要支援的語言 LANGUAGES,並設置 locale 的路徑,並在 locale 目錄下新增對應的語言檔案(注意:zh-Hant 對應的檔案名稱要改為 zh_Hant):
# default
USE_I18N = True
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', # 要在這裡新增
'django.middleware.common.CommonMiddleware',
... 略 ...
]
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'django.template.context_processors.i18n', # 加這個
... 略 ...

# 網站可支持的語言
from django.utils.translation import gettext_lazy as _
LANGUAGES = (
('en', ('English')),
('zh-hant', _('Traditional Chinese')),
)
# 設置 locale 的路徑
# BASE_DIR =
# os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)

2. template 新增 {% load i18n %}標籤到需要 i18n 功能的頁面(注意:就算是 extends 的頁面也需要加。),並將要翻譯的文字內容改為 {% trans "要翻的內容" %},如變量則不用加引號 {% trans variable %},如下:

{% extends 'base.html' %}
{% load i18n %} // 加這個
....<title>{% trans "This is the title." %}</title>
<title>{% trans variable %}</title>

3. 執行命令 python manage.py makemessages -l <語言>生成對應的副檔名為 po 的檔案(為從原碼提取需要翻譯的字符串列表的檔案,是用來編輯翻譯對應的文字):

python manage.py makemessages -l <語言>

可以看到文件夾的目錄為:

<project>/
- manager.py
- locale/
- zh_Hant/
- LC_MESSAGES/ # 新增
- django.po
- 其他語言/
- settings.py // 修改

比方說在 demo/templates/demo.htm 新增 i18n:

# demo/templates/demo.htm
{% load i18n %}
第 42 行: <h1>{% trans "Traditional Chinese" %}</h1>

執行完生成副檔名為 po 檔案python manage.py makemessages -l zh_Hant的命令後,到 <project>/locale/zh_Hant/LC_MESSAGES/django.po 新增對應的文字:

#: demo/templates/demo.html:42  # 對應的位置
msgid "Traditional Chinese"
msgstr "" # 填入對應的翻譯文字

可以在 msgstr 填入對應的翻譯文字

#: demo/templates/demo.html:42  # 對應的位置
msgid "Traditional Chinese"
msgstr "繁體中文" # 填入對應的翻譯文字

再執行python manage.py compilemessages生成副檔名為 mo 的檔案(mo 為Machine Object 的縮寫,為面向機器、用 msgfmt 將 .po 文件編譯成的二進制文件,無法直接編輯)

可以透過編輯 settings.py 的語言,啟動 Django ,訪問網站就可以看到網站語言的變化喔!

LANGUAGE_CODE = "zh-Hant"

那 views 或 models 的 i18n 呢?

上面說了 template 的 i18n ,那如果想要將 form、views 也加上 i18n 的功能呢?可以用 gettext以 models 為例:可以在 verbose_name (自定義資料庫名稱)加上 _(‘要翻譯的文字’):

from django.utils.translation import gettext as _
class Order(models.Model):
first_name = models.CharField(
max_length=50,
verbose_name=_('First Name') # i18n
)
last_name = models.CharField(
max_length=50,
verbose_name=_('Last Name') # i18n
)

同上執行生成 .po 的文件並加上對應的翻譯再生成 .mo,就有下面的效果喔!

form — i18n

但是……用 gettext 的話只有在切換瀏覽器語言的時候生效,如果是頁面提供選單讓用戶自己切換語言的話,就不會跟改變對應的語言QQ。所以這時候要改用 gettext_lazy,等到字符串上下文的時候才翻譯,一般 models 都用 gettext_lazy

下一篇會說明如何設置以「語言」開頭的 URL 並支持用戶切換語言

--

--