У цій статті я хотів би показати приклад того, як можна зробити на сайті посилання, щоб користувач міг перемикатися між мовами на сайті.
Але я покажу більш просунутий варіант подібного функціоналу, а саме збереження вибраної мови в таблиці користувача, а також перенаправлення користувача на сторінку з правильною мовою, яку вибрано користувачем, якщо вони звичайно авторизовані. Тобто, якщо користувач налаштував собі німецьку мову, то при переході на сайт за англійським посиланням сайт автоматично перенаправить користувача на сторінку з німецькою мовою.
Для цього нам знадобиться додати поле коду мови в модель користувача, сподіваюся, що всі вже використовують свою модель користувача Django замість стандартної.
Переписати стандартну функцію встановлення мови Django, а також додати Middleware, який оброблятиме запитані з сайту url.
Крім того, цей функціонал буде корисним для того, щоб формувати листи з правильною мовою для зареєстрованих користувачів.
Стаття написана на основі Django 4 і може не підходити для старших версій Django.
Налаштування моделі пользователя
Додамо в модель користувача поле language, в яке додаватиме код обраної мови, за замовчуванням буде та мова, яка є для вашого сайту основною.
Файл yourapp/yourauthapp/models.py
# -*- coding: utf-8 -*- from django.conf import settings from django.contrib.auth.models import AbstractUser from django.db import models class Group(DjangoGroup): class Meta: proxy = True class User(AbstractUser): language = models.CharField(max_length=10, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE)
Відповідно створимо міграцію та виконаємо її.
python manage.py makemigrations python manage.py migrate
Додамо view для встановлення мови
Файл yourapp/yourauthapp/views.py
Тут є два важливі моменти:
- Оригінальна функція передбачає використання форми і відправки POST повідомлення. Я ж віддаю перевагу посиланню з кодом мови.
- У випадку, якщо користувач авторизований,
# -*- coding: utf-8 -*- from django.conf import settings from django.http import HttpResponseRedirect, HttpResponse from django.urls import translate_url from django.utils.http import url_has_allowed_host_and_scheme from django.utils.translation import check_for_language def set_language(request, lang_code): next_url = request.POST.get('next', request.GET.get('next')) if ( (next_url or request.accepts('text/html')) and not url_has_allowed_host_and_scheme( url=next_url, allowed_hosts={request.get_host()}, require_https=request.is_secure(), ) ): next_url = request.META.get('HTTP_REFERER') if not url_has_allowed_host_and_scheme( url=next_url, allowed_hosts={request.get_host()}, require_https=request.is_secure(), ): next_url = '/' response = HttpResponseRedirect(next_url) if next_url else HttpResponse(status=204) if request.method == 'GET': # Change method from POST to GET, we want use url parameters for this funcionality if lang_code and check_for_language(lang_code): if next_url: next_trans = translate_url(next_url, lang_code) if next_trans != next_url: response = HttpResponseRedirect(next_trans) 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, ) # Important part of code, set language to user, if user is authenticated if request.user.is_authenticated: request.user.language = lang_code request.user.save(update_fields=['language']) return response
Підключіть set_language у вашому головному файлі urls.py
Тепер потрібно підключити view, щоб можна було генерувати посилання для перемикання мови шаблонів.
# -*- coding: utf-8 -*- from django.urls import path from yourauthapp import views urlpatterns = [ path('lang/<str:lang_code>/', views.set_language, name='lang'), ... ]
Генерування посилань у шаблоні
Зверніть увагу, що я додаю ?next={{ request.path }} до посилання, щоб отримати правильний редирект на вихідну сторінку, на якій користувач вирішив переключити мову.
{% get_available_languages as LANGUAGES %} {% get_language_info_list for LANGUAGES as languages %} {% for language in languages %} <a href="{% url 'lang' language.code %}?next={{ request.path }}">{{ language.name_local }}</a> {% endfor %}
yourapp/yourauthapp/middleware.py
А тепер напишемо middleware, який автоматично вироблятиме редирект користувача на сторінку з відповідною мовою.
# -*- coding: utf-8 -*- from django.http import HttpResponseRedirect from django.urls import translate_url from django.utils import translation from django.utils.deprecation import MiddlewareMixin class LocaleMiddleware(MiddlewareMixin): def process_response(self, request, response): user = getattr(request, 'user', None) if not user: return response if not user.is_authenticated: return response user_language = getattr(user, 'language', None) if not user_language: return response next_trans = translate_url(request.path, user_language) if next_trans != request.path: translation.activate(user_language) response = HttpResponseRedirect(next_trans) return response
Залишається тільки підключити middleware у налаштуваннях сайту і все буде працювати.
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', # add your middleware for redirect user 'yourauthapp.middleware.LocaleMiddleware', ]
Висновок
Тепер всі авторизовані користувачі завжди будуть перенаправлятися на сторінки з мовою, яку вони вибрали.
Звичайно для неавторизованих користувачів так працювати не буде, але вони принаймні завжди зможуть вибрати ту мову, яку захочуть з доступних на вашому сайті.
Добрый день.
Уведомление об этой статье на почту мне пришло почему-то на английском.
Добрый день!
Потому что на этом сайте это не сделано :)
Я сейчас работаю над вторым проектом и делаю работу над ошибками :)
Позже буду ремонтировать и здесь, нужно ещё на более новую версию Django мигрировать.
Будет интересно посмотреть ваш новый проект, Евгений. Уж как никак, но ваши статьи самые лучшие и подходят на уровень детального создания, ведь по вашим статьям я делал много для своего проекта. Надеюсь у вас будут перспективы создать инструкции с новыми вашими познаниями и новым кодом :)
Благодарю за отзыв. Да, я понемногу буду писать статьи с информацией из нового проекта.
А сам проект позже анонсирую, также повешаю в сайдбаре анонсовый виджет.
Буду ждать, Евгений! Потому что буду разрабатывать новый проект, как альманах программиста новичка.)
Можно пояснительную записку настроек. Что примерно указывается
Это всё настройки для языка в Django, по умолчанию ничего менять не нужно.
А сам этот кусок кода скопирован из оригинальной функции.
Подробнее написано в официальной документации Django settings .
Там написаны и значения по умолчанию.
Я как так сказать новичёк в Python и Django в целом. Читал документацию и вот по этому мне показалось сразу что это оттуда. Немного маштабируемо по своему усмотрению. Однако все настройки из settings возможно индивидуальны. Это как я понимаю те настройки что я делаю сам.
Да, вы можете в своём settings файле определить все эти переменные и значения по умолчанию будут переписаны.
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
It is redirect from untranslated url to translated url. It is normal behavior for mutlilanguage web site based on the Django.