Internationalization and localization for your Django project.
Configuration
in settings.py
USE_I18N = True
# Django 1.6 要用 'zh-tw' 或 'zh-cn'
# Django 1.7+ 要用 'zh-hant' 或 'zh-hans'
LANGUAGE_CODE = 'zh-hant'
LANGUAGES = (
('en', 'English'),
('zh-hans', 'Simplified Chinese'),
('zh-hant', 'Traditional Chinese'),
)
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale/'),
)
# 要記得加上 LocaleMiddleware,才會針對 request headers 使用對應的語言
MIDDLEWARE_CLASSES = (
...
'django.middleware.locale.LocaleMiddleware',
...
)
ref:
https://docs.djangoproject.com/en/dev/ref/settings/#languages
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-language-preference
in urls.py
urlpatterns = patterns('',
...
url(r'^i18n/', include('django.conf.urls.i18n')),
...
)
ref:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#the-set-language-redirect-view
Usage
在 models.py 中通常都會使用 ugettext_lazy()
而不是 ugettext()
。因為 gettext_lazy() 其中的值是在被訪問的時候才翻譯,而不是在呼叫 gettext_lazy() 的時候就翻譯。另外,ugettext()
和 ugettext_lazy()
出來的字串都是 unicode。pgettext()
的作用跟 ugettext() 一樣,只是多了一個參數可以傳 context 進去。
ref:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#lazy-translation
https://docs.djangoproject.com/en/dev/ref/utils/#django.utils.translation.pgettext
要在 ugettext()
中使用 string format,必須要用以下的形式:
msg = _(u'您有 %(not_ready_count)s 項行程的尚未填寫「司機備忘錄」。') % {'not_ready_count': not_ready_count}
ref:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#internationalization-in-python-code
in base.html
{% load i18n %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Heelstagram</title>
</head>
<body>
{% block content %}{% endblock %}
<form action="/i18n/setlang/" method="POST">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_language_info_list for LANGUAGES as LANGUAGES %}
{% for language in LANGUAGES %}
<option value="{{ language.code }}">{{ language.name_local }} ({{ language.code }})</option>
{% endfor %}
</select>
<input type="submit" value="{% trans 'Change Language' %}" />
</form>
</body>
</html>
in home.html
{% extends 'base.html' %}
{# 即使 base.html 已經 load i18n 了,在每個 template 還是得在 load 一次 #}
{% load i18n %}
{% block content %}
<p>current language: "{{ LANGUAGE_CODE }}"</p>
{# 在 .po 中會表示為 msgid "string 1" #}
<p>1: {{ VAR_1 }} 會被翻譯</p>
{# 這兩行是等價的,在 .po 中會表示為 msgid "string 3" #}
<p>2: {% trans VAR_3 %} 會被翻譯</p>
<p>3: {% trans "string 3" %} 會被翻譯</p>
{# 在 .po 中會表示為: #}
{# msgctxt "說明的文字" #}
{# msgid "User" #}
<p>4: {% trans 'User' context '說明的文字' %} 會被翻譯</p>
<p>5: {{ VAR_3 }} 不會被翻譯</p>
{# 在 .po 中會表示為 msgid "%(VAR_2)s 這整句會被翻譯,包含 VAR_2 的值" #}
{# VAR_2 也會被翻譯是因為它等於 _('string 2') #}
{# blocktrans 中的變數不能是 artist.name 這種形式,必須用 artist_name 或是 with #}
<p>6: {% blocktrans %}{{ VAR_2 }} 這整句會被翻譯,包含 VAR_2 的值{% endblocktrans %}</p>
{# VAR_4 不會被翻譯是因為它等於 'string 4',只是一個單純的字串 #}
<p>7: {% blocktrans %}{{ VAR_4 }} 這整句會被翻譯,但是不包含 VAR_4 的值{% endblocktrans %}</p>
{% endblock %}
blocktrans
的作用是讓你在翻譯字串中插入 template contexts 變數。
ref:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#trans-template-tag
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#internationalization-in-template-code
Create Language Files
要先安裝 gettext
,否則會出現 /bin/sh: xgettext: command not found
的錯誤
# 必須手動建立 locale 目錄(放在 project 或 app 的根目錄)
$ mkdir -p locale
# 第一次執行,必須指定 locale name,不能直接用 `-a` 參數,這樣才會在 locale 底下產生相對應的目錄
# 注意!是 zh_TW 而不是 zh-tw
# 在專案根目錄執行 makemessages 就是對整個專案的所有 apps 產生翻譯檔案
$ ./manage.py makemessages -l en
$ ./manage.py makemessages -l ja
$ ./manage.py makemessages -l zh_CN
$ ./manage.py makemessages -l zh_TW
$ ./manage.py makemessages -l zh_Hans
$ ./manage.py makemessages -l zh_Hant
$ ./manage.py makemessages --all
# .js 的翻譯要額外指定 `-d djangojs` 才會產生 djangojs.po
$ ./manage.py makemessages -l zh_Hant -d djangojs --ignore=node_modules
# 如果你的 django.po 裡有些字串被標記為 `#, fuzzy` 的話,要記得刪掉,否則該字串不會被翻譯
$ ./manage.py compilemessages
# 只對特定 app 產生翻譯檔案
$ cd your_app
$ django-admin.py makemessages -l zh_Hant
$ django-admin.py compilemessages
ref:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#localization-how-to-create-language-files
https://docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
每次 compilemessages 完要記得重啟 server
How Django discovers translations
django-admin.py makemessages -a
這個指令會去收集整個 project 裡的所有 apps 的 locale 字串。
優先權最高的是 LOCALE_PATHS
定義的那個目錄,找不到的話才會去找個別 app 之下的 locale 目錄。
ref:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#how-django-discovers-translations
強制使用某種語言
除了可以用上面那個 /i18n/setlang/
的 form 表單之外,也可以在 views 裡面這樣寫:
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.translation import activate
from django.utils.translation import ugettext as _
def common_processor(request):
contexts = {
'T1': _('string 1'),
}
return contexts
def home(request):
activate('zh-tw') # 強制使用正體中文,覆蓋掉 user 和 browser 的設定
contexts = {
'T2': _('string 2'),
'T3': 'string 3',
}
return render_to_response('home.html', contexts, RequestContext(request, processors=[common_processor]))
ref:
https://docs.djangoproject.com/en/dev/ref/utils/#module-django.utils.translation
JavaScript
in urls.py
urlpatterns = patterns(
'',
...
url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog'),
...
)
in your_shit.html
<script src="{% url 'django.views.i18n.javascript_catalog' %}"></script>
<script>
var text = gettext('要被翻譯的字串');
</script>
是 gettext()
而不是 ugettext()
# 要加上 -d djangojs 才會去 parse .js 裡的字串
$ ./manage.py makemessages --all -d djangojs