Hreflang атрибуты

При разработке многоязычных веб-приложений недостаточно просто перевести интерфейс через I18next. Поисковые системы должны понимать, какая языковая версия страницы предназначена для конкретной аудитории. Для решения этой задачи используется атрибут hreflang.

hreflang сообщает поисковым роботам:

  • на каком языке доступна страница;
  • для какого региона предназначен контент;
  • какие страницы являются альтернативными языковыми версиями друг друга.

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


Связь I18next и hreflang

I18next отвечает за локализацию приложения:

  • хранение переводов;
  • определение языка пользователя;
  • переключение языков;
  • интернационализацию контента.

Однако сама библиотека не занимается SEO-настройками. После определения текущего языка необходимо дополнительно формировать соответствующие метаданные страницы, включая атрибуты hreflang.

Типичная схема работы выглядит следующим образом:

  1. I18next определяет активную локаль.
  2. Приложение отображает переведённый контент.
  3. В <head> страницы генерируются ссылки с атрибутами hreflang.
  4. Поисковые системы связывают все локализованные версии между собой.

Синтаксис hreflang

Базовый вариант:

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

Здесь указываются две версии одной страницы:

  • английская;
  • русская.

Если требуется разделение по регионам:

<link rel="alternate" hreflang="en-US" href="https://example.com/us/" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/uk/" />

В этом случае:

  • en-US — английский язык для США;
  • en-GB — английский язык для Великобритании.

Формат языковых кодов

I18next использует языковые идентификаторы на основе стандарта BCP 47, поэтому они хорошо сочетаются с hreflang.

Примеры:

Код Описание
ru Русский
en Английский
de Немецкий
fr Французский
es Испанский
kk Казахский

Региональные варианты:

Код Описание
en-US США
en-GB Великобритания
fr-CA Канадский французский
pt-BR Бразильский португальский
zh-CN Китай
zh-TW Тайвань

Если в конфигурации I18next используются такие локали:

i18next.init({
  supportedLngs: [
    'en-US',
    'en-GB',
    'ru',
    'kk'
  ]
});

те же значения могут использоваться и в hreflang.


Атрибут x-default

Для страницы по умолчанию рекомендуется использовать специальное значение x-default.

Пример:

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

Такая страница может:

  • автоматически определять язык пользователя;
  • содержать выбор локали;
  • служить точкой входа для всех посетителей.

Генерация hreflang на основе конфигурации I18next

Во многих проектах список локалей уже хранится в настройках I18next.

Например:

const supportedLanguages = [
  'en',
  'ru',
  'de'
];

На основе этого массива можно автоматически формировать теги:

function generateHreflangTags(languages, currentPath) {
  return languages.map(lang => ({
    hreflang: lang,
    href: `https://example.com/${lang}${currentPath}`
  }));
}

Результат:

[
  {
    hreflang: 'en',
    href: 'https://example.com/en/products'
  },
  {
    hreflang: 'ru',
    href: 'https://example.com/ru/products'
  },
  {
    hreflang: 'de',
    href: 'https://example.com/de/products'
  }
]

Такой подход позволяет избежать ручного сопровождения большого количества страниц.


Использование в React-приложениях

В React-проектах часто применяется библиотека React Helmet или её современные аналоги.

Пример:

import { Helmet } from 'react-helmet';

function SeoLinks() {
  return (
    <Helmet>
      <link
        rel="alternate"
        hreflang="en"
        href="https://example.com/en/"
      />

      <link
        rel="alternate"
        hreflang="ru"
        href="https://example.com/ru/"
      />
    </Helmet>
  );
}

При интеграции с I18next:

import i18next from 'i18next';

const currentLanguage = i18next.language;

можно динамически строить URL для альтернативных языков.


Пример с react-i18next

Конфигурация:

const supportedLngs = [
  'en',
  'ru',
  'de'
];

Генерация ссылок:

<Helmet>
  {supportedLngs.map(lang => (
    <link
      key={lang}
      rel="alternate"
      hreflang={lang}
      href={`https://example.com/${lang}/about`}
    />
  ))}
</Helmet>

После рендеринга получится:

<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="de" href="https://example.com/de/about" />

Настройка для Next.js и next-i18next

В приложениях Next.js локализация обычно описывается следующим образом:

module.exports = {
  i18n: {
    locales: ['en', 'ru', 'de'],
    defaultLocale: 'en'
  }
};

На основе этих настроек легко сформировать набор ссылок:

import Head from 'next/head';

function HreflangLinks() {
  const locales = ['en', 'ru', 'de'];

  return (
    <Head>
      {locales.map(locale => (
        <link
          key={locale}
          rel="alternate"
          hrefLang={locale}
          href={`https://example.com/${locale}`}
        />
      ))}
    </Head>
  );
}

Так как локали уже используются системой маршрутизации Next.js, риск расхождения URL и переводов существенно снижается.


Hreflang для маршрутов с параметрами

Допустим, существуют страницы товаров:

/en/products/123
/ru/products/123
/de/products/123

Для каждой версии необходимо указывать полный набор альтернатив:

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

<link rel="alternate"
      hreflang="ru"
      href="https://example.com/ru/products/123" />

<link rel="alternate"
      hreflang="de"
      href="https://example.com/de/products/123" />

Важно, чтобы все версии ссылались друг на друга.


Взаимность ссылок

Поисковые системы ожидают двустороннюю связь между локализованными страницами.

Если английская версия содержит:

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

то русская версия должна содержать:

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

Отсутствие взаимности может привести к игнорированию части атрибутов.


Использование канонических ссылок вместе с hreflang

Частая ошибка — попытка сделать все локализованные страницы каноническими относительно одной версии.

Неправильно:

<link rel="canonical"
      href="https://example.com/en/about" />

на русской странице.

Правильный вариант:

<link rel="canonical"
      href="https://example.com/ru/about" />

Каждая локализованная страница должна иметь собственный canonical URL и одновременно набор альтернативных hreflang.

Пример:

<link rel="canonical"
      href="https://example.com/ru/about" />

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

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

Автоматическая генерация через маршрутизатор

При наличии единой схемы URL можно использовать функцию:

function getAlternateLinks(path, locales) {
  return locales.map(locale => ({
    locale,
    url: `https://example.com/${locale}${path}`
  }));
}

Использование:

const links = getAlternateLinks(
  '/contacts',
  ['en', 'ru', 'de']
);

Результат:

[
  {
    locale: 'en',
    url: 'https://example.com/en/contacts'
  },
  {
    locale: 'ru',
    url: 'https://example.com/ru/contacts'
  },
  {
    locale: 'de',
    url: 'https://example.com/de/contacts'
  }
]

Подобная автоматизация особенно важна для крупных проектов с тысячами страниц.


Hreflang в XML Sitemap

Поисковые системы позволяют размещать информацию о языковых версиях не только в HTML, но и в sitemap.

Пример:

<url>
  <loc>https://example.com/en/about</loc>

  <xhtml:link
      rel="alternate"
      hreflang="ru"
      href="https://example.com/ru/about" />

  <xhtml:link
      rel="alternate"
      hreflang="de"
      href="https://example.com/de/about" />
</url>

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


Типичные ошибки

Использование неподдерживаемых кодов

Неверно:

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

Правильно:

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

Несуществующие страницы

Ошибка:

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

если страница фактически отсутствует и возвращает ошибку 404.

Все альтернативные URL должны быть доступны для индексации.


Несоответствие локалей I18next

Например:

supportedLngs: [
  'en-US',
  'ru-RU'
]

но в hreflang указано:

hreflang="en"
hreflang="ru"

Технически это допустимо, однако рекомендуется использовать единообразную схему локалей во всём приложении.


Отсутствие ссылки на текущую страницу

Неверно:

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

на английской странице отсутствует ссылка на саму себя.

Правильно:

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

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

Каждая версия должна участвовать в общем наборе альтернатив.


Практическая архитектура для проектов на I18next

Распространённая структура:

const locales = [
  'en',
  'ru',
  'de',
  'kk'
];

const baseUrl = 'https://example.com';

Функция генерации:

function buildHreflangs(path) {
  return locales.map(locale => ({
    hreflang: locale,
    href: `${baseUrl}/${locale}${path}`
  }));
}

Использование:

buildHreflangs('/blog/article-1');

Результат:

[
  {
    hreflang: 'en',
    href: 'https://example.com/en/blog/article-1'
  },
  {
    hreflang: 'ru',
    href: 'https://example.com/ru/blog/article-1'
  },
  {
    hreflang: 'de',
    href: 'https://example.com/de/blog/article-1'
  },
  {
    hreflang: 'kk',
    href: 'https://example.com/kk/blog/article-1'
  }
]

Такой подход обеспечивает синхронизацию между:

  • конфигурацией I18next;
  • системой маршрутизации;
  • SEO-метаданными;
  • картой сайта;
  • механизмами индексации поисковых систем.

При грамотной интеграции I18next и hreflang многоязычное приложение становится понятным как пользователям, так и поисковым роботам, обеспечивая корректное отображение локализованных страниц в результатах поиска для разных стран и языковых аудиторий.