Flask Многоязыковая обработка, переключение и исключение 404 Страница не найдена
В этой заметке мы обсуждаем несколько условий при обработке языка в url, используя язык по умолчанию и используя список доступных языков.
Как реализовать многоязычие Flask объясняется в документах Flask , см. ссылки ниже. Но это только начало. Вам необходимо более глубокое понимание процесса обработки особых случаев, таких как возврат к языку по умолчанию, переключение языка и исключение 404 Страница не найдена.
Предположения
В оставшейся части этой статьи мы используем код языка 'lang_code', который доступен в URL, это первая часть URL, например:
https://www.example.com/en
https://www.example.com/en/login
Мы также используем Flask-Babel для переводов. Я использую blueprints и регистрирую их в create_app() следующим образом:
# authentication (shared)
from shared.blueprints.auth.views import auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/<lang_code>/auth')
# pages (shared)
from shared.blueprints.pages.views import pages_blueprint
app.register_blueprint(pages_blueprint, url_prefix='/<lang_code>')
В качестве значения выбранного языка мы используем g.lang_code. Я использую переменную сессии не для запоминания языка, а полагаюсь на доступность языка в каждом запросе.
Flask Многоязычная обработка данных
Flask обрабатывает запрос на нескольких языках следующим образом:
Во-первых, вызывается url_value_preprocessor() для извлечения языка из примера url:
@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
# pop lang_code from url and set g.lang_code
...
if 'lang_code' in values:
g.lang_code = values.pop('lang_code')
Затем вызывается функция locale_selector() Babels для обеспечения перевода страницы, например:
@babel.localeselector
def get_locale():
return g.get('lang_code')
Наконец url_defaults() вызывается перед тем, как страница будет собрана для замены <lang_code> на lang_code> в urls, например:
@pages_blueprint.url_defaults
def add_language_code(endpoint, values):
# stuff g.lang_code in urls
...
values.setdefault('lang_code', g.lang_code)
Это довольно просто, но, как вы видите, могут возникнуть условия, когда код языка изменяется, недоступен или даже недействителен. Самое главное - убедиться, что g.lang_code всегда установлен в допустимый язык перед вызовом localeselector() и url_defaults(). Ниже рассматривается ряд условий.
Flask Многоязычная обработка: переключение посетителя на другой язык
Для переключения на другой язык мы можем использовать GET для текущего запроса с дополнительным параметром lang_code:
<a href="{{ request.script_root + request.path }}?lc=en">English</a>
<a href="{{ request.script_root + request.path }}?lc=de">Deutsch</a>
Мы должны расширить функциональность url_value_preprocessor() для поддержки языкового переключателя. Упрощенно, этот дополнительный код выглядит так:
@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
...
request_lang_code = request.args.get('lc')
if request_lang_code:
g.lang_code = request_lang_code
...
Flask Многоязыковая обработка: отсутствует язык в url и языке по умолчанию
Это не может быть ошибкой, потому что вы можете захотеть, чтобы vistor напечатал ваш URL домена и был "перенаправлен" на страницы языка по умолчанию. Но это также может случиться, если посетитель набирает неправильный URL, (поисковый) бот набирает неправильный URL. Опять же мы можем справиться с этим в url_value_preprocessor(). В этом случае мы устанавливаем значение lang_code на lang_code языка по умолчанию:
@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
...
if g.get('lang_code') is None:
g.lang_code = default_lang_code
Flask Многоязыковая обработка: язык не поддерживается
Наше приложение поддерживает только ограниченное количество языков, например
available_lang_codes = ['en', 'de']
Опять же мы можем обработать некорректный языковой регистр в url_value_preprocessor(). Если язык недействителен, мы устанавливаем для Lang_code значение lang_code языка по умолчанию:
@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
...
if 'lang_code' in values:
lang_code = values.pop('lang_code')
if lang_code not in available_lang_codes:
g.lang_code = default_lang_code
Flask Многоязычная обработка: Страница Не найдена (404) Ошибка
Это вызвало у меня головные боли, потребовалось немного отладки, чтобы понять, что в этом случае поток отличается. Здесь происходит следующее: если ни один из blueprints не соответствует запросу url, вызов url_value_preprocessor() НИКОГДА не выполняется. Например, с blueprints , показанным ранее, это действительный url:
http://127.0.0.1:8000/en/auth/login
но этот урна дает 404 исключения:
http://127.0.0.1:8000/en/auth/login/something
Что здесь делать? Ответ заключается в обработке этого условия в Flask _@before_request. При нормальном потоке до запроса() вызывается после (!) url_value_preprocessor():
@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
....
@app.before_request
def before_request():
....
В случае исключения 404 вызов функции url_value_preprocessor() НЕ выполняется, а выполняется до вызова функции_request():
@app.before_request
def before_request():
....
Обычно url_value_preprocessor() устанавливает g.lang_code в значение, языковой код. Но на 404 функция url_value_preprocessor() не вызывается и g.lang_code не задается. В функции before_request() мы проверяем значение g.lang_code. Если он не установлен, мы можем обработать запрос url самостоятельно. Если первая часть является правильным кодом языка, мы предполагаем, что это то, что нам нужно, и устанавливаем g.lang_code. В противном случае мы установим g.lang_code на язык по умолчанию. Затем, когда вызывается обработчик 404, страница может быть отображена на нужном языке.
Резюме
Я не использовал переменную сессии для хранения выбранного языка, а полагался на язык в url. Это прекрасно работает, если мы работаем со всеми типами условий, таких как отсутствие языка. Наиболее важным является установка языка в g перед выполнением любой другой обработки.
Ссылки / кредиты
Flask Series: Internationalization
https://damyanon.net/post/flask-series-internationalization/
Flask-Babel
https://pythonhosted.org/Flask-Babel/
Using URL Processors
https://flask.palletsprojects.com/en/1.1.x/patterns/urlprocessors/
Подробнее
Babel Flask Multilanguage
Недавний
- Скрытие первичных ключей базы данных UUID вашего веб-приложения
- Don't Repeat Yourself (DRY) с Jinja2
- SQLAlchemy, PostgreSQL, максимальное количество строк для user
- Показать значения в динамических фильтрах SQLAlchemy
- Безопасная передача данных с помощью шифрования Public Key и pyNaCl
- rqlite: альтернатива dist с высокой степенью готовности и SQLite
Большинство просмотренных
- Используя Python pyOpenSSL для проверки SSL-сертификатов, загруженных с хоста
- Использование UUID вместо Integer Autoincrement Primary Keys с SQLAlchemy и MariaDb
- Подключение к службе на хосте Docker из контейнера Docker
- Использование PyInstaller и Cython для создания исполняемого файла Python
- SQLAlchemy: Использование Cascade Deletes для удаления связанных объектов
- Flask Удовлетворительный запрос API проверка параметров запроса с помощью схем Маршмэллоу