Skip to main content

Django i18n: водич за интернационализацију и превођење

Од settings.py датотеке до продукције: подесите Django систем за превођење, пишите PO датотеке, обрадите множине и аутоматизујте преводе помоћу AI технологије.

1

Инсталирајте и издвојте текстове

Django i18n радни оквир је уграђен — треба само да га омогућите. Инсталирајте django-locale-chain за паметне резервне локале, а затим користите makemessages да из Python кода и шаблона издвојите преводиве текстове у PO датотеке.

Django у позадини користи GNU gettext. Команда makemessages скенира код у потрази за gettext позивима и ознакама шаблона, па генерише .po датотеке. После превођења, compilemessages их конвертује у бинарне .mo датотеке за брзу претрагу током извршавања.
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

Подесите поставке и посреднички софтвер

Омогућите интернационализацију у settings.py тако што ћете поставити USE_I18N = True, дефинисати листу подржаних LANGUAGES и додати LocaleMiddleware у MIDDLEWARE стек. LocaleMiddleware открива језик корисника из префикса URL адресе, сесије, колачића или 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 мора да буде после SessionMiddleware (јер чита сесију), а пре CommonMiddleware. Ако је постављен погрешним редоследом, откривање језика неприметно отказује и сви корисници виде подразумевани LANGUAGE_CODE.

Интернационализација URL адреса

Користите i18n_patterns() да аутоматски додате кôд активног језика као префикс URL адресама. Тако сваки језик добија сопствени именски простор URL адреса (/en/about/, /de/about/), што је боље за SEO и омогућава корисницима да деле везе за одређени језик.

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

Означите текстове за превођење

Django пружа две главне функције за превођење: gettext() (са псеудонимом _()) за текстове који се вреднују током захтева и gettext_lazy() за текстове који се вреднују током увоза. У шаблонима користите ознаке {% trans %} и {% blocktrans %}.

У приказима (Python код)

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

У шаблонима

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>

У моделима и обрасцима

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
Употреба gettext() уместо gettext_lazy() у пољима модела, ознакама образаца или атрибутима нивоа класе доводи до тога да се текстови преведу само једном током увоза (када се сервер покрене), а не за сваки захтев. Превод ће остати замрзнут на језику који је био активан током увоза — обично подразумеваном LANGUAGE_CODE језику.

Формат PO датотеке

Након покретања makemessages команде, Django генерише .po (Portable Object) датотеке за сваки језик. Оне садрже парове msgid/msgstr. Преведите вредности msgstr, а затим покрените compilemessages да генеришете бинарне .mo датотеке које Django чита током извршавања.

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

Обрадите множине и променљиве

Django користи ngettext() за множину, према правилима множине система GNU gettext. Сваки језик дефинише колико облика множине има и формулу за избор исправног облика. PO датотеке то наводе у заглављу 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}
Никада не користите Python f-string текстове или .format() унутар gettext позива. Алатка за издвајање превода не може да их рашчлани. Користите стари стил %() форматирања: _('Hello, %(name)s!') % {'name': name}. Тако преводиоци виде и чуваре места променљивих у својим PO уређивачима.

Аутоматизујте квалитет превода

Помоћу i18n-validate алатке откријте недостајуће кључеве и неисправне чуваре места пре испоруке. Тестирајте кориснички интерфејс псеудопреводима помоћу i18n-pseudo алатке пре него што стигну прави преводи.

Уобичајене замке

Забуна око gettext() и gettext_lazy() функција

Користите gettext_lazy() (увезен као _) за поља модела, ознаке образаца и све атрибуте нивоа класе који се вреднују током увоза. Користите gettext() за функције приказа и код који се извршава током захтева. Ако их помешате, преводи остају замрзнути на језику покретања сервера.

Заборављено покретање compilemessages команде

Django чита .mo (компајлиране) датотеке, а не .po датотеке. Ако измените .po датотеку и не покренете 'python manage.py compilemessages', измене се неће појавити. Додајте compilemessages у скрипту за постављање.

LOCALE_PATHS није подешен

Ако је LOCALE_PATHS празан или показује на погрешан директоријум, makemessages прави .po датотеке на погрешном месту и Django не може да их пронађе током извршавања. Увек поставите LOCALE_PATHS = [BASE_DIR / 'locale'] и проверите да ли директоријум постоји.

i18n_patterns недостаје у URL адресама

Без i18n_patterns(), URL адресе немају језички префикс и Django се за откривање језика ослања само на колачиће и заглавља. То штети SEO оптимизацији (нема URL адреса за одређене језике) и онемогућава промену језика путем URL адресе. Обухватите обрасце URL адреса намењене корисницима функцијом i18n_patterns().

Паметни резервни локали уз django-locale-chain

Django систем за превођење одмах прелази на LANGUAGE_CODE када регионална варијанта недостаје. Корисник локала pt-BR види енглески чак и када имате преводе за pt-PT. django-locale-chain то исправља постављањем gettext ланаца резервних локала: pt-BR покушава pt-PT, затим pt, пре преласка на подразумевани језик.

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

Препоручена структура пројекта

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

Испробајте i18n Agent сада

Пустите датотеку за превођење овде

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

или кликните за избор

Циљни језици

Регистрација није потребнаТренутна процена

Резервни локали уз django-locale-chain

Када кључ превода недостаје у регионалном локалу као што је pt-BR, Django одмах прелази на језик шаблона уместо да прво провери надређени локал 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',
    ...
]

Погледајте наш водич за резервне локале за целу листу подржаних система и 75 уграђених ланаца. Learn more →

Честа питања