A built-in framework in the Django web framework that allows developers to prepare Python web applications for translation and adapt them to different languages, regions, and cultural formats.
Django i18n refers to Django’s internationalization (i18n) and localization (l10n) support, which is built into the framework rather than added as a third-party library. The goal is to separate translatable text from the application’s code so that the same codebase can serve users in different languages without any structural changes. Django’s i18n system is built on the GNU gettext standard, which is also the foundation of the .po and .mo file formats used throughout the localization industry.
The distinction Django draws between i18n and l10n is worth knowing: internationalization is the work developers do to prepare the application for translation — marking strings, setting up locale paths, enabling language detection. Localization is the work of actually providing translations and locale-specific formatting for each target language. Both are controlled through Django’s settings and activated together in most projects.
The process starts in settings.py. Enabling USE_I18N = True activates the translation engine. In older versions of Django, USE_L10N was used for locale-aware formatting, but as of Django 5.0, this is handled automatically when USE_I18N is enabled. Developers then mark any user-facing string for translation using Django’s translation functions.
In Python code, a translatable string looks like this:
from django.utils.translation import gettext_lazy as _
# Use gettext_lazy for models, forms, and global variables
greeting = _("Welcome to our site!")In HTML templates, the same approach uses a template tag:
{% load i18n %}
<h1>{% trans "Welcome to our site!" %}</h1>Once strings are marked, the makemessages command scans the codebase and generates a .po file for each supported language. Translators fill in the translations, and the compilemessages command compiles the .po files into binary .mo files that Django uses at runtime.
Django detects the user’s preferred language automatically through LocaleMiddleware, which reads the Accept-Language header sent by the browser. It can also detect language from the URL (for example, /en/about/ vs /de/about/), from session data, or from a cookie. This middleware must be placed correctly in the MIDDLEWARE list in settings.py, after SessionMiddleware and before CommonMiddleware, for detection to work as expected.
makemessages and compilemessages management commands handle the full translation file lifecycle without external tooling.ngettext, which handles language-specific plural rules correctly across languages with complex plural forms.LANGUAGE_BIDI flag, which templates can use to adjust layout direction.gettext_lazy for strings in models or forms to ensure they are translated when the user views the page, not when the server starts.javascript_catalog view, allowing you to use your .po file translations directly in frontend scripts.For teams using a TMS, Django’s .po files are the standard exchange format. Most localization platforms, including Lokalise, Phrase, and Localazy, support .po file upload and download natively. This means developers can generate .po files with makemessages, send them to a TMS for translation, and import the completed translations back without any format conversion.
Localazy supports .po files natively, making it easy to connect a Django project to a professional localization workflow. Instead of manual file handling, you can use the Localazy CLI to automate the upload of source strings and the download of translated files directly into your locale/ folders. This integrates easily into CI/CD pipelines, ensuring your translations stay in sync with every code deployment.
See also: Localazy docs on integrating Django and Django’s official i18n documentation.