Как пометить многоязычный контент в 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>;
}
Определение поддерживаемых языков в виде констант даёт автодополнение в редакторе и документирует, какие языковые коды используются в приложении, при этом остаётся возможность использовать произвольные коды языков при необходимости.