Search code examples
pythondjangodjango-i18ndjango-messagesdjango-4.0

How to make Django messages framework play nicely with i18n?


Using django 4.0.6 I was using the messages framework to display messages when users successfully completed a form. Then I added i18n:

When the default language is selected, messages are shown on the second screen after the form is submitted, not the first.

When the not-default language is active, untranslated messages are shown, on the first screen after the message is created (as expected).

I've tried using both gettext_lazy and gettext and it didnt help.

Its an unusual bug and Im not sure what I've done wrong?

views:

from django.utils.translation import gettext_lazy as _
from django.views.generic.edit import CreateView
...

class ContactView(SuccessMessageMixin, CreateView):

    template_name = "contact-form.html"
    form_class = ContactForm
    success_url = reverse_lazy("base:home")
    success_message = _("Thanks for contacting us.")

    def form_valid(self, form):
        if contact_form_filter(form):
            create_and_send_contact_form_email(form)
        return super().form_valid(form)

    def form_invalid(self, form):
        """If the form is invalid, render the invalid form."""
        return self.render_to_response(self.get_context_data(form=form))

settings:

TIME_ZONE = "CET"
LANGUAGE_CODE = "en"
USE_I18N = True
WAGTAIL_I18N_ENABLED = True
USE_L10N = True  # Deprecated in Django 4, but still used in Wagtail I believe
USE_TZ = True

WAGTAIL_CONTENT_LANGUAGES = LANGUAGES = [
    ("en", _("English")),
    ("nl", _("Dutch")),
]

INSTALLED_APPS = [
    ...
    "django.contrib.messages",
    ...
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.locale.LocaleMiddleware",
    "django.middleware.cache.UpdateCacheMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.cache.FetchFromCacheMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "wagtail.contrib.redirects.middleware.RedirectMiddleware",
    "compression_middleware.middleware.CompressionMiddleware",
]

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [str(APPS_DIR / "built"), str(APPS_DIR / "templates")],
        "OPTIONS": {
            "loaders": [
                "django.template.loaders.filesystem.Loader",
                "django.template.loaders.app_directories.Loader",
            ],
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.template.context_processors.i18n",
                "django.template.context_processors.media",
                "django.template.context_processors.static",
                "django.template.context_processors.tz",
                "django.contrib.messages.context_processors.messages",
                "lettergun.utils.context_processors.settings_context",
                "lettergun.utils.context_processors.pass_",
                "lettergun.utils.context_processors.toggle_customer_testimonials",
            ],
        },
    }
]



Solution

  • I solved the problems and the site now behaves consistently and as expected. The odd behavior was caused by two issues:

    1. The order of middleware is important.
    2. Take care that any custom template tags that are used to set or switch the site language are not creating side effects. See this answer for this specific issue.

    I set the middleware to the below and messages and translations now work as expected:

    MIDDLEWARE = [
        "django.middleware.security.SecurityMiddleware",
        "django.middleware.http.ConditionalGetMiddleware",
        "django.middleware.cache.UpdateCacheMiddleware",
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.common.CommonMiddleware",
        "django.middleware.csrf.CsrfViewMiddleware",
        "django.contrib.auth.middleware.AuthenticationMiddleware",
        "corsheaders.middleware.CorsMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.contrib.messages.middleware.MessageMiddleware",
        "django.middleware.clickjacking.XFrameOptionsMiddleware",
        "wagtail.contrib.redirects.middleware.RedirectMiddleware",
        "django.middleware.cache.FetchFromCacheMiddleware",
    ]