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 = Trueinsettings.py. - Define
LANGUAGE_CODE(the default) and aLANGUAGESlist of supported languages. - Set
LOCALE_PATHSto the folder where your translation files will live, for exampleBASE_DIR / "locale". - Add
django.middleware.locale.LocaleMiddlewareafter 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_lazyfor strings defined at import time, such as model field labels and form labels. - Use
ngettextfor plurals, so each language can supply its own plural forms. - Use
pgettextto 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_lazyin models and forms to avoid untranslated labels. - Format dates and numbers with Django's localization features instead of fixed formats.
- Run
makemessagesandcompilemessagesin 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.