Quay lại blog

Tại sao Bản dịch Django Bị Lỗi (và Cách Khắc phục 10 Nguyên nhân Phổ biến Nhất)

2026-02-04 Đọc 12 phút
Tại sao Bản dịch Django Bị Lỗi (và Cách Khắc phục 10 Nguyên nhân Phổ biến Nhất)

Ban da danh dau cac chuoi de dich, tao file .po, chay compilemessages, va ung dung cua ban van hien thi tieng Anh. Ban khong don doc. Framework i18n cua Django rat manh me, nhung no co nhung canh sac ben ma ngay ca cac lap trinh vien co kinh nghiem cung mac phai.

Huong dan nay bao gom 10 ly do pho bien nhat khien ban dich Django that bai mot cach tham lang, voi cac trieu chung chinh xac va cach khac phuc cho tung truong hop.

1. Quen chay compilemessages sau khi chinh sua file .po

Ban da chinh sua mot file .po (thu cong hoac bang cong cu), nhung van ban da dich khong bao gio xuat hien. Ung dung tiep tuc hien thi cac chuoi tieng Anh goc.

Django khong doc file .po khi chay. No doc cac file nhi phan .mo (machine object) da bien dich. Neu ban chinh sua file .po ma khong bien dich lai, Django khong biet gi da thay doi.

Chay compilemessages sau moi thay doi file .po:

python manage.py compilemessages

Neu ban tu dong hoa ban dich voi TranslateBot, them compilemessages la buoc cuoi cung trong quy trinh lam viec cua ban:

python manage.py makemessages -a --no-obsolete
python manage.py translate
python manage.py compilemessages

2. Thieu {% load i18n %} trong template

Ban su dung {% trans "Hello" %} trong template, nhung Django nem ra TemplateSyntaxError. Hoac toi te hon, the khong lam gi mot cach tham lang neu ban co mot template engine duoc cau hinh sai.

Cac the {% trans %} va {% blocktrans %} nam trong thu vien the template i18n cua Django. Khong tai no, template engine khong nhan dien duoc chung.

Them {% load i18n %} o dau moi template su dung cac the dich:

{% load i18n %}

<h1>{% trans "Welcome to our site" %}</h1>
<p>{% blocktrans with name=user.name %}Hello, {{ name }}!{% endblocktrans %}</p>

Day la yeu cau cho tung template. Ngay ca khi template cha tai i18n, cac template con su dung cac the dich can khai bao {% load i18n %} rieng cua chung.

3. LocaleMiddleware khong co trong MIDDLEWARE hoac o vi tri sai

Django luon phuc vu noi dung bang ngon ngu mac dinh bat ke header Accept-Language cua trinh duyet, tien to URL, hoac cai dat phien.

LocaleMiddleware xac dinh ngon ngu hoat dong cho moi yeu cau. Khong co no, Django mac dinh su dung LANGUAGE_CODE va bo qua tat ca cac co che chon ngon ngu. Vi tri cua no trong middleware stack cung quan trong, vi no can truy cap vao du lieu phien va phan giai URL.

Them LocaleMiddleware vao cai dat MIDDLEWARE cua ban, sau SessionMiddleware va CommonMiddleware:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.locale.LocaleMiddleware",  # Must be after SessionMiddleware
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
]

Cung dam bao django.conf.urls.i18n duoc bao gom trong cau hinh URL cua ban neu ban su dung chuyen doi ngon ngu dua tren URL:

from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path("", include("myapp.urls")),
)

4. Ma ngon ngu khong khop (vd. pt-br vs pt_BR)

Ban dich ton tai trong file .po, compilemessages thanh cong, nhung Django bo qua ban dich cho mot so locale nhat dinh.

Django mong doi cac thu muc locale theo dinh dang <language>_<COUNTRY> voi dau gach duoi va ma quoc gia viet hoa. Vi du, pt_BR cho tieng Bo Dao Nha Brazil. Neu thu muc cua ban duoc dat ten la pt-br, pt-BR, hoac ptBR, Django se khong tim thay no. Dieu tuong tu ap dung cho cai dat LANGUAGES: cac ma o do su dung gach noi (pt-br), nhung he thong file su dung gach duoi (pt_BR).

Dam bao cau truc thu muc cua ban khop voi ky vong cua Django:

locale/
    pt_BR/
        LC_MESSAGES/
            django.po
            django.mo

Va trong cai dat cua ban, su dung dang co gach noi:

LANGUAGES = [
    ("en", "English"),
    ("pt-br", "Brazilian Portuguese"),
    ("zh-hans", "Simplified Chinese"),
]

Khi chay makemessages, su dung dang gach duoi cho co locale:

python manage.py makemessages -l pt_BR

5. Cac muc fuzzy bi bo qua tham lang trong qua trinh bien dich

Ban dich ton tai trong file .po, nhung Django hien thi chuoi tieng Anh goc khi chay cho muc cu the do. Dieu nay dac biet kho chiu vi ban dich nam ngay trong file.

Khi makemessages cua Django phat hien chuoi nguon da thay doi nhe, no danh dau ban dich hien tai la "fuzzy" (nghia la no la mot du doan can duoc nguoi xem xet). Lenh compilemessages bo qua tat ca cac muc fuzzy, coi chung la chua duoc dich. Vay muc do trong nhu da duoc dich trong file .po, nhung file .mo loai tru hoan toan no.

Mot muc fuzzy trong nhu the nay:

#, fuzzy
msgid "Welcome to our website!"
msgstr "Welkom op onze website!"

Xem xet ban dich, cap nhat msgstr neu can, sau do xoa co #, fuzzy:

msgid "Welcome to our website!"
msgstr "Welkom op onze website!"

Sau do bien dich lai:

python manage.py compilemessages

Trong mot du an lon hon, cac muc fuzzy tich tu va de bi bo sot. Lenh check_translations cua TranslateBot tu dong bat chung:

python manage.py check_translations
locale/nl/LC_MESSAGES/django.po: 0 untranslated, 3 fuzzy
CommandError: Translation check failed

Them no vao pipeline CI cua ban voi check_translations --makemessages va ban se khong bao gio ship mot muc fuzzy nua.

6. LOCALE_PATHS khong duoc cau hinh hoac tro den thu muc sai

makemessages tao file .po o mot vi tri, nhung Django tim chung o noi khac. Ban dich ton tai tren dia nhung khong bao gio duoc tai.

Django tim kiem file dich theo thu tu cu the: thu muc LOCALE_PATHS truoc, sau do thu muc locale/ cua tung ung dung, va cuoi cung la thu muc locale/ cua du an. Neu LOCALE_PATHS khong duoc thiet lap hoac tro den duong dan sai, Django co the khong bao gio tim thay file .po cua ban.

Dat LOCALE_PATHS trong cai dat cua ban thanh duong dan tuyet doi:

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

LOCALE_PATHS = [
    BASE_DIR / "locale",
]

Xac minh rang thu muc ton tai va chua cau truc mong doi:

locale/
    de/
        LC_MESSAGES/
            django.po
            django.mo
    nl/
        LC_MESSAGES/
            django.po
            django.mo

Mot loi pho bien la dat LOCALE_PATHS thanh locale/ (tuong doi) thay vi duong dan tuyet doi. Django khong giai quyet duong dan tuong doi tu thu muc goc du an cua ban. No phu thuoc vao thu muc lam viec cua tien trinh, thuong khong phai la nhung gi ban mong doi.

7. Cache phuc vu ban dich cu

Ban da cap nhat va bien dich ban dich, nhung van ban cu van xuat hien. Khoi dong lai may chu se khac phuc.

Danh muc ban dich cua Django duoc tai mot lan cho moi tien trinh. Trong moi truong san xuat, cac may chu WSGI/ASGI nhu Gunicorn hoac Uvicorn giu cac tien trinh worker song trong thoi gian dai. File .mo co the da thay doi tren dia, nhung tien trinh dang chay van giu ban dich cu trong bo nho. Ngoai ra, neu ban su dung framework cache cua Django hoac reverse proxy nhu Nginx hoac Cloudflare, cac phan hoi da cache se phuc vu noi dung cu cho den khi het han.

Khoi dong lai may chu ung dung sau khi trien khai ban dich moi:

# Gunicorn
kill -HUP $(cat /tmp/gunicorn.pid)

# Systemd
sudo systemctl restart myapp

# Docker
docker compose restart web

Doi voi framework cache cua Django, xoa cache sau khi cap nhat ban dich:

from django.core.cache import cache
cache.clear()

Trong moi truong phat trien, runserver tu dong tai lai khi file Python thay doi nhung khong theo doi file .mo. Ban can khoi dong lai thu cong sau khi chay compilemessages.

8. Chuoi khong duoc boc trong gettext (_() hoac {% trans %})

makemessages khong trich xuat mot so chuoi, nen chung khong bao gio xuat hien trong file .po va khong bao gio duoc dich. Day la van de co ban nhat va cung de bi bo qua nhat trong mot codebase lon.

Lenh makemessages cua Django su dung xgettext de quet ma nguon cua ban tim cac dau hieu dich. Neu mot chuoi khong duoc boc trong gettext() (thuong duoc dat bi danh la _()), gettext_lazy(), {% trans %}, hoac {% blocktrans %}, no vo hinh doi voi qua trinh trich xuat.

Boc moi chuoi huong toi nguoi dung:

# Python code
from django.utils.translation import gettext_lazy as _

class Article(models.Model):
    class Meta:
        verbose_name = _("article")
        verbose_name_plural = _("articles")

# Views
from django.utils.translation import gettext as _

def my_view(request):
    message = _("Your changes have been saved.")
    return HttpResponse(message)
<!-- Templates -->
{% load i18n %}
<h1>{% trans "Welcome" %}</h1>
<p>{% blocktrans with count=items|length %}You have {{ count }} items.{% endblocktrans %}</p>

Su dung co --dry-run cua TranslateBot de xem truoc cac chuoi hien chua duoc dich, de ban co the bat cac chuoi bi bo sot trong qua trinh trich xuat:

python manage.py translate --target-lang de --dry-run

Dieu nay hien thi tat ca cac muc chua duoc dich trong file .po ma khong thuc hien bat ky cuoc goi API hoac thay doi nao.

9. f-string khong the duoc dich (han che cua Django)

Ban boc mot f-string trong _() va duoc mot loi cu phap, hoac makemessages trich xuat mot chuoi bi hong/khong day du khong the dich duoc.

F-string Python duoc danh gia khi chay. Cong cu trich xuat xgettext phan tich ma nguon mot cach tinh, nen khong the danh gia bieu thuc Python ben trong dau {}. Dieu nay co nghia la _(f"Hello, {name}") duoc trich xuat nhu mot chuoi chua bieu thuc {name} theo nghia den (hoac hoan toan that bai trong trich xuat), va muc .po ket qua se khong bao gio khop voi chuoi khi chay.

Su dung dinh dang % cua Django hoac .format() voi cac placeholder co ten thay the:

# Wrong -- f-string cannot be extracted
message = _(f"Hello, {user.name}! You have {count} new messages.")

# Correct -- named placeholders
message = _("Hello, %(name)s! You have %(count)d new messages.") % {
    "name": user.name,
    "count": count,
}

# Also correct -- .format() with positional args
message = _("Hello, {0}! You have {1} new messages.").format(user.name, count)

Day khong phai la han che cua TranslateBot hay cong cu. No la dieu co ban trong cach gettext hoat dong. Chuoi nguon phai la mot literal tinh de co the duoc trich xuat va tra cuu khi chay.

TranslateBot bao toan tat ca cac dinh dang placeholder nay (%(name)s, {0}, %s, the HTML) trong qua trinh dich, nen cac chuoi da dich van hoat dong day du.

10. Loi dinh dang chuoi placeholder lam hong viec bien dich .po

compilemessages that bai voi loi, hoac file .po co su khong khop co #, python-format, va muc bi loai bo tham lang.

Khi mot chuoi nguon chua cac placeholder dinh dang Python nhu %(name)s, Django danh dau muc .po voi #, python-format. Neu ban dich co cac placeholder khac (loi danh may nhu %(nome)s, placeholder thieu, hoac placeholder thua), cac cong cu gettext co the tu choi muc hoac compilemessages co the that bai. Dieu nay thuong xay ra voi ban dich thu cong hoac voi cac cong cu dich AI khong hieu ngu nghia placeholder.

Mot muc bi hong trong nhu the nay:

#, python-format
msgid "Hello, %(name)s! You have %(count)d new messages."
msgstr "Hallo, %(naam)s! Je hebt %(count)d nieuwe berichten."

O day %(naam)s phai la %(name)s. Cac placeholder phai khop chinh xac voi nguon.

Dam bao cac chuoi da dich chua dung cac placeholder giong het nguon. Kiem tra loi danh may, placeholder thieu, va placeholder thua.

Day la linh vuc ma TranslateBot mang lai loi the thuc su. Logic bao toan placeholder cua no dam bao rang tat ca cac chuoi dinh dang (%(name)s, {0}, %s) trong dau ra da dich khop chinh xac voi nguon. Viec xu ly placeholder duoc bao phu boi 100% do bao phu kiem thu, nen cac loi chuoi dinh dang tu ban dich duoc loai bo o cap do cong cu thay vi bi bat khi bien dich.

Neu ban dang dich thu cong hoac voi cong cu khong xu ly placeholder, xac thuc file .po cua ban voi:

msgfmt --check-format locale/de/LC_MESSAGES/django.po

Dieu nay chay xac thuc chuoi dinh dang cua gettext va bao cao bat ky su khong khop nao.

Ghep tat ca lai: Quy trinh lam viec phong thu

Hau het cac van de nay co chung mot nguyen nhan goc: cac buoc thu cong de quen. Day la quy trinh lam viec ngan chan ca 10 van de:

# 1. Extract strings (catches #8 -- any new gettext-wrapped strings)
python manage.py makemessages -a --no-obsolete

# 2. Translate (catches #1, #5, #8, #9, #10 -- handles untranslated,
#    fuzzy, and placeholder issues automatically)
python manage.py translate

# 3. Compile (catches #1 -- generates .mo files)
python manage.py compilemessages

# 4. Verify in CI (catches everything that slipped through)
python manage.py check_translations --makemessages

Them buoc 4 vao pipeline CI cua ban va cac chuoi chua duoc dich, cac muc fuzzy, va loi dinh dang se lam that bai ban build truoc khi chung den duoc moi truong san xuat.

Bang tham chieu nhanh

Nguyen nhan Trieu chung Khac phuc mot dong
Khong co compilemessages Ban dich ton tai nhung khong xuat hien python manage.py compilemessages
Thieu {% load i18n %} TemplateSyntaxError tren {% trans %} Them {% load i18n %} vao template
Thieu LocaleMiddleware Ngon ngu luon mac dinh la tieng Anh Them django.middleware.locale.LocaleMiddleware vao MIDDLEWARE
Ma ngon ngu khong khop Khong tim thay thu muc locale Su dung pt_BR (gach duoi) cho thu muc, pt-br (gach noi) cho cai dat
Muc fuzzy bi bo qua Ban dich trong .po nhung khong trong ung dung Xoa co #, fuzzy sau khi xem xet
LOCALE_PATHS sai File .po ton tai nhung Django bo qua Dat LOCALE_PATHS thanh duong dan tuyet doi
Ban dich da cache Van ban cu xuat hien sau cap nhat Khoi dong lai may chu ung dung
Chuoi khong trong gettext Chuoi thieu trong file .po Boc trong _() hoac {% trans %}
f-string trong gettext Trich xuat bi hong hoac khong khop khi chay Thay the bang placeholder % hoac .format()
Placeholder khong khop compilemessages that bai hoac muc bi loai bo Khop chinh xac placeholder giua nguon va ban dich

Hau het cac van de nay bien mat khi ban tu dong hoa buoc dich va thuc thi kiem tra trong CI. Lenh translate cua TranslateBot xu ly bao toan placeholder va dich tang dan, trong khi check_translations bat moi thu lot qua (cac muc chua duoc dich, co fuzzy, va van de chuoi dinh dang) truoc khi chung den moi truong san xuat.

Ngừng chỉnh sửa file .po thủ công

TranslateBot tự động hóa bản dịch Django bằng AI. Một lệnh, tất cả ngôn ngữ, chi phí cực thấp mỗi bản dịch.