Python

Как сообщить Google о других языках на вашем сайте Django

Spread the love

Если у вас есть публичный сайт построенный на 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')),
    ('he', _('Hebrew')),
]

Установите язык по умолчанию:

# 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/he/about
שלום!

И это все что нужно!

Есть несколько дополнительных шагов, таких как добавление представления для переключения языка, но в целом ваш многоязычный сайт Django готов к работе!

Чтобы поисковые системы знали, что страница так же доступна на другом языке, вы можете использовать специальный тег ссылки:

<link rel="alternate" hreflang="en" href="https://example.com/en" />

Тег имеет следующие атрибуты:

  • hreflang: Код языка связанной страницы.
  • href: Ссылка на страницу на указанном языке.

В соответствии с рекомендациями Google и информацией из Википедии, мы должны следовать следующим правилам:

  1. Использовать абсолютные URL, включая схему.
  2. Ссылка должна быть действительной, а связанная страница должна быть на указанном языке.
  3. Нужно перечислить все языки, включая текущий.
  4. Если язык 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', 'he')
'/he/about'

Функция translate_url принимает URL-адрес и язык и возвращает URL-адрес на этом языке. В приведенном выше примере мы активировали английский язык и получили URL с префиксом / en.

В документация написано что требуются только абсолютные URL со схемой.

Давайте убедимся, что translate_url может обрабатывать и абсолютные URL:

>>> urls.translate_url('https://example.com/en/about', 'he')
'https://example.com/he/about'

Супер! translate_url может «переводить» и полные URL.

Как насчет URL с параметрами запроса или хэшем?

>>> urls.translate_url('https://example.com/en/about?utm_source=search#top', 'he')
'https://example.com/he/about?utm_source=search#top'

Круто, это тоже сработало!

ПРИМЕЧАНИЕ. Не имеет особого смысла иметь URL страницы с параметрами запроса и хэшами в таком месте, как тег ссылки. Я упоминаю об этом потому, что это может быть полезно для глубоких ссылок на другие страницы.

Это в основном все, что нам нужно. Но translate_url имеет некоторые ограничения, которые стоит знать.

Давайте попробуем перевести нелокализованный URL, то есть без использование языка (в нашем примере /en/) в пути URL:

>>> urls.translate_url('/about', 'en')
'/about'

Если вы используете встроенный мидлваре LocaleMiddleware и попытаетесь перейти к /about, Django перенаправит вас на страницу на текущем языке. translate_url не сможет сделать то же самое.

translate_url не может «перевести» нелокализованный URL (даже если он существует).

Как насчет перевода URL на язык, который не является текущим языком?

>>> translation.activate('en')
>>> urls.translate_url('/he/about', 'en')
'/he/about'

Нет, тоже не может.

translate_url может переводить только локализованные URL на текущий выбранный язык.

Если вы посмотрите на реализацию 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 пытается обработать resolve URL. Это способ Django проверить, действителен ли URL. Только если URL действителен, он разбивается его на части и возвращает на нужном языке.

translate_url шаблонный тег

Теперь, когда мы знаем, как «translate» обрабатывает 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="he"
    href="https://example.com/he/about" />
<link
    rel="alternate"
    hreflang="x-default"
    href="https://example.com/en/about" />

Заключение

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

Оригинальная статья: Haki Benita How to Let Google Know of Other Languages in Your Django Site

Была ли вам полезна эта статья?
[1 / 5]

Spread the love
Editorial Team

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago