Как пометить многоязычный контент в Next.js (Pages Router) v16

Помечайте текст на разных языках для доступности

Проблема

Когда на странице есть текст на нескольких языках, браузеры и вспомогательные технологии воспринимают весь контент так, будто он написан на основном языке страницы. Например, скринридер, настроенный на английский, будет пытаться произносить французские фразы, испанские названия книг или немецкие названия компаний с английским акцентом, что делает речь неразборчивой для пользователей, полагающихся на аудиовывод. Браузеры применяют проверку орфографии и типографику, исходя из неправильного языка, отмечая правильно написанные иностранные слова как ошибки и некорректно обрабатывая пунктуацию и форматирование.

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

Решение

Добавьте к элементам с текстом на иностранном языке атрибут HTML lang, чтобы явно указать язык этого контента. Этот атрибут сообщает браузерам и вспомогательным технологиям, что отмеченный текст нужно обрабатывать по правилам указанного языка, а не основного языка страницы. Скринридеры переключаются на нужный движок озвучки, браузеры используют правильные словари для проверки орфографии, а типографика применяет языковые правила форматирования.

Оборачивая иностранный текст в элементы с правильным атрибутом lang, вы создаёте чёткие языковые границы в контенте и сохраняете корректность многоязычного текста.

Шаги

1. Создайте компонент для текста с языковой разметкой

Сделайте React-компонент, который оборачивает контент на иностранном языке в элемент span с нужным атрибутом lang.

interface ForeignTextProps {
  lang: string;
  children: React.ReactNode;
}

export function ForeignText({ lang, children }: ForeignTextProps) {
  return <span lang={lang}>{children}</span>;
}

Этот компонент принимает языковой код и оборачивает свои дочерние элементы в span с установленным атрибутом lang, создавая языковую границу, которую могут распознать вспомогательные технологии и браузеры.

2. Используйте компонент для выделения иностранных фраз

Оборачивайте текст на иностранном языке в вашем контенте с помощью компонента, указывая соответствующий языковой код ISO 639-1.

export default function ArticlePage() {
  return (
    <article>
      <h1>Understanding French Cuisine</h1>
      <p>
        The concept of <ForeignText lang="fr">mise en place</ForeignText> is
        fundamental to professional cooking. It means having all ingredients
        prepared and organized before you begin.
      </p>
      <p>
        The restaurant <ForeignText lang="fr">Le Bernardin</ForeignText> in New
        York has maintained three Michelin stars for decades.
      </p>
    </article>
  );
}

Каждая иностранная фраза оборачивается в компонент с её языковым кодом, чтобы скринридеры правильно произносили её, а браузеры применяли нужные языковые правила.

3. Обработка длинных фрагментов на иностранном языке

Для многофразового иностранного контента оборачивайте весь фрагмент в один элемент с языковой разметкой, чтобы не дробить языковой контекст.

export default function QuotePage() {
  return (
    <article>
      <h1>Universal Declaration of Human Rights</h1>
      <h2>Article 1</h2>
      <blockquote lang="es">
        <p>
          Todos los seres humanos nacen libres e iguales en dignidad y derechos
          y, dotados como están de razón y conciencia, deben comportarse
          fraternalmente los unos con los otros.
        </p>
      </blockquote>
    </article>
  );
}

Применение lang напрямую к блочным элементам, таким как blockquote или p, выделяет весь фрагмент, позволяя скринридерам сохранять правильное произношение и браузерам применять языковые правила ко всему контексту.

4. Выделяйте иностранный текст в форматированных сообщениях

Когда в переведённых сообщениях встречается текст на иностранном языке, используйте компонент внутри форматирования rich text сообщения.

import { FormattedMessage } from "react-intl";

export default function RecipePage() {
  return (
    <div>
      <FormattedMessage
        id="recipe.description"
        defaultMessage="This dish is called {dishName} in French cuisine."
        values={{
          dishName: <ForeignText lang="fr">coq au vin</ForeignText>,
        }}
      />
    </div>
  );
}

Компонент интегрируется с rich text форматированием react-intl, позволяя выделять иностранные термины в переведённом контенте и при этом сохранять языковую границу для вспомогательных технологий.

5. Создавайте варианты для смыслового выделения

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

interface ForeignEmphasisProps {
  lang: string;
  children: React.ReactNode;
}

export function ForeignEmphasis({ lang, children }: ForeignEmphasisProps) {
  return <i lang={lang}>{children}</i>;
}

Элемент i семантически обозначает текст в альтернативном тоне или настроении, поэтому он подходит для иностранных терминов, которые также выделяются в тексте. Атрибут lang обеспечивает правильное произношение, а сам элемент — семантическое значение.

6. Документируйте поддерживаемые языковые коды

Создайте тип или константу, определяющую языковые коды, которые поддерживает ваше приложение, чтобы обеспечить согласованность и выявлять ошибки на этапе разработки.

export const SUPPORTED_LANGUAGES = {
  FRENCH: "fr",
  SPANISH: "es",
  GERMAN: "de",
  ITALIAN: "it",
  JAPANESE: "ja",
  CHINESE: "zh",
} as const;

type LanguageCode =
  (typeof SUPPORTED_LANGUAGES)[keyof typeof SUPPORTED_LANGUAGES];

interface ForeignTextProps {
  lang: LanguageCode | string;
  children: React.ReactNode;
}

export function ForeignText({ lang, children }: ForeignTextProps) {
  return <span lang={lang}>{children}</span>;
}

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