埋坑: Django 多國語言

資料夾殺人事件

Lililala
6 min readDec 23, 2018

其實照著官方文件一步一步做不會有什麼問題,只是沒想到….

本文 Django 對應 2 版

  1. 首先照著以下標準步驟設定 Settings:
# 不用解釋
USE_I18N = True
# 非必要、預設網站語言
LANGUAGE_CODE = 'zh-hant'
# 非必要、方便做語言選單用的
from django.utils.translation import gettext_lazy as _
LANGUAGES = (
('en', _('English')),
('zh-hans', _('Simplified Chinese')),
('zh-hant', _('Traditional Chinese')),
)
# 設定我們的語言檔案所放的路徑
# 此例採用 Two Scoops 的結構, locale 放在:
#
{專案路徑}/locale
# 因設定檔路徑如下,所以 -3 將設定檔路徑前移為 {專案路徑}/ 作為 ROOT_DIR
#
{專案路徑}/config/settings/{設定檔}.py
ROOT_DIR = environ.Path(__file__) - 3
LOCALE_PATHS = (
os.path.join(ROOT_DIR, 'locale'),
)
# 加入 LocaleMiddleware 至 SessionMiddleware 與 CommonMiddleware 之間
MIDDLEWARE = [
# 其他 ...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
# 其他 ...
]
# Templates 設定中加上 i18n 的 context processors
TEMPLATES = [
{
# 其他 ...
'OPTIONS': {
'context_processors': [
# 其他 ...
'django.template.context_processors.i18n',
],
},
},
]

2. 接著我們利用 Django 整合好 GNU gettext 的命令列工具,將專案中標註為須翻譯的字串轉出至 PO 檔格式:

django-admin makemessages -l en
django-admin makemessages -l zh_Hans
django-admin makemessages -l zh_Hant
# 初始化,以後用 django-admin makemessages 即可更新
# JS 的部分則須指定 domain 用 django-admin makemessages -d djangojs

原始碼中標註方式如gettext(), gettext_lazy(), {% trans "mystr"%}等超出本文範圍,請參照 官方文件

關於 gettext:
● Windows 上需 安裝編譯好的 gettext
● OSX 上安裝指令 brew link gettext --force

3. 翻譯轉出的 PO 檔內容,如 locale/zh_Hant/LC_MESSAGES/django.po

#: .\my_project\supplier\models.py:115
msgid "supplier"
msgstr "供應商"

4. 將 PO檔編譯成高效的 MO 二進位檔案。

django-admin compilemessages

5. 其他課題如【用 session 切換語言】【用 cookie 儲存使用者選擇的語言】【翻譯前端 Javascript code】【多語URL的處理】就不再此詳述,教學非本篇重點。

😵😵問題來了,Language Code 明明是zh-hantzh-hans,為啥資料夾要用zh_Hantzh_Hans,Django 才能成功地找到翻譯檔?

魔鬼藏在細節裡

Django 的 i18n 直接套 python 使用的 GNU gettext 標準,其語言檔的目錄結構為: {設定路徑}/{語言碼}_{國碼}或{語言碼}/LC_MESSAGES/*.mo

例如 Django admin source code 中的 locale 結構:

https://github.com/django/django/tree/master/django/contrib/admin/locale

華語國家、地域、文化傻傻分不清的特殊性/政治性,有許多約定成俗的名稱如 zh-TWzh-CNzh-HKzh-SG等,如果不想細分,就如統一使用 zh-Hant (繁/正體)、zh-Hans(簡體) 兩者即可。

其行為如瀏覽器發出標頭:
Accept-Language:zh-TW
Django 內部使用 fallback key 轉換 zh-twzh-hant 後回應:
Content-Language:zh-Hant

也因採用 gettext 的目錄結構, Django 模組 translation.trans_real會將破折號的分隔符號均被轉成底線,再傳給 gettext.translation()作為找到 MO 檔路徑之一。

規則在原始碼的註解中寫得很清楚,例 zh-hant → zh_Hant、zh-tw → zh_TW

就因為這個不重造輪子的轉換過程,不明所以的整台車卡在坑裡 (茶~~~

2020/5/18 坑 2

若遭遇 JS Template literals 寫法 gettext() 抓不到翻譯 Key 時,請將 gettext 升級至 0.20.2 以後的版本 (bug #56678, Wrong behaviour of template strings)

--

--

Lililala
Lililala

Written by Lililala

技能樹越點越歪的 Software Architect (Fullstacker for fun)、大自然狂熱愛好者、V豚、不認真的貓蛋劊子手。不特定反SEO佛系寫作

Responses (1)