Skip to main content

Django i18n: vodič za internacionalizaciju i prevođenje

Od datoteke settings.py do produkcije: konfigurirajte sustav prevođenja Djanga, pišite PO datoteke, obradite množinu i automatizirajte prevođenje s pomoću AI-ja.

1

Instalirajte i izdvojite tekstove

Djangov okvir i18n ugrađen je — trebate ga samo omogućiti. Instalirajte django-locale-chain za pametne zamjenske lokalne postavke, a zatim naredbom makemessages izdvojite prevodive tekstove iz Python kôda i predložaka u PO datoteke.

Django u pozadini upotrebljava GNU gettext. Naredba makemessages pregledava kôd tražeći pozive gettext i oznake predložaka te generira .po datoteke. Nakon prevođenja compilemessages ih pretvara u binarne .mo datoteke radi brzog dohvaćanja tijekom izvođenja.
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

Konfigurirajte postavke i posrednički sloj

U datoteci settings.py omogućite internacionalizaciju postavljanjem USE_I18N = True, definiranjem popisa podržanih jezika LANGUAGES i dodavanjem LocaleMiddleware u stog MIDDLEWARE. LocaleMiddleware prepoznaje korisnikov jezik iz prefiksa URL-a, sesije, kolačića ili zaglavlja Accept-Language.

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',
]
LocaleMiddleware mora biti nakon SessionMiddleware (jer čita sesiju), a prije CommonMiddleware. Ako je redoslijed pogrešan, prepoznavanje jezika tiho ne uspijeva i svi korisnici vide zadani LANGUAGE_CODE.

Internacionalizacija URL-ova

Funkcijom i18n_patterns() automatski dodajte kôd aktivnog jezika kao prefiks URL-ovima. Tako svaki jezik dobiva vlastiti prostor imena URL-ova (/en/about/, /de/about/), što poboljšava SEO i omogućuje dijeljenje poveznica za određeni jezik.

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

Označite tekstove za prijevod

Django nudi dvije glavne funkcije za prevođenje: gettext() (s pseudonimom _()) za tekstove koji se vrednuju pri obradi zahtjeva i gettext_lazy() za tekstove koji se vrednuju pri uvozu. U predlošcima upotrebljavajte oznake {% trans %} i {% blocktrans %}.

U pogledima (Python kôd)

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}")

U predlošcima

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>

U modelima i obrascima

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
Ako u poljima modela, oznakama obrazaca ili atributima na razini klase upotrijebite gettext() umjesto gettext_lazy(), tekstovi će se prevesti samo jednom pri uvozu (pokretanju poslužitelja), a ne za svaki zahtjev. Prijevod će ostati zamrznut na jeziku aktivnom tijekom uvoza — obično zadanom LANGUAGE_CODE.

Format PO datoteke

Nakon pokretanja naredbe makemessages Django generira .po datoteke (Portable Object) za svaki jezik. One sadržavaju parove msgid/msgstr. Prevedite vrijednosti msgstr, a zatim naredbom compilemessages generirajte binarne .mo datoteke koje Django čita tijekom izvođenja.

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

Obradite množinu i varijable

Django za množinu upotrebljava ngettext(), koji slijedi pravila sustava GNU gettext. Svaki jezik definira broj oblika množine i formulu za odabir odgovarajućeg oblika. PO datoteke to navode u zaglavlju Plural-Forms.

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}
Nikada nemojte upotrebljavati Pythonove f-stringove ili .format() unutar poziva gettext. Alat za izdvajanje prijevoda ne može ih raščlaniti. Upotrijebite staro oblikovanje %(): _('Hello, %(name)s!') % {'name': name}. Time prevoditelji vide rezervirana mjesta varijabli u svojim uređivačima PO datoteka.

Automatizirajte provjeru kvalitete prijevoda

Alatom i18n-validate otkrijte ključeve koji nedostaju i neispravna rezervirana mjesta prije objave. Korisničko sučelje testirajte pseudoprijevodima uz i18n-pseudo prije nego što stignu stvarni prijevodi.

Uobičajene zamke

Zabuna između funkcija gettext() i gettext_lazy()

Upotrebljavajte gettext_lazy() (uvezen kao _) za polja modela, oznake obrazaca i sve atribute na razini klase koji se vrednuju pri uvozu. gettext() upotrebljavajte za funkcije pogleda i kôd koji se izvršava pri obradi zahtjeva. Zamijenite li ih, prijevodi ostaju zamrznuti na jeziku pokretanja poslužitelja.

Naredba compilemessages nije pokrenuta

Django čita prevedene .mo datoteke, a ne .po datoteke. Ako uredite .po datoteku i ne pokrenete 'python manage.py compilemessages', promjene se neće prikazati. Dodajte compilemessages u skriptu za objavu.

LOCALE_PATHS nije konfiguriran

Ako je LOCALE_PATHS prazan ili upućuje na pogrešnu mapu, makemessages izrađuje .po datoteke na pogrešnom mjestu pa ih Django ne može pronaći tijekom izvođenja. Uvijek postavite LOCALE_PATHS = [BASE_DIR / 'locale'] i provjerite postoji li mapa.

i18n_patterns nedostaje u URL-ovima

Bez i18n_patterns() URL-ovi nemaju jezični prefiks pa se Django pri prepoznavanju jezika oslanja samo na kolačiće i zaglavlja. To šteti SEO-u (nema URL-ova za pojedine jezike) i onemogućuje promjenu jezika putem URL-a. Obrasce URL-ova namijenjene korisnicima obuhvatite funkcijom i18n_patterns().

Pametne zamjenske lokalne postavke uz django-locale-chain

Kada nedostaje regionalna inačica, Djangov sustav prevođenja odmah prelazi na LANGUAGE_CODE. Korisnik s postavkom pt-BR vidi engleski čak i kada postoje prijevodi za pt-PT. django-locale-chain to rješava postavljanjem zamjenskih lanaca gettext: pt-BR pokušava pt-PT, zatim pt pa tek onda zadani jezik.

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"]})

Preporučena struktura projekta

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

Isprobajte i18n Agent odmah

Povucite datoteku za prijevod ovdje

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

ili kliknite za odabir

Ciljni jezici

Registracija nije potrebnaProcjena odmah

Zamjenske lokalne postavke uz django-locale-chain

Kada u regionalnoj lokalnoj postavci poput pt-BR nedostaje ključ prijevoda, Django odmah prelazi na jezik predloška umjesto da prvo provjeri nadređenu postavku 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',
    ...
]

U našem vodiču za zamjenske lokalne postavke pogledajte cjelovit popis podržanih razvojnih okvira i 75 ugrađenih lanaca. Learn more →

Često postavljana pitanja