Создание мультиязычного веб-сайта с помощью.. Flask.Babel
Не так уж много примеров для мультиязычного языка. Здесь мы следуем рекомендациям из Flask документации.
С единым языком проблем не возникает, мы просто забываем об остальном мире и создаем наше Flask приложение для работы с одним языком. Мы начинаем испытывать головную боль, когда веб-сайт должен поддерживать несколько языков. Что такое веб-сайт, поддерживающий несколько языков? Сколько языков будет поддерживаться и какие языки? Для английского языка существуют, например, en-GB и en-US. Какие разделы сайта должны быть доступны на всех языках? Какие части сайта вообще существуют? Я ограничусь здесь ответом на самые тривиальные вопросы. Для удобства ознакомления вы также можете ознакомиться, например, с руководством по подключаемым модулям Wordpress Polylang, см. ниже.
Когда вы создаете веб-сайт без поддержки нескольких языков, вы используете urls для своего контента, когда вы хотите добавить дополнительные языки, вы должны поддерживать все urls, т.е. то, что уже было создано. С точки зрения SEO вам лучше начать со всех мультиязычных компонентов, даже если вы сомневаетесь, что когда-либо будете добавлять другой язык.
Выбор языка
Когда язык находится в куки (сессии) правильный просмотр языка может быть проблемой, когда куки отключены. С языком в домене / URL эта проблема устранена, а также сайт является более SEO дружественным.
Вариант 1: язык расширения домена
example.com
example.es
example.pl
Пример: Тойота
https://www.toyota.de
https://www.toyota.es
Вариант 2: язык субдомена
Э...example.com
э... э...example.com
э... э... э... э... э... э... э... э...example.com
Пример: cnn
https://edition.cnn.com
https://cnnespanol.cnn.com
Вариант 3: язык в урльском варианте
example.com/en
example.com/es /pl /en /es
example.com/pl
Переведенные урны
Переведенные урны очень дружелюбны, но также представляют большую сложность:
https://edition.cnn.comРазвлечения / секс-работы / секс-индустрия /восприятие /принятие/
Некоторые веб-сайты не имеют переведенных писем:
https://www.tesla.com/nl_NL/model3/design#battery
https://www.tesla.com/de_CH/model3/design#battery
Если мы хотим иметь переведенные языковые урлы, и почему бы и нет, то нам также нужно несколько конечных точек для функции просмотра:
@pages.route('/<lang_code>/about-us', methods=['GET', 'POST'])
@pages.route('/<lang_code>/uber-uns', methods=['GET', 'POST'])
def about():
return render_template(...)
Конечно, мы хотим, чтобы это было как-то автоматизировано... сложно.
Делая выбор
На данный момент я фокусируюсь на сайте с "языковым id" на пути URL, см. выше вариант 3, и я не буду иметь дело с переведенными URL. Потому что мы используем Flask, мы используем Flask-Babel для наших переводов. Некоторые тексты, например, блоги, категории, теги, находятся в базе данных. Мы разберемся с этим позже.
Вы можете захотеть сайт с основным языком без "языкового id" в URL пути и другие языки с "языковым id" в URL пути. Я не знаю, как это сделать Flask в данный момент, и считаю, что это очень сильно усложняет ситуацию, а также думаю о SEO. Резюме: Я думаю, не плохая идея начать с языка на пути урны.
В первой реализации я использовал cookie для выбора языка, теперь я должен удалить его и использовать язык в url. К счастью, Flask документация дает хорошую информацию о интернационализации. Я предлагаю вам прочитать это (я делал это много раз). У меня их много, для просмотра главной страницы.py я добавляю следующее в просмотр:
...
home_blueprint = Blueprint('home', __name__)
# lang_code in urls
@home_blueprint.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', g.lang_code)
@home_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
url_lang_code_items_values = get_url_lang_code_items_values()
url_lang_code_default_item_value = get_url_lang_code_default_item_value()
g.lang_code = url_lang_code_default_item_value
if values:
if 'lang_code' in values:
if values['lang_code'] in url_lang_code_items_values:
g.lang_code = values.pop('lang_code', None)
else:
pass
...
Функция get_url_lang_lang_code_items_values() возвращает список языковых кодов: en, nl, es, and function get_url_lang_code_default_item_value() возвращает en, поэтому английский язык является языком по умолчанию. Затем в __init__.py я регистрирую дом :
from .blueprints.home.views import home_blueprint
app.register_blueprint(home_blueprint, url_prefix='/<lang_code>')
Что произойдет, если мы напечатаем урну без пути или совершенно случайный урл? Появится сообщение об ошибке:
TypeError: homepage() got an unexpected keyword argument 'lang_code'
Flask Документы не дают решения, но после некоторых головных болей (опять же) я думаю, что нашел решение этой проблемы, используя обработчик before_request. В этом обработчике я смотрю на запрос url. Путь этой урны разделен на части. Первая часть должна быть нашей речью. Если первая часть находится в нашем списке языков, то просто продолжайте. Если страница не может быть найдена, сгенерируется 404, страница не найдена, что вполне нормально. Если первая часть не является нашим списком языков, то обработчик before_request возвращает URL перенаправления на главную страницу языка по умолчанию.
После этого сайт был показан без стилей и я получил странные сообщения об ошибках в консоли инструментов разработчика. Решение заключалось в исключении статического каталога. Итак, вот что происходит в обработчике запроса before_request:
@app.before_request
def before_request():
# try to handle missing lang_code in url interceptor
url_lang_code_items_values = get_url_lang_code_items_values()
url_lang_code_default_item_value = get_url_lang_code_default_item_value()
# check for a valid url = starts with /lang_code/
request_path = request.path.strip('/')
request_path_parts = urlparse(request_path).path.split('/')
if request.method in ['GET'] and len(request_path_parts) > 0:
request_path_part_0 = request_path_parts[0]
# do nothing with static urls !!!
if request_path_part_0 != 'static' and request_path_part_0 not in url_lang_code_items_values:
# fucked up url
redir_url_parts = []
redir_url_parts.append( request.url_root.strip('/') )
redir_url_parts.append( url_lang_code_default_item_value.strip('/') )
redir_url = '/'.join(redir_url_parts)
return redirect(redir_url)
Это работает, но как мы можем изменить язык?
В шаблоне base.html у меня есть выпадающий переключатель языка:
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ language_selected }}
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ request.path }}?lc=en_US">{{ _('EN') }}</a>
<a class="dropdown-item" href="{{ request.path }}?lc=nl_NL">{{ _('NL') }}</a>
<a class="dropdown-item" href="{{ request.path }}?lc=es_ES">{{ _('ES') }}</a>
</div>
</li>
Затем мы активируем Babel язык при смене языка:
@babel.localeselector
def get_locale():
request_lc = request.args.get('lc')
if not request_lc:
if not 'lang_code' in g:
# use default
g.lang_code = 'en'
request_lc = 'en_US'
else:
if g.lang_code == 'es':
request_lc = 'es_ES'
elif g.lang_code == 'nl':
request_lc = 'nl_NL'
else:
request_lc = 'en_US'
else:
# set g.lang_code to the requested language
if request_lc == 'nl_NL':
g.lang_code = 'nl'
elif request_lc == 'es_ES':
g.lang_code = 'es'
else:
request_lc = 'en_US'
g.lang_code = 'en'
#sys.exit()
session['lc'] = request_lc
return request_lc
Хорошо, он работает сейчас, но должен быть оптимизирован. Также на данный момент все еще существуют две проблемы:
- Когда язык изменен, он не отображается в url после этого.
Тебе нужно перейти на новую страницу. После изменения языка с помощью выпадающего списка URL не отображает язык в URL сразу, а только на следующем щелчке мыши. Может, переместить Babel код в обработчик before_request? - Многие вызовы url_defaults по умолчанию для каждого вызова, который я хотел бы иметь код:
@home_.url_defaults @home_
.url_value_preprocessor
в __init__.py, а не в blueprint view.py, но это не работает.
Зачем мне это? Потому что мне не нравится дублировать один и тот же код и я вижу много обращений к @auth_.url и т.д. Я считаю, что они должны быть сделаны один раз в __init__.py, но, возможно, я ошибаюсь.
Ссылки / кредиты
Flask Series: Internationalization
https://damyanon.net/post/flask-series-internationalization/
Flask-multilang-demo
https://github.com/DusanMadar/Flask-multilang-demo
How to Easily Create a Multilingual WordPress Site
https://www.wpbeginner.com/beginners-guide/how-to-easily-create-a-multilingual-wordpress-site/
Internationalized Application URLs
https://flask.palletsprojects.com/en/1.1.x/patterns/urlprocessors/
Multilingual flask application
https://stackoverflow.com/questions/3420897/multilingual-flask-application
Set languages and locales
https://docs.microsoft.com/en-us/windows-hardware/customize/mobile/mcsf/set-languages-and-locales
Подробнее
Babel Flask Multilanguage
Оставить комментарий
Комментируйте анонимно или войдите в систему, чтобы прокомментировать.
Комментарии (1)
Оставьте ответ
Ответьте анонимно или войдите в систему, чтобы ответить.
From where 'get_url_lang_code_items_values()' and 'get_url_lang_code_default_item_value()' come from?
Недавний
- Скрытие первичных ключей базы данных 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 проверка параметров запроса с помощью схем Маршмэллоу