Как сообщить Google о других языках на вашем сайте Django
Если у вас есть общедоступный сайт Django на нескольких языках, вы, вероятно, захотите сообщить об этом Google и другим поисковым системам.
Многоязычный сайт Django
Django имеет очень обширную структуру для обслуживания сайтов на нескольких языках. Ознакомимся с базовыми настройками, необходимыми для добавления дополнительных языков на сайт Django.
Активируйте фреймворк i18n в settings.py:
# settings.py USE_I18N = True
Определите поддерживаемые языки:
# settings.py
from django.utils.translation import gettext_lazy as _
LANGUAGES = [
('en', _('English')),
('ru', _('Russian')),
]
Установите язык по умолчанию:
# settings.py LANGUAGE_CODE = 'en'
ДобавьтеLocaleMiddleware:
# settings.py
MIDDLEWARE = [
# ...
'django.middleware.locale.LocaleMiddleware',
# ...
]
Используйте gettext, чтобы пометить тексты для перевода:
# app/views.py
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponse
def about(request) -> HttpResponse:
return HttpResponse(_('Hello!'))
Создайте файлы перевода:
$ python manage.py makemessages
Переведите текст:
msgid "Hello!" msgstr "Привет!"
Скомпилируйте файлы перевода:
$ python manage.py compilemessages
Настройте представления на нескольких языках с помощью i18n_patterns:
# urls.py
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls import url
from . import views
urlpatterns = i18n_patterns(
url(r'^about$', views.about, name='about'),
)
Убедитесь, что это работает:
$ curl http://localhost:8000/en/about Hello! $ curl http://localhost:8000/ru/about Привет!
Это всё!
Есть несколько дополнительных шагов, таких как добавление представления для переключения языка, но в целом ваш многоязычный сайт Django готов к работе!
Ссылка на другие языки с помощью hreflang
Чтобы поисковые системы знали, что страница доступна на другом языке, вы можете использовать специальный тег ссылки:
<link rel="alternate" hreflang="en" href="https://example.com/en" />
Тег имеет следующие атрибуты:
hreflang: Код языка связанной страницы.href: Ссылка на страницу на указанном языке.
Согласно рекомендациям Google и информации в Википедии, мы должны соблюдать следующие правила:
- Используйте абсолютные URL-адреса, включая схему.
- Ссылка должна быть действительной, а связанная страница должна быть на указанном языке.
- Перечислить все языки, включая текущий.
- Если язык X ссылается на язык Y, язык Y должен ссылаться обратно на язык X.
Чтобы реализовать следующее в Django, начните с перечисления доступных языков в шаблоне и установите код языка в атрибуте hreflang:
{% load i18n %}
{% get_available_languages as LANGUAGES %}
{% for language_code, language_name in LANGUAGES %}
<link
rel="alternate"
hreflang="{{ language_code }}"
href="TODO" />
{% endfor %}
Следующим шагом будет добавление локализованных ссылок для каждого языка. Потребовалось немного покопаться, но оказалось, что в Django уже есть функция translate_url, которую мы можем использовать:
>>> from django import urls
>>> from django.utils import translation
>>> translation.activate('en')
>>> reverse('about')
'/en/about'
>>> urls.translate_url('/en/about', 'ru')
'/ru/about'
Функция translate_url принимает URL-адрес и язык и возвращает URL-адрес на этом языке. В приведенном выше примере мы активировали английский язык и получили URL-адрес с префиксом /en.
В правилах требуются абсолютные URL-адреса.
Убедитесь, что translate_url может обрабатывать и абсолютные URL:
>>> urls.translate_url('https://example.com/en/about', 'ru')
'https://example.com/ru/about'
Отлично! translate_url может «переводить» абсолютные URL-адреса.
Как насчет URL-адресов с параметрами запроса или хешем?
>>> urls.translate_url('https://example.com/en/about?utm_source=search#top', 'ru')
'https://example.com/ru/about?utm_source=search#top'
Круто, тоже заработало!
ПРИМЕЧАНИЕ. Не имеет особого смысла иметь URL-адрес страницы с параметрами запроса и хешами в таком месте, как тег ссылки (или канонический в этом отношении). Причина, по которой я упоминаю об этом, заключается в том, что это может быть полезно для ссылок на другие страницы.
Это практически все, что нам нужно. Но у translate_url есть некоторые ограничения, о которых стоит знать.
Перевести нелокализованный URL:
>>> urls.translate_url('/about', 'en')
'/about'
Если вы используете встроенный LocaleMiddleware и попытаетесь перейти к /about, Django перенаправит вас на страницу на текущем языке. translate_url не может сделать то же самое.
Как насчет перевода URL-адреса на язык, который не является текущим языком?
>>> translation.activate('en')
>>> urls.translate_url('/ru/about', 'en')
'/ru/about'
Нет, этого тоже нельзя.
Если вы посмотрите на реализацию translate_url, это ограничение станет понятным:
# django/urls/base.py
def translate_url(url, lang_code):
"""
Given a URL (absolute or relative), try to get its translated version in
the `lang_code` language (either by i18n_patterns or by translated regex).
Return the original URL if no translated version is found.
"""
parsed = urlsplit(url)
try:
match = resolve(parsed.path)
except Resolver404:
pass
else:
to_be_reversed = "%s:%s" % (match.namespace, match.url_name) if match.namespace else match.url_name
with override(lang_code):
try:
url = reverse(to_be_reversed, args=match.args, kwargs=match.kwargs)
except NoReverseMatch:
pass
else:
url = urlunsplit((parsed.scheme, parsed.netloc, url, parsed.query, parsed.fragment))
return url
Django сначала пытается разрешить URL-путь. Это способ Django проверить правильность URL-адреса. Только если URL-адрес действителен, он разбивается на части и переворачивается на желаемом языке.
Шаблонный тэг translate_url
Теперь, когда мы знаем, как «переводить» URL-адреса на разные языки, нам нужно иметь возможность использовать это в шаблоне. Django предоставляет нам возможность определять собственные теги и фильтры шаблонов.
Давайте добавим собственный тег шаблона для translate_url:
# app/templatetags/urls.py
from typing import Optional, Any
from django import urls
register = template.Library()
@register.simple_tag(takes_context=True)
def translate_url(context: Dict[str, Any], language: Optional[str]) -> str:
"""Get the absolute URL of the current page for the specified language.
Usage:
{% translate_url 'en' %}
"""
url = context['request'].build_absolute_uri()
return urls.translate_url(url, language)
Наш тег шаблона translate_url принимает контекст. Это необходимо, если мы хотим предоставить абсолютный URL. Мы используем build_absolute_uri для получения абсолютного URL из запроса.
Тег также принимает код целевого языка для перевода URL-адреса и использует translate_url для создания переведенного URL-адреса.
С помощью нашего нового тега шаблона мы можем заполнить пробелы в предыдущей реализации:
{% load i18n urls %}
{% get_available_languages as LANGUAGES %}
{% for language_code, language_name in LANGUAGES %}
<link
rel="alternate"
hreflang="{{ language_code }}"
href="{% translate_url language_code %}" />
{% endfor %}
Использование x-default для языка по умолчанию
В руководстве есть еще одна рекомендация:
Зарезервированное значение hreflang = "x-default" используется, когда никакой другой язык/регион не соответствует настройке браузера пользователя. Это значение не является обязательным, но рекомендуется, чтобы вы могли управлять страницей, когда языки не совпадают. Хорошее использование - настроить таргетинг на домашнюю страницу вашего сайта, где есть интерактивная карта, позволяющая пользователю выбрать свою страну.
Так что также неплохо добавить ссылку на какой-нибудь язык по умолчанию. Если, например, мы хотим сделать нашим языком по умолчанию английский, мы можем добавить следующее в приведенный выше фрагмент:
{% load i18n urls %}
{% get_available_languages as LANGUAGES %}
{% for language_code, language_name in LANGUAGES %}
<link
rel="alternate"
hreflang="{{ language_code }}"
href="{% translate_url language_code %}" />
{% endfor %}
<link
rel="alternate"
hreflang="x-default"
href="{% translate_url en %}" />
Когда мы настраиваем наш проект Django, мы уже определили язык по умолчанию. Вместо жесткого кодирования английского (или любого другого языка в этом отношении) мы хотим использовать LANGUAGE_CODE, определенный в settings.py.
Чтобы использовать значения из settings.py в шаблонах, мы можем использовать старый прием, который мы использовали в прошлом, чтобы визуально различать среды в админке Django. Это простой обработчик контекста, который предоставляет определенные значения из settings.py шаблонам через контекст запроса:
# app/context_processor.py
from typing import Dict, Any
from django.conf import settings
def from_settings(request) -> Dict[str, Any]:
return {
attr: getattr(settings, attr, None)
for attr in (
'LANGUAGE_CODE',
)
}
Чтобы зарегистрировать обработчик контекста, добавьте в settings.py следующее:
# settings.py
TEMPLATES = [{
# ...
'OPTIONS': {
'context_processors': [
#...
'app.context_processors.from_settings',
],
#...
}
]}
Теперь, когда у нас есть доступ к LANGUAGE_CODE в шаблоне, мы действительно можем завершить наш фрагмент:
{% load i18n urls %}
{% get_available_languages as LANGUAGES %}
{% for language_code, language_name in LANGUAGES %}
<link
rel="alternate"
hreflang="{{ language_code }}"
href="{% translate_url language_code %}" />
{% endfor %}
<link
rel="alternate"
hreflang="x-default"
href="{% translate_url LANGUAGE_CODE %}" />
Отрисованная разметка для страницы about выглядит так:
<link
rel="alternate"
hreflang="en"
href="https://example.com/en/about" />
<link
rel="alternate"
hreflang="ru"
href="https://example.com/ru/about" />
<link
rel="alternate"
hreflang="x-default"
href="https://example.com/en/about" />
Заключительные слова
Надеюсь, эта короткая статья помогла вам лучше понять, как поисковые системы могут определять разные языки на вашем сайте Django. В процессе вы, возможно, также подобрали некоторые маленькие уловки для управления локализованными URL-адресами в Django.
Оригинал: https://hakibenita.com/django-multi-language-site-hreflang
Вернуться на верх