Skip to content

Translations

Every user-visible string in the package goes through gettext — model field labels and help texts, admin fieldset headings, banner copy, maintenance page copy, and even the JavaScript unit labels, which are translated server-side and injected into the script as variables.

Two catalogs ship with the package:

Language Status
English (en) Source strings
Polish (pl) Complete

Turning it on

Translation is automatic once Django's i18n machinery is active. For per-request language negotiation you need LocaleMiddleware:

settings.py
USE_I18N = True
LANGUAGES = [("en", "English"), ("pl", "Polski")]
LANGUAGE_CODE = "en"

MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",
    # LocaleMiddleware must sit after SessionMiddleware and before Common.
    "django.middleware.locale.LocaleMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django_countdown.middleware.CountdownBlockingMiddleware",
]

With that in place, a visitor sending Accept-Language: pl gets the Polish maintenance page; everyone else gets English.

lang attribute on the maintenance page

blocked_base.html renders <html lang="{{ LANGUAGE_CODE|default:'en' }}">. LANGUAGE_CODE only reaches the template context if django.template.context_processors.i18n is registered — otherwise the page always claims to be English, whatever language it actually renders in. Add the processor if you serve more than one language:

"context_processors": [
    # ...
    "django.template.context_processors.i18n",
    "django_countdown.context_processors.countdown_context",
],

Overriding the shipped wording

The packaged copy is deliberately generic — "We're sorry for the inconvenience. We're rolling out an important update." If it does not match your voice, you have two options.

Override the translation, which is the lighter touch. Catalogs in LOCALE_PATHS take precedence over app catalogs, so you can restate any string without forking a template:

settings.py
LOCALE_PATHS = [BASE_DIR / "locale"]
$ mkdir -p locale/en/LC_MESSAGES
$ ./manage.py makemessages --locale en --all

Then edit the entry in locale/en/LC_MESSAGES/django.po:

msgid "System under maintenance"
msgstr "We'll be right back"
$ ./manage.py compilemessages

This works even for English → English, which is the trick for rewording without touching markup.

Override the template, when the structure changes too — see Blocked page.

Adding a language to your project

If you translate the package for your own deployment only, the same LOCALE_PATHS mechanism applies — run makemessages --locale de, fill in the entries, compile.

The msgids to look for are the English source strings, spread across models.py, admin.py and the four templates.

Contributing a language upstream

Translations are welcome in the package itself, where everyone benefits:

$ git clone https://github.com/iplweb/django-countdown.git
$ cd django-countdown/src/django_countdown
$ uv run django-admin makemessages --locale de
# edit locale/de/LC_MESSAGES/django.po
$ uv run django-admin compilemessages

Notes for a clean pull request:

  • Commit both django.po and the compiled django.mo — the package ships compiled catalogs, and package-data in pyproject.toml includes locale/**/*.
  • makemessages rewraps lines at 79 characters. If your diff shows unrelated reflow noise, that is xgettext normalising the file; it is harmless.
  • Keep the placeholders intact. Several strings use named interpolation — %(n)d days, {{ minutes }} inside {% blocktrans %} — and the substitution breaks if a name is changed.
  • Translate the JavaScript labels too — the duration units (days, h, min, sec) and the maintenance page's status line, which is what visitors read while they wait for the site to come back. They are ordinary {% trans %} strings rendered into the script.

The example project

example/ is translated end to end and doubles as a working reference for the setup above: LocaleMiddleware enabled, LOCALE_PATHS configured, and a complete Polish catalog at example/example_project/locale/pl/LC_MESSAGES/django.po.

Run it with Accept-Language: pl, or set LANGUAGE_CODE = "pl" in its settings, to see both the app and the package render in Polish.