Как отмечать многоязычный контент в React Router v7
Отмечайте текст на разных языках для доступности
Проблема
Когда на странице есть текст на нескольких языках, браузеры и вспомогательные технологии предполагают, что весь контент использует язык, указанный для страницы. Экранный диктор, настроенный на английский, будет пытаться произносить французские фразы, испанские названия книг или немецкие имена с английской фонетикой, что делает речь непонятной для пользователей, полагающихся на аудио. Браузеры применяют проверку орфографии и типографику на основе языка страницы, ошибочно помечая иностранные слова как ошибки и неправильно обрабатывая знаки препинания. Поисковые системы и переводчики не могут корректно обрабатывать многоязычный контент без явных языковых меток.
Это касается не только пользователей экранных дикторов, но и всех, кто использует функции браузера, зависящие от определения языка, включая автоматический перевод, синтез речи и режим чтения.
Решение
Оборачивайте текст на других языках в HTML-элементы с атрибутом lang, установленным на нужный языковой код. Атрибут lang сообщает браузерам и вспомогательным технологиям, что для этого контента нужно использовать другие языковые правила, обеспечивая правильное произношение экранными дикторами и корректную проверку орфографии и типографику в браузерах.
Используйте семантические HTML-элементы, такие как <span> или <i>, чтобы оборачивать инлайн-текст на других языках, не нарушая верстку. Атрибут lang принимает языковые коды ISO 639-1 (например, fr для французского или es для испанского) и, при необходимости, региональные коды для специфики диалектов.
Шаги
1. Создайте компонент для выделения текста на других языках
Создайте переиспользуемый компонент, который оборачивает текст в элемент span с соответствующим атрибутом lang.
type ForeignTextProps = {
lang: string;
children: React.ReactNode;
};
export function ForeignText({ lang, children }: ForeignTextProps) {
return <span lang={lang}>{children}</span>;
}
Этот компонент принимает языковой код и оборачивает свои дочерние элементы в span с атрибутом lang, что позволяет скринридерам переключать правила произношения для вложенного текста.
2. Используйте компонент для выделения инлайн-иностранного текста
Оборачивайте иностранные слова или фразы в вашем контенте с помощью компонента ForeignText.
export default function ArticlePage() {
return (
<article>
<h1>International Cuisine</h1>
<p>
The restaurant's signature dish is{" "}
<ForeignText lang="fr">coq au vin</ForeignText>, a classic French
preparation that pairs perfectly with their house wine.
</p>
<p>
Their dessert menu features{" "}
<ForeignText lang="es">tres leches</ForeignText> and{" "}
<ForeignText lang="it">tiramisu</ForeignText>.
</p>
</article>
);
}
Теперь скринридеры будут произносить «coq au vin» с французской фонетикой, «tres leches» — с испанской, а «tiramisu» — с итальянской, при этом окружающий английский текст будет читаться с английским произношением.
3. Отметьте более длинные фрагменты текста на иностранном языке
Для многофразового иностранного контента применяйте атрибут lang напрямую к блочным элементам.
export default function QuotePage() {
return (
<article>
<h1>Universal Declaration of Human Rights</h1>
<h2>Article 1</h2>
<blockquote lang="fr">
<p>
Tous les êtres humains naissent libres et égaux en dignité et en
droits. Ils sont doués de raison et de conscience et doivent agir les
uns envers les autres dans un esprit de fraternité.
</p>
</blockquote>
</article>
);
}
Применение lang к элементу blockquote помечает всю цитату как французскую, что обеспечивает правильное произношение и типографику для всего фрагмента.
4. Комбинируйте с переведённым UI-текстом
При отображении иностранного контента вместе с переведённым интерфейсом используйте react-intl для UI-элементов и атрибуты lang для пользовательского или цитируемого контента.
import { FormattedMessage } from "react-intl";
import { ForeignText } from "~/components/ForeignText";
export default function BookReview() {
return (
<article>
<h1>
<FormattedMessage id="review.title" defaultMessage="Book Review" />
</h1>
<p>
<FormattedMessage
id="review.intro"
defaultMessage="The novel {title} explores themes of identity and belonging."
values={{
title: <ForeignText lang="de">Der Steppenwolf</ForeignText>,
}}
/>
</p>
</article>
);
}
Текст интерфейса адаптируется под локаль пользователя через react-intl, а название книги сохраняет оригинальный немецкий язык с правильной языковой разметкой для доступности.