Evgenii Legotckoi
June 1, 2022, 2:30 p.m.

Django - Lesson 059. Saving the selected language in user settings

In this article, I would like to show an example of how you can make a link on the site so that the user can switch between languages on the site.

But I will show a more advanced version of this functionality, namely saving the selected language in the user table, as well as redirecting the user to a page with the correct language that was selected by the user, if they are of course authorized. That is, if the user has set the German language for himself, then when going to the site via an English link, the site will automatically redirect the user to the page with the German language.

To do this, we need to add a language code field to the user model, I hope that everyone is already using their user model in Django instead of the default one.
Rewrite the standard Django language setup function, and also add a Middleware that will process the urls requested from the site.

Among other things, this functionality will be useful in order to generate letters with the correct language for registered users.

This article is based on Django 4 and may not be suitable for older versions of Django.

Set up the user model

Let's add the language field to the user model, in which the code of the selected language will be added, by default it will be the language that is the main language for your site.

Файл yourapp/yourauthapp/models.py

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.conf import settings
  4. from django.contrib.auth.models import AbstractUser
  5. from django.db import models
  6.  
  7.  
  8.  
  9. class Group(DjangoGroup):
  10. class Meta:
  11. proxy = True
  12.  
  13.  
  14. class User(AbstractUser):
  15. language = models.CharField(max_length=10,
  16. choices=settings.LANGUAGES,
  17. default=settings.LANGUAGE_CODE)

Accordingly, we will create a migration and execute it.

  1. python manage.py makemigrations
  2. python manage.py migrate

Add a view to set the language

Файл yourapp/yourauthapp/views.py

There are two important points here:

  • The original function is to use a form and send a POST message. I prefer the link with the language code.
  • In case the user is authorized,
  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.conf import settings
  4. from django.http import HttpResponseRedirect, HttpResponse
  5. from django.urls import translate_url
  6. from django.utils.http import url_has_allowed_host_and_scheme
  7. from django.utils.translation import check_for_language
  8.  
  9.  
  10. def set_language(request, lang_code):
  11.  
  12. next_url = request.POST.get('next', request.GET.get('next'))
  13. if (
  14. (next_url or request.accepts('text/html')) and
  15. not url_has_allowed_host_and_scheme(
  16. url=next_url,
  17. allowed_hosts={request.get_host()},
  18. require_https=request.is_secure(),
  19. )
  20. ):
  21. next_url = request.META.get('HTTP_REFERER')
  22. if not url_has_allowed_host_and_scheme(
  23. url=next_url,
  24. allowed_hosts={request.get_host()},
  25. require_https=request.is_secure(),
  26. ):
  27. next_url = '/'
  28. response = HttpResponseRedirect(next_url) if next_url else HttpResponse(status=204)
  29.  
  30. if request.method == 'GET': # Change method from POST to GET, we want use url parameters for this funcionality
  31.  
  32. if lang_code and check_for_language(lang_code):
  33. if next_url:
  34. next_trans = translate_url(next_url, lang_code)
  35. if next_trans != next_url:
  36. response = HttpResponseRedirect(next_trans)
  37. response.set_cookie(
  38. settings.LANGUAGE_COOKIE_NAME, lang_code,
  39. max_age=settings.LANGUAGE_COOKIE_AGE,
  40. path=settings.LANGUAGE_COOKIE_PATH,
  41. domain=settings.LANGUAGE_COOKIE_DOMAIN,
  42. secure=settings.LANGUAGE_COOKIE_SECURE,
  43. httponly=settings.LANGUAGE_COOKIE_HTTPONLY,
  44. samesite=settings.LANGUAGE_COOKIE_SAMESITE,
  45. )
  46.  
  47. # Important part of code, set language to user, if user is authenticated
  48. if request.user.is_authenticated:
  49. request.user.language = lang_code
  50. request.user.save(update_fields=['language'])
  51.  
  52. return response

Include set_language in your main urls.py file

Now you need to connect the view so that you can generate links for switching the language in templates.

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.urls import path
  4.  
  5. from yourauthapp import views
  6.  
  7.  
  8. urlpatterns = [
  9. path('lang/<str:lang_code>/', views.set_language, name='lang'),
  10. ...
  11. ]

Generation of links in the template

Note that I add ?next={{ request.path }} to the link to get the correct redirect to the original page where the user chose to switch the language.

  1. {% get_available_languages as LANGUAGES %}
  2. {% get_language_info_list for LANGUAGES as languages %}
  3. {% for language in languages %}
  4. <a href="{% url 'lang' language.code %}?next={{ request.path }}">{{ language.name_local }}</a>
  5. {% endfor %}

yourapp/yourauthapp/middleware.py

And now let's write a middleware that will automatically redirect the user to a page with the appropriate language.

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.http import HttpResponseRedirect
  4. from django.urls import translate_url
  5. from django.utils import translation
  6. from django.utils.deprecation import MiddlewareMixin
  7.  
  8.  
  9. class LocaleMiddleware(MiddlewareMixin):
  10.  
  11. def process_response(self, request, response):
  12. user = getattr(request, 'user', None)
  13. if not user:
  14. return response
  15.  
  16. if not user.is_authenticated:
  17. return response
  18.  
  19. user_language = getattr(user, 'language', None)
  20. if not user_language:
  21. return response
  22.  
  23. next_trans = translate_url(request.path, user_language)
  24. if next_trans != request.path:
  25. translation.activate(user_language)
  26. response = HttpResponseRedirect(next_trans)
  27.  
  28. return response

It remains only to enable middleware in the site settings and everything will work.

  1. MIDDLEWARE = [
  2. 'django.middleware.security.SecurityMiddleware',
  3. 'django.contrib.sessions.middleware.SessionMiddleware',
  4. 'django.middleware.common.CommonMiddleware',
  5. 'django.middleware.csrf.CsrfViewMiddleware',
  6. 'django.middleware.locale.LocaleMiddleware',
  7. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  8. 'django.contrib.messages.middleware.MessageMiddleware',
  9. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  10.  
  11. # add your middleware for redirect user
  12. 'yourauthapp.middleware.LocaleMiddleware',
  13. ]

Conclusion

Now all authorized users will always be redirected to pages with the language they have chosen.

Of course, for unauthorized users this will not work, but at least they will always be able to choose the language they want from those available on your site.

By article asked0question(s)

6
IscanderChe
  • June 1, 2022, 2:54 p.m.

Добрый день.

Помимо прочего, данный функционал будет полезен для того, чтобы формировать письма с правильным языком для зарегистрированных пользователей.

Уведомление об этой статье на почту мне пришло почему-то на английском.

Evgenii Legotckoi
  • June 1, 2022, 3:57 p.m.
  • (edited)

Добрый день!
Потому что на этом сайте это не сделано :)
Я сейчас работаю над вторым проектом и делаю работу над ошибками :)
Позже буду ремонтировать и здесь, нужно ещё на более новую версию Django мигрировать.

Будет интересно посмотреть ваш новый проект, Евгений. Уж как никак, но ваши статьи самые лучшие и подходят на уровень детального создания, ведь по вашим статьям я делал много для своего проекта. Надеюсь у вас будут перспективы создать инструкции с новыми вашими познаниями и новым кодом :)

Благодарю за отзыв. Да, я понемногу буду писать статьи с информацией из нового проекта.
А сам проект позже анонсирую, также повешаю в сайдбаре анонсовый виджет.

Буду ждать, Евгений! Потому что буду разрабатывать новый проект, как альманах программиста новичка.)

NSProject
  • June 5, 2022, 4:47 p.m.

Можно пояснительную записку настроек. Что примерно указывается

  1. path=settings.LANGUAGE_COOKIE_PATH,
  2. domain=settings.LANGUAGE_COOKIE_DOMAIN,
  3. secure=settings.LANGUAGE_COOKIE_SECURE,
  4. httponly=settings.LANGUAGE_COOKIE_HTTPONLY,
  5. samesite=settings.LANGUAGE_COOKIE_SAMESITE,
Evgenii Legotckoi
  • June 6, 2022, 4:18 p.m.

Это всё настройки для языка в Django, по умолчанию ничего менять не нужно.
А сам этот кусок кода скопирован из оригинальной функции.

Подробнее написано в официальной документации Django settings .
Там написаны и значения по умолчанию.

NSProject
  • June 6, 2022, 8:57 p.m.

Я как так сказать новичёк в Python и Django в целом. Читал документацию и вот по этому мне показалось сразу что это оттуда. Немного маштабируемо по своему усмотрению. Однако все настройки из settings возможно индивидуальны. Это как я понимаю те настройки что я делаю сам.

Evgenii Legotckoi
  • June 7, 2022, 1:06 p.m.

Да, вы можете в своём settings файле определить все эти переменные и значения по умолчанию будут переписаны.

c
  • Dec. 2, 2023, 4:34 a.m.

It tries to do language translation in API views. That's why it sends or receives the same API request twice. Do you have any suggestions on this? Example: stripe webhook.

"GET /warehouse/webhook/ HTTP/1.1" 302
"GET /en/warehouse/webhook/ HTTP/1.1" 200

Evgenii Legotckoi
  • Dec. 3, 2023, 7:39 p.m.

It is redirect from untranslated url to translated url. It is normal behavior for mutlilanguage web site based on the Django.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
  • Last comments
  • Evgenii Legotckoi
    March 9, 2025, 9:02 p.m.
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    March 9, 2025, 4:14 p.m.
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
  • ИМ
    Nov. 22, 2024, 9:51 p.m.
    Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
  • Evgenii Legotckoi
    Oct. 31, 2024, 11:37 p.m.
    Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
  • A
    Oct. 19, 2024, 5:19 p.m.
    Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html