12

Is there any way to change the value of LANGUAGE_CODE variable in settings.py dynamically on clicking a button (sending a request)?

I want the user to have their own "default language" set for their account.

Right now the user can select their preferred language using a drop-down list, and the website gets translated perfectly, and because Django picks up the browser's language, the user need not to re-select their language after they reopen the website from the same browser.

But when they open the website from a different browser, the default language is again "English" because of the LANGUAGE_CODE variable set to en-us in settings.py.

So what I want to do is make each user have an option to select their desired language as default for them. I want to do this by making an another(similar) drop-down and ask user to select a language they want as "default" and hit the save button, and on saving, I want to change LANGUAGE_CODE's value to the one selected by the user (i.e change it dynamically). But I don't know how to change the value of LANGUAGE_CODE dynamically.

Also, there is one more problem with this approach. Say even if I was able to change this LANGUAGE_CODE variable dynamically, it would make the website have the selected language as default for ALL THE USERS and not only for that one specific user who changed it, according to Django's documentation:

LANGUAGE_CODE:

  • If the locale middleware isn’t in use, it decides which translation is served to all users.

I researched a lot, but couldn't find a solution for me. I am very new to Internationalization. Please help.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Yoshita Arora
  • 475
  • 2
  • 7
  • 24

3 Answers3

11

Of course there is, that is the whole point of translations. You've confused yourself by thinking of the "default" language; something that they've chosen is not the default, by definition.

The Django docs explain how to set the active language for a user explicitly. You can set this on save exactly as you describe.

You probably also want to re-set this value on login, again by passing the value from the user's profile.

Flimm
  • 136,138
  • 45
  • 251
  • 267
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
3

referencing to what stated in the question:

I want the user to have their own "default language" set for their account.

The translation of a Django app with the preferred language selected by a registered user can be done with the middleware django-user-language-middleware. This allows easy translation of your Django app by looking at the selected language in the user.language field (or what the question defines as "default language" of a user).

Usage:

  1. Add a language field to your user model:

    class User(auth_base.AbstractBaseUser, auth.PermissionsMixin):
        # ...
        language = models.CharField(max_length=10,
                                    choices=settings.LANGUAGES,
                                    default=settings.LANGUAGE_CODE)
    
  2. Install the middleware from pip:

    pip install django-user-language-middleware

  3. Add it to your middleware class list in settings to listen to requests:

    MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
        ...
        'user_language_middleware.UserLanguageMiddleware',
        ...
    ]
    

I hope this may help people landing on this question in the future.

Laura Barluzzi
  • 111
  • 1
  • 3
  • 2
    This is only working If you create an new project or app from scratch. Because the AbstractBaseUser model need to defined before the first migration. If you can't reset your migrations and Database you have to overwrite the middleware for example. – Tobit Mar 19 '19 at 12:17
  • Comment is old but, you can always move it to `UserProfile` if you're stuck with the standard User, but always start w/ `AbstractUser`!!! – nitsujri Mar 08 '23 at 07:39
  • @laura-barluzzi, any chance of an update from this very useful package now that storing language info in the django session is deprecated? – Skratt Jun 27 '23 at 19:29
0

You can change and save LANGUAGE_CODE in settings.py with i18n switcher so the language is not changed even if you use different browsers.

First, you need to do the following 3 steps:

  1. Add lang field to User model following one of two ways(my answer) to create custom User model. *I recommend more customizable way(my answer) than less customizable way(my answer)

    lang = models.CharField(max_length=20, blank=True)
    
  2. Set translation(English and French) in Djnago following my answer.

  3. Create i18n switcher for both or either Django and/or Django Admin following my answer and my answer respectively.

Next, create special/middleware/, special/views/ and special/conf/urls/ folders with __init__.py(Empty file) and copy locale.py, i18n.py and i18n.py from django/middleware/locale.py, django/views/i18n.py and django/conf/urls/i18n.py in your virtual environment to special/middleware/, special/views/ and special/conf/urls/ folders respectively as shown below:

django-project
 |-core
 |  |-settings.py
 |  |-urls.py
 |  └-special
 |     |-middleware
 |     |  |-__init__.py
 |     |  └-locale.py # Here
 |     |-views
 |     |  |-__init__.py
 |     |  └-i18n.py # Here
 |     └-conf
 |        |-__init__.py
 |        └-urls
 |           |-__init__.py
 |           └-i18n.py # Here
 |-my_app1
 |  |-views.py
 |  |-urls.py
 |  |-models.py
 |  |_admin.py
 |  └-apps.py
 |-my_app2
 |-templates
 |  └-index.html  
 └-locale
    └-fr
       └-LC_MESSAGES
          └-django.po

Then, replace 'django...LocaleMiddleware', with 'core...LocaleMiddleware', in core/settings.py as shown below:

# "core/settings.py"

MIDDLEWARE = [
    ...
    "django.contrib.sessions.middleware.SessionMiddleware",
    # 'django.middleware.locale.LocaleMiddleware',
    'core.special.middleware.locale.LocaleMiddleware',
    "django.middleware.common.CommonMiddleware",
]

Then, replace path(... include("django...")) with path(... include("core...")) in core/urls.py as shown below:

# "core/urls.py"

urlpatterns += [
    # path("i18n/", include("django.conf.urls.i18n"))
    path("i18n/", include("core.special.conf.urls.i18n"))
]

Then, add the code below to core/special/middleware/locale.py as shown below:

# "core/special/middleware/locale.py"

...
from django.contrib import auth # Add
...
class LocaleMiddleware(MiddlewareMixin):
    ...
    def process_request(self, request): 
        ...
        if (
            not language_from_path
            and i18n_patterns_used
            and not prefixed_default_language
        ):
            language = settings.LANGUAGE_CODE

        # ↓ For more customizable `User` model ↓
        user = auth.get_user(request)
        if user.is_authenticated and user.lang:
            language = user.lang
        # ↑ For more customizable `User` model ↑

        # ↓ For less customizable `User` model ↓
        user = auth.get_user(request)          
        if user.is_authenticated and user.userprofile.lang:
            language = user.userprofile.lang
        # ↑ For less customizable `User` model ↑
 
        translation.activate(language)
        request.LANGUAGE_CODE = translation.get_language()

Then, add the code below to core/special/views/i18n.py as shown below:

# "core/special/views/i18n.py"

...

def set_language(request):
    ...
            response.set_cookie(
                settings.LANGUAGE_COOKIE_NAME,
                lang_code,
                max_age=settings.LANGUAGE_COOKIE_AGE,
                path=settings.LANGUAGE_COOKIE_PATH,
                domain=settings.LANGUAGE_COOKIE_DOMAIN,
                secure=settings.LANGUAGE_COOKIE_SECURE,
                httponly=settings.LANGUAGE_COOKIE_HTTPONLY,
                samesite=settings.LANGUAGE_COOKIE_SAMESITE,
            )

            # ↓ For more customizable `User` model ↓
            user = request.user
            if user.is_authenticated:
                user.lang = lang_code
                user.save()
            # ↑ For more customizable `User` model ↑

            # ↓ For less customizable `User` model ↓
            user = request.user
            if user.is_authenticated:
                user.userprofile.lang = lang_code
                user.userprofile.save()
            # ↑ For less customizable `User` model ↑

    return response

Finally, replace from django... import set_language with from core... import set_language in core/special/conf/urls/i18n.py as shown below:

# "core/special/conf/urls/i18n.py"

...
# from django.views.i18n import set_language
from core.special.views.i18n import set_language
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129