{"id":247,"date":"2016-07-27T16:42:47","date_gmt":"2016-07-27T08:42:47","guid":{"rendered":"https:\/\/vinta.ws\/code\/?p=247"},"modified":"2026-03-16T23:37:18","modified_gmt":"2026-03-16T15:37:18","slug":"i18n-translation-in-django","status":"publish","type":"post","link":"https:\/\/vinta.ws\/code\/i18n-translation-in-django.html","title":{"rendered":"Configure i18n Translations in Django"},"content":{"rendered":"<p>Internationalization and localization for your Django project.<\/p>\n<h2>Configuration<\/h2>\n<p>in settings.py<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">USE_I18N = True\n\n# Django 1.6 \u8981\u7528 'zh-tw' \u6216 'zh-cn'\n# Django 1.7+ \u8981\u7528 'zh-hant' \u6216 'zh-hans'\nLANGUAGE_CODE = 'zh-hant'\n\nLANGUAGES = (\n    ('en', 'English'),\n    ('zh-hans', 'Simplified Chinese'),\n    ('zh-hant', 'Traditional Chinese'),\n)\n\nLOCALE_PATHS = (\n    os.path.join(BASE_DIR, 'locale\/'),\n)\n\n# \u8981\u8a18\u5f97\u52a0\u4e0a LocaleMiddleware\uff0c\u624d\u6703\u91dd\u5c0d request headers \u4f7f\u7528\u5c0d\u61c9\u7684\u8a9e\u8a00\nMIDDLEWARE_CLASSES = (\n    ...\n    'django.middleware.locale.LocaleMiddleware',\n    ...\n)<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/settings\/#languages\">https:\/\/docs.djangoproject.com\/en\/dev\/ref\/settings\/#languages<\/a><br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#how-django-discovers-language-preference\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#how-django-discovers-language-preference<\/a><\/p>\n<p>in urls.py<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">urlpatterns = patterns('',\n    ...\n    url(r'^i18n\/', include('django.conf.urls.i18n')),\n    ...\n)<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#the-set-language-redirect-view\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#the-set-language-redirect-view<\/a><\/p>\n<h2>Usage<\/h2>\n<p>\u5728 models.py \u4e2d\u901a\u5e38\u90fd\u6703\u4f7f\u7528 <code>ugettext_lazy()<\/code> \u800c\u4e0d\u662f <code>ugettext()<\/code>\u3002\u56e0\u70ba gettext_lazy() \u5176\u4e2d\u7684\u503c\u662f\u5728\u88ab\u8a2a\u554f\u7684\u6642\u5019\u624d\u7ffb\u8b6f\uff0c\u800c\u4e0d\u662f\u5728\u547c\u53eb gettext_lazy() \u7684\u6642\u5019\u5c31\u7ffb\u8b6f\u3002\u53e6\u5916\uff0c<code>ugettext()<\/code> \u548c <code>ugettext_lazy()<\/code> \u51fa\u4f86\u7684\u5b57\u4e32\u90fd\u662f unicode\u3002<code>pgettext()<\/code> \u7684\u4f5c\u7528\u8ddf ugettext() \u4e00\u6a23\uff0c\u53ea\u662f\u591a\u4e86\u4e00\u500b\u53c3\u6578\u53ef\u4ee5\u50b3 context \u9032\u53bb\u3002<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#lazy-translation\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#lazy-translation<\/a><br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/utils\/#django.utils.translation.pgettext\">https:\/\/docs.djangoproject.com\/en\/dev\/ref\/utils\/#django.utils.translation.pgettext<\/a><\/p>\n<p>\u8981\u5728 <code>ugettext()<\/code> \u4e2d\u4f7f\u7528 string format\uff0c\u5fc5\u9808\u8981\u7528\u4ee5\u4e0b\u7684\u5f62\u5f0f\uff1a<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">msg = _(u'\u60a8\u6709 %(not_ready_count)s \u9805\u884c\u7a0b\u7684\u5c1a\u672a\u586b\u5beb\u300c\u53f8\u6a5f\u5099\u5fd8\u9304\u300d\u3002') % {'not_ready_count': not_ready_count}<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#internationalization-in-python-code\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#internationalization-in-python-code<\/a><\/p>\n<p>in base.html<\/p>\n<pre class=\"line-numbers\"><code class=\"language-html\">{% load i18n %}\n\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;meta charset=\"utf-8\"&gt;\n    &lt;title&gt;Heelstagram&lt;\/title&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n    {% block content %}{% endblock %}\n\n    &lt;form action=\"\/i18n\/setlang\/\" method=\"POST\"&gt;\n      {% csrf_token %}\n      &lt;input name=\"next\" type=\"hidden\" value=\"{{ redirect_to }}\" \/&gt;\n      &lt;select name=\"language\"&gt;\n      {% get_language_info_list for LANGUAGES as LANGUAGES %}\n      {% for language in LANGUAGES %}\n        &lt;option value=\"{{ language.code }}\"&gt;{{ language.name_local }} ({{ language.code }})&lt;\/option&gt;\n      {% endfor %}\n      &lt;\/select&gt;\n      &lt;input type=\"submit\" value=\"{% trans 'Change Language' %}\" \/&gt;\n    &lt;\/form&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n<p>in home.html<\/p>\n<pre class=\"line-numbers\"><code class=\"language-html\">{% extends 'base.html' %}\n\n{# \u5373\u4f7f base.html \u5df2\u7d93 load i18n \u4e86\uff0c\u5728\u6bcf\u500b template \u9084\u662f\u5f97\u5728 load \u4e00\u6b21 #}\n{% load i18n %}\n\n{% block content %}\n&lt;p&gt;current language: \"{{ LANGUAGE_CODE }}\"&lt;\/p&gt;\n\n{# \u5728 .po \u4e2d\u6703\u8868\u793a\u70ba msgid \"string 1\" #}\n&lt;p&gt;1: {{ VAR_1 }} \u6703\u88ab\u7ffb\u8b6f&lt;\/p&gt;\n\n{# \u9019\u5169\u884c\u662f\u7b49\u50f9\u7684\uff0c\u5728 .po \u4e2d\u6703\u8868\u793a\u70ba msgid \"string 3\" #}\n&lt;p&gt;2: {% trans VAR_3 %} \u6703\u88ab\u7ffb\u8b6f&lt;\/p&gt;\n&lt;p&gt;3: {% trans \"string 3\" %} \u6703\u88ab\u7ffb\u8b6f&lt;\/p&gt;\n\n{# \u5728 .po \u4e2d\u6703\u8868\u793a\u70ba\uff1a #}\n{# msgctxt \"\u8aaa\u660e\u7684\u6587\u5b57\" #}\n{# msgid \"User\" #}\n&lt;p&gt;4: {% trans 'User' context '\u8aaa\u660e\u7684\u6587\u5b57' %} \u6703\u88ab\u7ffb\u8b6f&lt;\/p&gt;\n\n&lt;p&gt;5: {{ VAR_3 }} \u4e0d\u6703\u88ab\u7ffb\u8b6f&lt;\/p&gt;\n\n{# \u5728 .po \u4e2d\u6703\u8868\u793a\u70ba msgid \"%(VAR_2)s \u9019\u6574\u53e5\u6703\u88ab\u7ffb\u8b6f\uff0c\u5305\u542b VAR_2 \u7684\u503c\" #}\n{# VAR_2 \u4e5f\u6703\u88ab\u7ffb\u8b6f\u662f\u56e0\u70ba\u5b83\u7b49\u65bc _('string 2') #}\n{# blocktrans \u4e2d\u7684\u8b8a\u6578\u4e0d\u80fd\u662f artist.name \u9019\u7a2e\u5f62\u5f0f\uff0c\u5fc5\u9808\u7528 artist_name \u6216\u662f with #}\n&lt;p&gt;6: {% blocktrans %}{{ VAR_2 }} \u9019\u6574\u53e5\u6703\u88ab\u7ffb\u8b6f\uff0c\u5305\u542b VAR_2 \u7684\u503c{% endblocktrans %}&lt;\/p&gt;\n\n{# VAR_4 \u4e0d\u6703\u88ab\u7ffb\u8b6f\u662f\u56e0\u70ba\u5b83\u7b49\u65bc 'string 4'\uff0c\u53ea\u662f\u4e00\u500b\u55ae\u7d14\u7684\u5b57\u4e32 #}\n&lt;p&gt;7: {% blocktrans %}{{ VAR_4 }} \u9019\u6574\u53e5\u6703\u88ab\u7ffb\u8b6f\uff0c\u4f46\u662f\u4e0d\u5305\u542b VAR_4 \u7684\u503c{% endblocktrans %}&lt;\/p&gt;\n{% endblock %}<\/code><\/pre>\n<p><code>blocktrans<\/code> \u7684\u4f5c\u7528\u662f\u8b93\u4f60\u5728\u7ffb\u8b6f\u5b57\u4e32\u4e2d\u63d2\u5165 template contexts \u8b8a\u6578\u3002<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#trans-template-tag\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#trans-template-tag<\/a><br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#internationalization-in-template-code\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#internationalization-in-template-code<\/a><\/p>\n<h2>Create Language Files<\/h2>\n<p>\u8981\u5148\u5b89\u88dd <code>gettext<\/code>\uff0c\u5426\u5247\u6703\u51fa\u73fe <code>\/bin\/sh: xgettext: command not found<\/code> \u7684\u932f\u8aa4<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\"># \u5fc5\u9808\u624b\u52d5\u5efa\u7acb locale \u76ee\u9304\uff08\u653e\u5728 project \u6216 app \u7684\u6839\u76ee\u9304\uff09\n$ mkdir -p locale\n\n# \u7b2c\u4e00\u6b21\u57f7\u884c\uff0c\u5fc5\u9808\u6307\u5b9a locale name\uff0c\u4e0d\u80fd\u76f4\u63a5\u7528 <code>-a<\/code> \u53c3\u6578\uff0c\u9019\u6a23\u624d\u6703\u5728 locale \u5e95\u4e0b\u7522\u751f\u76f8\u5c0d\u61c9\u7684\u76ee\u9304\n# \u6ce8\u610f\uff01\u662f zh_TW \u800c\u4e0d\u662f zh-tw\n# \u5728\u5c08\u6848\u6839\u76ee\u9304\u57f7\u884c makemessages \u5c31\u662f\u5c0d\u6574\u500b\u5c08\u6848\u7684\u6240\u6709 apps \u7522\u751f\u7ffb\u8b6f\u6a94\u6848\n$ .\/manage.py makemessages -l en\n$ .\/manage.py makemessages -l ja\n$ .\/manage.py makemessages -l zh_CN\n$ .\/manage.py makemessages -l zh_TW\n$ .\/manage.py makemessages -l zh_Hans\n$ .\/manage.py makemessages -l zh_Hant\n$ .\/manage.py makemessages --all\n\n# .js \u7684\u7ffb\u8b6f\u8981\u984d\u5916\u6307\u5b9a <code>-d djangojs<\/code> \u624d\u6703\u7522\u751f djangojs.po\n$ .\/manage.py makemessages -l zh_Hant -d djangojs --ignore=node_modules\n\n# \u5982\u679c\u4f60\u7684 django.po \u88e1\u6709\u4e9b\u5b57\u4e32\u88ab\u6a19\u8a18\u70ba <code>#, fuzzy<\/code> \u7684\u8a71\uff0c\u8981\u8a18\u5f97\u522a\u6389\uff0c\u5426\u5247\u8a72\u5b57\u4e32\u4e0d\u6703\u88ab\u7ffb\u8b6f\n$ .\/manage.py compilemessages\n\n# \u53ea\u5c0d\u7279\u5b9a app \u7522\u751f\u7ffb\u8b6f\u6a94\u6848\n$ cd your_app\n$ django-admin.py makemessages -l zh_Hant\n$ django-admin.py compilemessages<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#localization-how-to-create-language-files\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#localization-how-to-create-language-files<\/a><br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/django-admin\/#makemessages\">https:\/\/docs.djangoproject.com\/en\/dev\/ref\/django-admin\/#makemessages<\/a><\/p>\n<p>\u6bcf\u6b21 compilemessages \u5b8c\u8981\u8a18\u5f97\u91cd\u555f server<\/p>\n<h2>How Django discovers translations<\/h2>\n<p><code>django-admin.py makemessages -a<\/code> \u9019\u500b\u6307\u4ee4\u6703\u53bb\u6536\u96c6\u6574\u500b project \u88e1\u7684\u6240\u6709 apps \u7684 locale \u5b57\u4e32\u3002<br \/>\n\u512a\u5148\u6b0a\u6700\u9ad8\u7684\u662f <code>LOCALE_PATHS<\/code> \u5b9a\u7fa9\u7684\u90a3\u500b\u76ee\u9304\uff0c\u627e\u4e0d\u5230\u7684\u8a71\u624d\u6703\u53bb\u627e\u500b\u5225 app \u4e4b\u4e0b\u7684 locale \u76ee\u9304\u3002<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#how-django-discovers-translations\">https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/translation\/#how-django-discovers-translations<\/a><\/p>\n<h2>\u5f37\u5236\u4f7f\u7528\u67d0\u7a2e\u8a9e\u8a00<\/h2>\n<p>\u9664\u4e86\u53ef\u4ee5\u7528\u4e0a\u9762\u90a3\u500b <code>\/i18n\/setlang\/<\/code> \u7684 form \u8868\u55ae\u4e4b\u5916\uff0c\u4e5f\u53ef\u4ee5\u5728 views \u88e1\u9762\u9019\u6a23\u5beb\uff1a<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">from django.shortcuts import render_to_response\nfrom django.template import RequestContext\nfrom django.utils.translation import activate\nfrom django.utils.translation import ugettext as _\n\ndef common_processor(request):\n    contexts = {\n        'T1': _('string 1'),\n    }\n\n    return contexts\n\ndef home(request):\n    activate('zh-tw')  # \u5f37\u5236\u4f7f\u7528\u6b63\u9ad4\u4e2d\u6587\uff0c\u8986\u84cb\u6389 user \u548c browser \u7684\u8a2d\u5b9a\n\n    contexts = {\n        'T2': _('string 2'),\n        'T3': 'string 3',\n    }\n\n    return render_to_response('home.html', contexts, RequestContext(request, processors=[common_processor]))<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/utils\/#module-django.utils.translation\">https:\/\/docs.djangoproject.com\/en\/dev\/ref\/utils\/#module-django.utils.translation<\/a><\/p>\n<h2>JavaScript<\/h2>\n<p>in urls.py<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">urlpatterns = patterns(\n    '',\n    ...\n    url(r'^jsi18n\/$', 'django.views.i18n.javascript_catalog'),\n    ...\n)<\/code><\/pre>\n<p>in your_shit.html<\/p>\n<pre class=\"line-numbers\"><code class=\"language-html\">&lt;script src=\"{% url 'django.views.i18n.javascript_catalog' %}\"&gt;&lt;\/script&gt;\n&lt;script&gt;\n    var text = gettext('\u8981\u88ab\u7ffb\u8b6f\u7684\u5b57\u4e32');\n&lt;\/script&gt;<\/code><\/pre>\n<p>\u662f <code>gettext()<\/code> \u800c\u4e0d\u662f <code>ugettext()<\/code><\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\"># \u8981\u52a0\u4e0a -d djangojs \u624d\u6703\u53bb parse .js \u88e1\u7684\u5b57\u4e32\n$ .\/manage.py makemessages --all -d djangojs<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Internationalization and localization for your Django project.<\/p>\n","protected":false},"author":1,"featured_media":760,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,116],"tags":[13,2],"class_list":["post-247","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-about-python","category-about-web-development","tag-django","tag-python"],"_links":{"self":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/247","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/comments?post=247"}],"version-history":[{"count":0,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/247\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media\/760"}],"wp:attachment":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media?parent=247"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/categories?post=247"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/tags?post=247"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}