Home / Blog / Guides
Guides

Django Translation: A Step-by-Step i18n Guide With PO Files

Translate your Django project with gettext: settings, marking strings in code and templates, makemessages, PO files, compilemessages, translated URLs and best practices.

WordBeam Team
Oct 12, 2026 · 6 min read
Django Translation: A Step-by-Step i18n Guide With PO Files

Django translation uses the gettext system: you mark strings in Python code and templates, run makemessages to collect them into PO files, translate the PO files and run compilemessages to produce the MO files Django reads at runtime. Combined with locale middleware and language-prefixed URLs, this lets one Django project serve many languages. This guide walks through the full process step by step.

Step 1: Enable Internationalization in Settings

  • Keep USE_I18N = True in settings.py.
  • Define LANGUAGE_CODE (the default) and a LANGUAGES list of supported languages.
  • Set LOCALE_PATHS to the folder where your translation files will live, for example BASE_DIR / "locale".
  • Add django.middleware.locale.LocaleMiddleware after the session middleware so Django can detect the user's language.

The official Django translation documentation covers every setting in detail.

Step 2: Mark Strings in Python Code

  • Use gettext, usually imported as _, for strings translated at request time.
  • Use gettext_lazy for strings defined at import time, such as model field labels and form labels.
  • Use ngettext for plurals, so each language can supply its own plural forms.
  • Use pgettext to add context when the same English word has different meanings.
  • Use named placeholders, for example _("Hello, %(name)s") % {"name": user.first_name}.

Step 3: Mark Strings in Templates

Add {% load i18n %} at the top of the template. Use {% translate "Sign in" %} for simple strings and {% blocktranslate %} for text with variables or plurals. Older projects may use the equivalent trans and blocktrans tags.

Step 4: Create PO Files

Run django-admin makemessages -l de for each language. Django scans your code and templates and creates locale/de/LC_MESSAGES/django.po. Each entry has a msgid with the source text and an empty msgstr for the translation. For JavaScript strings, use -d djangojs.

Step 5: Translate the PO Files

PO files can be edited in a text editor, but that is slow and risky with many languages. A translation tool keeps placeholders such as %(name)s safe, applies translation memory and checks plural forms. Our guide to PO file translation explains the format in detail.

Step 6: Compile and Test

Run django-admin compilemessages to turn PO files into binary MO files. Restart the server, switch the browser language or use a language selector, and check every page. Fuzzy entries in PO files are ignored until a translator confirms them.

Step 7: Translate URLs

Wrap URL patterns in i18n_patterns() to add language prefixes such as /de/ and /fr/. This makes each language version crawlable. Add hreflang tags so search engines connect the versions, as explained in our hreflang guide.

Django Translation Best Practices

  • Translate full sentences; never build sentences from fragments.
  • Add translator comments in code with # Translators: so context appears in the PO file.
  • Use gettext_lazy in models and forms to avoid untranslated labels.
  • Format dates and numbers with Django's localization features instead of fixed formats.
  • Run makemessages and compilemessages in CI so translations never fall behind.

Translate Django PO Files With WordBeam

WordBeam imports Django PO files directly, protects Python placeholders and HTML tags, and handles plural entries. Translators work with translation memory, a term base and AI engines such as DeepL, GPT, Claude and Grok, and QA checks catch broken placeholders before export. On the Studio plan, GitHub and GitLab integrations keep PO files in sync with your repository. Learn more about software localization with WordBeam.

Frequently Asked Questions

What file format does Django use for translations?

Django uses gettext PO files for editing and compiled MO files at runtime.

What is the difference between gettext and gettext_lazy?

gettext translates immediately, while gettext_lazy delays translation until the string is used, which is needed for strings defined when modules load.

Why are my Django translations not showing?

Common causes are forgetting compilemessages, a wrong LOCALE_PATHS setting, missing LocaleMiddleware, or entries still marked as fuzzy.