0

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",
            ],
        },
    }
]


John
  • 949
  • 1
  • 9
  • 20

2 Answers2

0

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",
]

John
  • 949
  • 1
  • 9
  • 20
-1

Translations together with messages is a very interesting thing.

Every message in messages dictionary wait till own render through {{ messages }} in template.

It means, if next template don't have this tag - you can not see the messages and they can not be rendered and they should wait.

A lazy_translation is a wrapper that does nothing until the str/unicode function for that translation is called. In your case - message has lazy_translation, and they wait render call.

Let's try - choose language. Open the from. Fill the form. Press Save. Close the browser before you see the answer.

Your messages still waiting the moment to render self. Lasy_translation wait too.

Open your browser, open completely other link with other language. If template has {{ messages }}, you see the old message with old info from other view with translation on the current language.

If you change lazy_translation on gettext - and made the same process. You should see the message with old language.

My opinion. Every should override get_success_message function and wrap super().get_success_message in str. It's made the expected behavior of translations in messages.

The next question - why you not see the messages. I need more information about view and templates to answer.

Maxim Danilov
  • 2,472
  • 1
  • 3
  • 8