
Django i18n : คู่มือการรองรับหลายภาษาและการแปล
ตั้งแต่ settings.py จนถึงระบบจริง กำหนดค่าระบบแปลของ Django เขียนไฟล์ PO จัดการพหูพจน์ แล้วทำให้การแปลเป็นอัตโนมัติด้วย AI
ติดตั้งและแยกข้อความ
เฟรมเวิร์ก i18n ของ Django มีในตัว เพียงเปิดใช้งาน ติดตั้ง django-locale-chain เพื่อใช้ภาษาสำรองอัจฉริยะ แล้วใช้ makemessages แยกข้อความที่แปลได้จากโค้ด Python กับเทมเพลตลงในไฟล์ PO
pip install django-locale-chain# Extract all translatable strings from Python and template files
python manage.py makemessages -l de -l ja -l es -l fr
# After translating .po files, compile to .mo (binary)
python manage.py compilemessages
# Project structure after running makemessages:
# locale/
# ├── de/
# │ └── LC_MESSAGES/
# │ ├── django.po <-- translate this
# │ └── django.mo <-- compiled (auto-generated)
# ├── ja/
# │ └── LC_MESSAGES/
# │ ├── django.po
# │ └── django.mo
# └── es/
# └── LC_MESSAGES/
# ├── django.po
# └── django.moกำหนดค่าการตั้งค่าและมิดเดิลแวร์
เปิดใช้การรองรับหลายภาษาใน settings.py โดยตั้ง USE_I18N = True กำหนดรายการ LANGUAGES ที่รองรับ และเพิ่ม LocaleMiddleware ลงในสแต็ก MIDDLEWARE LocaleMiddleware ตรวจหาภาษาของผู้ใช้จากคำนำหน้า URL เซสชัน คุกกี้ หรือส่วนหัว Accept-Language
# settings.py
from django.utils.translation import gettext_lazy as _
# Default language
LANGUAGE_CODE = 'en'
# Enable i18n
USE_I18N = True
USE_L10N = True
# Languages your site supports
LANGUAGES = [
('en', _('English')),
('de', _('German')),
('ja', _('Japanese')),
('es', _('Spanish')),
('fr', _('French')),
('pt-br', _('Brazilian Portuguese')),
]
# Where Django looks for .po files
LOCALE_PATHS = [
BASE_DIR / 'locale',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', # <-- enables i18n
'locale_chain.middleware.LocaleChainMiddleware', # <-- smart fallbacks
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]การทำให้ URL รองรับหลายภาษา
ใช้ i18n_patterns() เติมรหัสภาษาปัจจุบันเป็นคำนำหน้า URL โดยอัตโนมัติ แต่ละภาษาจึงมีเนมสเปซ URL ของตัวเอง (/en/about/, /de/about/) ซึ่งดีกว่าสำหรับ SEO และช่วยให้ผู้ใช้แชร์ลิงก์เฉพาะภาษาได้
# urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
urlpatterns = [
# Non-localized URLs (API, admin, etc.)
path('api/', include('api.urls')),
]
urlpatterns += i18n_patterns(
# These get prefixed with the language code: /en/about/, /de/about/
path('', include('myapp.urls')),
path('admin/', admin.site.urls),
prefix_default_language=False, # Skip prefix for default language
)ทำเครื่องหมายข้อความสำหรับแปล
Django มีฟังก์ชันแปลหลักสองแบบ ได้แก่ gettext() ซึ่งมีชื่อย่อ _() สำหรับข้อความที่ประเมินตอนรับคำขอ และ gettext_lazy() สำหรับข้อความที่ประเมินตอนนำเข้า ในเทมเพลตให้ใช้แท็ก {% trans %} และ {% blocktrans %}
ในมุมมอง (โค้ด Python)
from django.utils.translation import gettext as _
from django.utils.translation import ngettext
from django.http import HttpResponse
def greeting_view(request):
# Simple translation
welcome = _("Welcome to our site")
# Translation with variables (Python string formatting)
user_greeting = _("Hello, %(name)s!") % {"name": request.user.username}
# Plurals
count = request.user.order_set.count()
order_text = ngettext(
"You have %(count)d order.",
"You have %(count)d orders.",
count,
) % {"count": count}
return HttpResponse(f"{welcome}<br>{user_greeting}<br>{order_text}")ในเทมเพลต
{# Load the i18n template tags #}
{% load i18n %}
{# Simple translation #}
<h1>{% trans "Welcome to our site" %}</h1>
{# Translation with variables #}
{% blocktrans with name=user.username %}
Hello, {{ name }}!
{% endblocktrans %}
{# Plurals in templates #}
{% blocktrans count count=order_count %}
You have {{ count }} order.
{% plural %}
You have {{ count }} orders.
{% endblocktrans %}
{# Mark strings as translatable but don't output them (for attributes, etc.) #}
{% trans "Submit" as submit_label %}
<button type="submit">{{ submit_label }}</button>ในโมเดลและแบบฟอร์ม
from django.db import models
from django.utils.translation import gettext_lazy as _
class Product(models.Model):
name = models.CharField(_("product name"), max_length=200)
description = models.TextField(_("description"), blank=True)
class Meta:
verbose_name = _("product")
verbose_name_plural = _("products")
def __str__(self):
return self.name
# IMPORTANT: Use gettext_lazy (_) for anything evaluated at import time:
# - Model field labels, verbose_name, help_text
# - Form field labels
# - Class-level attributes
# Use gettext for anything evaluated at request time:
# - View functions, template tagsรูปแบบไฟล์ PO
หลังรัน makemessages Django จะสร้างไฟล์ .po (Portable Object) สำหรับแต่ละภาษา ซึ่งมีคู่ msgid/msgstr ให้แปลค่า msgstr แล้วรัน compilemessages เพื่อสร้างไฟล์ไบนารี .mo ที่ Django อ่านขณะรัน
# locale/de/LC_MESSAGES/django.po
msgid "Welcome to our site"
msgstr "Willkommen auf unserer Seite"
msgid "Hello, %(name)s!"
msgstr "Hallo, %(name)s!"
#, python-format
msgid "You have %(count)d order."
msgid_plural "You have %(count)d orders."
msgstr[0] "Sie haben %(count)d Bestellung."
msgstr[1] "Sie haben %(count)d Bestellungen."
msgid "product name"
msgstr "Produktname"
msgid "description"
msgstr "Beschreibung"
msgid "product"
msgstr "Produkt"
msgid "products"
msgstr "Produkte"
msgid "Submit"
msgstr "Absenden"จัดการพหูพจน์และตัวแปร
Django ใช้ ngettext() สำหรับพหูพจน์ตามกฎพหูพจน์ของ GNU gettext แต่ละภาษากำหนดจำนวนรูปพหูพจน์และสูตรเลือกรูปแบบที่ถูกต้อง ไฟล์ PO ประกาศข้อมูลนี้ด้วยส่วนหัว Plural-Forms
# English: 2 forms (singular, plural)
msgid "%(count)d item"
msgid_plural "%(count)d items"
msgstr[0] "%(count)d item"
msgstr[1] "%(count)d items"
# German: 2 forms (singular, plural)
msgstr[0] "%(count)d Artikel"
msgstr[1] "%(count)d Artikel"
# Russian: 3 forms (one, few, many)
msgstr[0] "%(count)d товар" # 1 item
msgstr[1] "%(count)d товара" # 2-4 items
msgstr[2] "%(count)d товаров" # 5+ items
# Arabic: 6 forms (zero, one, two, few, many, other)
msgstr[0] "لا عناصر" # 0
msgstr[1] "عنصر واحد" # 1
msgstr[2] "عنصران" # 2
msgstr[3] "%(count)d عناصر" # 3-10
msgstr[4] "%(count)d عنصرًا" # 11-99
msgstr[5] "%(count)d عنصر" # 100+
# Japanese: 1 form (no plural distinction)
msgstr[0] "%(count)d個のアイテム"
# In Python code, always use ngettext:
from django.utils.translation import ngettext
msg = ngettext(
"%(count)d item",
"%(count)d items",
count,
) % {"count": count}ทำให้คุณภาพการแปลเป็นอัตโนมัติ
ข้อผิดพลาดที่พบบ่อย
สับสนระหว่าง gettext() กับ gettext_lazy()
ลืมรัน compilemessages
ไม่ได้กำหนดค่า LOCALE_PATHS
ไม่มี i18n_patterns ใน URL
การใช้ภาษาสำรองอัจฉริยะด้วย django-locale-chain
ระบบแปลของ Django จะถอยไปใช้ LANGUAGE_CODE ทันทีเมื่อไม่มีรูปแบบภาษาตามภูมิภาค ผู้ใช้ pt-BR จึงเห็นภาษาอังกฤษแม้มีคำแปล pt-PT django-locale-chain แก้ปัญหานี้ด้วยการติดตั้งลำดับสำรอง gettext โดย pt-BR จะลอง pt-PT แล้ว pt ก่อนถอยไปใช้ภาษาเริ่มต้น
# settings.py -- Smart fallback with django-locale-chain
# pip install django-locale-chain
MIDDLEWARE = [
# ...
'django.middleware.locale.LocaleMiddleware',
'locale_chain.middleware.LocaleChainMiddleware', # after LocaleMiddleware
# ...
]
# That's it! 75 built-in fallback chains are now active:
# pt-BR user → tries pt-PT → tries pt → falls back to LANGUAGE_CODE
# es-MX user → tries es-419 → tries es → falls back to LANGUAGE_CODE
# fr-CA user → tries fr → falls back to LANGUAGE_CODE
# Optional: customize specific chains
LOCALE_FALLBACK_CHAINS = {
"pt-BR": ["pt-PT", "pt"],
"es-MX": ["es-419", "es"],
"fr-CA": ["fr"],
}
# Or configure programmatically in AppConfig.ready():
from locale_chain import configure
class MyAppConfig(AppConfig):
name = "myapp"
def ready(self):
configure(overrides={"zh-Hant-HK": ["zh-Hant-TW", "zh-Hant"]})โครงสร้างโปรเจกต์ที่แนะนำ
myproject/
├── myproject/
│ ├── settings.py # i18n config, MIDDLEWARE, LANGUAGES
│ ├── urls.py # i18n_patterns for URL prefixing
│ └── wsgi.py
├── myapp/
│ ├── models.py # gettext_lazy for field labels
│ ├── views.py # gettext for request-time strings
│ └── templates/
│ └── myapp/
│ └── index.html # {% load i18n %}, {% trans %}, {% blocktrans %}
├── locale/ # Created by makemessages
│ ├── de/
│ │ └── LC_MESSAGES/
│ │ ├── django.po # German translations
│ │ └── django.mo # Compiled binary
│ ├── ja/
│ │ └── LC_MESSAGES/
│ │ ├── django.po
│ │ └── django.mo
│ └── es/
│ └── LC_MESSAGES/
│ ├── django.po
│ └── django.mo
├── manage.py
└── requirements.txtแปลรายการต่อไปนี้ได้ด้วย :
ลองใช้ i18n Agent ตอนนี้
ลากและวางไฟล์แปลของคุณที่นี่
JSON, YAML, PO, XML, CSV, Markdown, Properties
หรือคลิกเพื่อเลือกไฟล์
ภาษาเป้าหมาย
การใช้ภาษาสำรองด้วย django-locale-chain
เมื่อไม่มีคีย์คำแปลในภาษาตามภูมิภาคอย่าง pt-BR Django จะข้ามไปใช้ภาษาเทมเพลตทันทีแทนที่จะตรวจภาษาหลัก pt ก่อน
pip install django-locale-chain# settings.py
LOCALE_CHAINS = {
'pt-BR': ['pt', 'es', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
}
MIDDLEWARE = [
...
'django_locale_chain.middleware.LocaleChainMiddleware',
...
]ดูคู่มือการใช้ภาษาสำรองของเราสำหรับรายการเฟรมเวิร์กที่รองรับทั้งหมดและลำดับสำเร็จรูป 75 รายการ Learn more →