Django's get_current_language always returns "en"
Asked Answered
T

2

20

In my Django 2.0 site, I want to set the lang atribute of the html tag to the current locale's language. In my base.html which other templates extend, I use get_current_language in the following way

{% load i18n %}

{% get_current_language as LANGUAGE_CODE %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
 ...
</html>

The site has translations for multiple languages. If I switch the language in the browser, I see the correct translations, but the lang attribute will always contain en.

In my settings.py I have

USE_I18N = True
LANGUAGE_CODE = 'en-us'

and based on the suggestion of Goran the following middleware order

MIDDLEWARE = [
    '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',
]

The LANGUAGES setting is unset.

As suggested by Kostadin Slavov I have tried printing the language from the view. It seems that get_current_language calls django.utils.translation.get_language, so I have inserted the following in my view

from django.utils import translation                                        
print(translation.get_language())                                           

It prints the correct value (eg de when accessing the view with a browser set to German).

What else am I missing?

Transition answered 1/8, 2018 at 19:59 Comment(7)
be sure that the order of middlewares is correct how Django discovers language preferencesGirgenti
I've fixed the order of middlewares according to the docs; it didn't fix the problem, but I've added the information to the question above.Hardie
are you sure that you send POST request to the {% url 'set_language' %}? The view expects to be called via the POST method docsGirgenti
No, I am sending an Accept-Language header. It is enough for the translations to work correctly.Hardie
What do you have set for LANGUAGE_CODE and LANGUAGES, if anything?Aishaaisle
Hi, @StefanKögl, what is the value of {{ LANGUAGE_CODE }} try printing it out in the backend to see what is sending to youAscham
I have added the requested info within the question.Hardie
H
5

I tried to simulate your environment with these steps:

$ cd ~
$ python3 -m venv ~/venvs/mysite
$ source ~/venvs/mysite/bin/activate
$ pip install django==2.0.8
$ django-admin startproject mysite

Then I updated the generate code as in your example:

  • mysite/settings.py

    ...
    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',
    ]
    ...
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': ['templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    ...
    
  • mysite/urls.py

    from django.contrib import admin
    from django.urls import path
    from django.views.generic.base import TemplateView
    
    urlpatterns = [
        path('', TemplateView.as_view(template_name='base.html'), name='home'),
        path('admin/', admin.site.urls),
    ]
    
  • templates/base.html

    {% load i18n %}
    {% get_current_language as LANGUAGE_CODE %}
    <!DOCTYPE html>
    <html lang="{{ LANGUAGE_CODE }}">
    <body>
    <pre>LANGUAGE_CODE = {{ LANGUAGE_CODE }}</pre>
    <body>
    </html>
    

With the Django generated code and my few above updates I can see different language code if I switch the language of my browser visiting http://localhost:8000/ after starting it with:

$ python manage.py runserver

Try my steps on your local environment and check if it works, and then compare your project to the code above.

Update

Try to use diffsettings to see "differences between the current settings file and Django’s default settings".

Hydrate answered 8/8, 2018 at 16:50 Comment(5)
A simple project like this works correctly; however the issue is the comparison of my project to one like this. I am not sure what I could miss that is causing the wrong language to be returned.Hardie
So have you tried my simple test locally? Can you provide more details about your project to permit recreate your environment ?Hydrate
For what it's worth, I also setup a simple project, tested against 2.0 and 2.1, and found that both versions worked as expected. I was able to reproduce the default (en-us) if I had LANGUAGES defined to an empty list.Aishaaisle
I can't see your code but I would check the diff of settings and try to use only defaults adding your settings one by one to see which setting broke the language tag.Hydrate
Can I use get_current_language without using LocaleMiddleware? => #59302478Kibler
I
0

Had the same problem. In my case, the function was called async and always returned the default language.

SOLUTION: pass language from 'main' context.

Code like in this example:

def get_context_data( self, **kwargs ):
    context = super().get_context_data(**kwargs)
    lng_code = get_language() # -> 'de'

    @sync_to_async
    def get_data():

        context['data1'] = Model1.objects.filter(language==get_language()) # get_language() -> 'en'

    @sync_to_async
    def get_data2():
        ...

    @sync_to_async
    def get_data3():
        ...

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(
            asyncio.gather(
                    get_data1(),
                    get_data2(),
                    get_data3()
                    ))
    loop.close()
Ilana answered 12/9, 2022 at 9:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.