Search code examples
djangodjango-templatestranslation

Django "trans" template tag using wrong language


I have a site using Django 1.10 with German and English as available languages, where German is the source language. Dynamic content is translated with django-modeltranslation and for static strings I am using Django's built-in trans template tag.

I want Django to return the page in the visitor's preferred language. I have read how Django discovers language preference carefully several times, and I think I have everything right. As I change my language settings in my browser, the value of the LANGUAGE_CODE variable when displayed in a template always changes accordingly, and also the dynamic content is always returned in the expected language by django-modeltranslation. Also the admin interface and extensions like rosetta and django-debug-toolbar switch their interface language nicely as expected. It's only the trans template tag that is not picking my browser's language preference. Instead, it seems to directly resort to the initial value of the LANGUAGE_CODE variable as it is originally set in the settings file, without going through the algorithm described in the aforementioned link.

The locale middleware is of course in place, and so are the *.po and *.mo files as well. The browser request headers also look fine. Because everything except the trans tag behaves as expected, I don't think that any of those is the problem. But for reference, here is my middleware settings:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

And my language settings:

LANGUAGE_CODE = 'en'

LANGUAGES = [
    ('de', _('German')),
    ('en', _('English')),
]

Other possibly related posts on SO (yet a bit old):


Solution

  • Finally, I figured this out. I had .po and .mo files for English but not for my source language (German). Django of course doesn't know that my source strings are in German, but I was assuming that in case translations for a certain language are not found, it would show the original strings untranslated (i.e, in German in this case). Instead, it looks like before doing that, Django still looks for translations for the fallback language (the one defined as LANGUAGE_CODE in the settings, or English if none is defined). Only if it can't find either translations for the detected language nor translations for the fallback language it will show untranslated strings.

    So, my practical advice is: generate .po and .mo files for all available languages including your source language. And set your source language as LANGUAGE_CODE in the settings. You can then leave these translations empty if you want, so that the original strings will be shown.

    Edit: I also observed that my problem appears only if the source language is not the same as the fallback language (in my case, setting de as LANGUAGE_CODE everything still works as expected, but it was required that the site defaults to English despite the original strings being in German). So here comes my advice refined: if your source language is different than the fallback language defined as LANGUAGE_CODE in the settings, then you need to include the translations that correspond to your source language as well. This might mean providing translations files where all msgid and msgstr are identical... If you leave any msgstr empty, Django will try to find translation strings in the fallback language (which is different than the source language).