Skip to main content

Django i18n: Gabay sa Internationalization at Pagsasalin

Mula settings.py hanggang production: i-configure ang translation system ng Django, gumawa ng PO file, pangasiwaan ang plural, at i-automate ang mga pagsasalin gamit ang AI.

1

I-install at I-extract ang mga String

Built-in ang i18n framework ng Django — kailangan lang ninyo itong i-enable. I-install ang django-locale-chain para sa matalinong locale fallback, pagkatapos ay gamitin ang makemessages para i-extract ang mga nasasaling string mula sa inyong Python code at template papunta sa mga PO file.

Gumagamit ang Django ng GNU gettext sa ilalim. Ini-scan ng makemessages command ang inyong code para sa mga gettext call at template tag, pagkatapos ay bumubuo ng mga .po file. Pagkatapos maisalin, kino-convert ng compilemessages ang mga ito sa binary .mo file para sa mabilis na lookup sa runtime.
Terminal
pip install django-locale-chain
Terminal
# 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
2

I-configure ang Settings at Middleware

I-enable ang internationalization sa settings.py sa pamamagitan ng pag-set ng USE_I18N = True, pagde-define ng listahan ng mga sinusuportahang LANGUAGES, at pagdaragdag ng LocaleMiddleware sa inyong MIDDLEWARE stack. Tinutukoy ng LocaleMiddleware ang wika ng user mula sa URL prefix, session, cookie, o Accept-Language header.

settings.py
# 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',
]
Dapat ilagay ang LocaleMiddleware pagkatapos ng SessionMiddleware (dahil binabasa nito ang session) at bago ang CommonMiddleware. Kapag mali ang pagkakasunod, tahimik na mabibigo ang language detection at makikita ng lahat ng user ang default LANGUAGE_CODE.

Internationalization ng URL

Gumamit ng i18n_patterns() para awtomatikong i-prefix ang inyong mga URL ng aktibong language code. Nagbibigay ito sa bawat wika ng sariling URL namespace (/en/about/, /de/about/) na mas mainam para sa SEO at nagpapahintulot sa mga user na magbahagi ng mga link na partikular sa wika.

urls.py
# 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
)
3

Markahan ang mga String para sa Pagsasalin

Nagbibigay ang Django ng dalawang pangunahing translation function: gettext() (ina-alias bilang _()) para sa mga string na ine-evaluate sa request time, at gettext_lazy() para sa mga string na ine-evaluate sa import time. Sa mga template, gamitin ang {% trans %} at {% blocktrans %} na tag.

Sa Mga View (Python Code)

views.py
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}")

Sa Mga Template

templates/myapp/index.html
{# 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>

Sa Mga Model at Form

models.py
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
Ang paggamit ng gettext() sa halip na gettext_lazy() sa mga model field, form label, o class-level attribute ay nagdudulot na maisalin ang mga string nang minsan sa import time (kapag nagsisimula ang server) sa halip na kada request. Mananatiling naka-freeze ang pagsasalin sa kung anong wikang aktibo noong import — kadalasan ay ang default LANGUAGE_CODE.

Format ng PO File

Pagkatapos patakbuhin ang makemessages, bumubuo ang Django ng mga .po (Portable Object) file para sa bawat wika. Naglalaman ang mga ito ng mga pares na msgid/msgstr. Isalin ang mga value ng msgstr, pagkatapos ay patakbuhin ang compilemessages para bumuo ng mga binary .mo file na binabasa ng Django sa runtime.

locale/de/LC_MESSAGES/django.po
# 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"
4

Pangasiwaan ang Plural at Variable

Gumagamit ang Django ng ngettext() para sa pluralization, na sumusunod sa plural rules ng GNU gettext. Tinutukoy ng bawat wika kung ilang plural form ang mayroon ito at ang pormula para piliin ang tamang form. Ipinapahayag ito sa mga PO file sa pamamagitan ng Plural-Forms header.

Plural forms by language
# 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}
Huwag kailanman gumamit ng Python f-strings o .format() sa loob ng mga gettext call. Hindi ito ma-parse ng translation extractor. Gumamit ng lumang %() formatting: _('Hello, %(name)s!') % {'name': name}. Tinitiyak din nito na makikita ng mga tagasalin ang mga variable placeholder sa kanilang PO editor.

I-automate ang Kalidad ng Pagsasalin

Matukoy ang mga nawawalang key at sirang placeholder bago ma-ship gamit ang i18n-validate. Subukan ang inyong UI gamit ang pseudo-translation sa i18n-pseudo bago dumating ang mga tunay na pagsasalin.

Mga Karaniwang Pitfall

Kalituhan sa gettext() vs gettext_lazy()

Gumamit ng gettext_lazy() (ini-import bilang _) para sa mga model field, form label, at anumang class-level attribute na ine-evaluate sa import time. Gumamit ng gettext() para sa mga view function at request-time code. Kapag napaghalo ang mga ito, nai-freeze ang mga pagsasalin sa wikang ginagamit sa pag-start ng server.

Nakalimutang Patakbuhin ang compilemessages

Binabasa ng Django ang mga .mo (compiled) file, hindi ang mga .po file. Kung nag-edit kayo ng .po file at hindi pinatakbo ang 'python manage.py compilemessages', hindi lalabas ang mga pagbabago ninyo. Idagdag ang compilemessages sa inyong deployment script.

Hindi Naka-configure ang LOCALE_PATHS

Kapag walang laman ang LOCALE_PATHS o tumuturo sa maling directory, gagawa ang makemessages ng mga .po file sa maling lugar at hindi mahahanap ng Django ang mga ito sa runtime. Laging i-set ang LOCALE_PATHS = [BASE_DIR / 'locale'] at i-verify na umiiral ang directory.

Walang i18n_patterns sa Mga URL

Kapag walang i18n_patterns(), walang language prefix ang mga URL at umaasa lang ang Django sa mga cookie/header para sa language detection. Nakakasama ito sa SEO (walang URL na partikular sa wika) at nasisira ang pagpapalit ng wika sa pamamagitan ng URL. I-wrap ang inyong user-facing URL pattern sa i18n_patterns().

Matalinong Locale Fallback gamit ang django-locale-chain

Ang default na behavior ng translation system ng Django ay direktang bumabalik sa LANGUAGE_CODE kapag nawawala ang regional variant. Makakakita ang pt-BR user ng English kahit mayroon kayong pt-PT translation. Inaayos ito ng django-locale-chain sa pamamagitan ng pag-install ng gettext fallback chain: susubukan ng pt-BR ang pt-PT, pagkatapos ay pt, bago bumalik sa inyong default language.

settings.py
# 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"]})

Inirerekomendang Istruktura ng Proyekto

Project Structure
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

Subukan ang i18n Agent Ngayon

I-drop dito ang inyong translation file

JSON, YAML, PO, XML, CSV, Markdown, Properties

o i-click para mag-browse

Mga target language

Hindi kailangan ang signupInstant na estimate

Locale Fallback gamit ang django-locale-chain

Kapag nawawala ang translation key sa isang regional locale tulad ng pt-BR, tumatalon ang Django diretso sa wika ng template sa halip na suriin muna ang parent locale na pt.

Terminal
pip install django-locale-chain
Configuration
# settings.py
LOCALE_CHAINS = {
    'pt-BR': ['pt', 'es', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
}

MIDDLEWARE = [
    ...
    'django_locale_chain.middleware.LocaleChainMiddleware',
    ...
]

Tingnan ang aming Locale Fallback Guide para sa kumpletong listahan ng mga sinusuportahang framework at 75 built-in chain. Learn more →

Mga Madalas Itanong