Локализация интерфейса не ограничивается переводом текстовых строк. Полноценная интернационализация должна учитывать потребности пользователей, работающих со скрин-ридерами, экранными увеличителями, голосовым управлением и другими ассистивными технологиями. При использовании I18next особое внимание уделяется переводу не только видимого контента, но и атрибутов доступности, динамических сообщений, уведомлений и описаний элементов интерфейса.
Скрин-ридер озвучивает информацию на основе структуры документа и специальных ARIA-атрибутов. Если локализованы только заголовки и кнопки, а вспомогательные описания остаются на исходном языке, пользователь получает смешанный интерфейс, что существенно ухудшает восприятие приложения.
Многие элементы содержат текст, который не отображается визуально, но активно используется программами чтения экрана.
К таким атрибутам относятся:
aria-labelaria-descriptionaria-placeholderaria-valuetexttitlealt{
"accessibility": {
"searchButton": "Поиск",
"closeDialog": "Закрыть окно",
"userAvatar": "Аватар пользователя"
}
}
button.setAttribute(
"aria-label",
i18next.t("accessibility.searchButton")
);
closeBtn.setAttribute(
"aria-label",
i18next.t("accessibility.closeDialog")
);
avatar.setAttribute(
"alt",
i18next.t("accessibility.userAvatar")
);
В результате скрин-ридер озвучивает элементы на языке локали пользователя.
Атрибут alt играет важнейшую роль для незрячих
пользователей. Его отсутствие приводит к потере части информации
интерфейса.
{
"images": {
"productPhoto": "Фотография товара",
"companyLogo": "Логотип компании",
"profilePicture": "Фотография профиля"
}
}
img.alt = i18next.t("images.productPhoto");
Если изображение декоративное и не несёт смысловой нагрузки, используется пустой атрибут:
<img src="background.png" alt="" />
Такой элемент будет проигнорирован скрин-ридером.
ARIA-метки позволяют уточнять назначение элементов управления.
{
"actions": {
"delete": "Удалить запись"
}
}
deleteButton.setAttribute(
"aria-label",
i18next.t("actions.delete")
);
{
"navigation": {
"main": "Основная навигация"
}
}
<nav aria-label="Основная навигация">
</nav>
При использовании I18next:
nav.setAttribute(
"aria-label",
i18next.t("navigation.main")
);
Нередко в интерфейсе присутствует текст, скрытый визуально, но доступный для скрин-ридеров.
<button>
<span class="icon"></span>
<span class="sr-only">
Удалить документ
</span>
</button>
{
"buttons": {
"deleteDocument": "Удалить документ"
}
}
screenReaderText.textContent =
i18next.t("buttons.deleteDocument");
Подход особенно полезен для иконок без текстовых подписей.
Формы содержат большое количество элементов, требующих перевода.
Локализуются:
{
"form": {
"email": "Электронная почта",
"emailHint": "Введите адрес электронной почты",
"emailError": "Некорректный адрес электронной почты"
}
}
<label for="email">
Электронная почта
</label>
<input
id="email"
aria-describedby="emailHint"
/>
<div id="emailHint">
Введите адрес электронной почты
</div>
label.textContent =
i18next.t("form.email");
hint.textContent =
i18next.t("form.emailHint");
Ошибки должны быть понятны как визуально, так и через ассистивные технологии.
{
"errors": {
"required": "Поле обязательно для заполнения",
"email": "Укажите корректный адрес электронной почты"
}
}
errorElement.textContent =
i18next.t("errors.required");
input.setAttribute(
"aria-invalid",
"true"
);
input.setAttribute(
"aria-describedby",
"error-message"
);
Скрин-ридер сможет автоматически связать поле с текстом ошибки.
Динамические уведомления должны озвучиваться автоматически.
Для этого применяются ARIA live-регионы.
<div
id="notifications"
aria-live="polite"
></div>
{
"notifications": {
"saved": "Изменения успешно сохранены",
"deleted": "Запись удалена"
}
}
notifications.textContent =
i18next.t("notifications.saved");
После обновления содержимого скрин-ридер озвучит сообщение пользователю.
Сообщение озвучивается после завершения текущего чтения.
<div aria-live="polite"></div>
Подходит для:
Сообщение озвучивается немедленно.
<div aria-live="assertive"></div>
Подходит для:
Тексты таких уведомлений также должны храниться в переводах I18next.
Скрин-ридеру часто требуется озвучивать динамические значения.
{
"cart": {
"itemsCount": "В корзине {{count}} товаров"
}
}
const message = i18next.t(
"cart.itemsCount",
{
count: 5
}
);
Результат:
В корзине 5 товаров
Скрин-ридер получит актуальную информацию.
Неправильные формы слов ухудшают восприятие озвучиваемого текста.
{
"messages_zero": "Нет сообщений",
"messages_one": "{{count}} сообщение",
"messages_few": "{{count}} сообщения",
"messages_many": "{{count}} сообщений"
}
i18next.t("messages", {
count: unreadCount
});
Для русского языка I18next автоматически выберет корректную форму.
Примеры:
1 сообщение
2 сообщения
5 сообщений
21 сообщение
Пользователь скрин-ридера должен получать информацию о текущем состоянии интерфейса.
{
"state": {
"expanded": "Развернуто",
"collapsed": "Свернуто"
}
}
const stateText = isOpen
? i18next.t("state.expanded")
: i18next.t("state.collapsed");
button.setAttribute(
"aria-label",
stateText
);
Сложные виджеты часто требуют дополнительных пояснений.
{
"table": {
"description":
"Таблица содержит информацию о заказах пользователей"
}
}
<table aria-describedby="orders-desc">
</table>
<div id="orders-desc">
</div>
description.textContent =
i18next.t("table.description");
Скрин-ридер сможет озвучить контекст до чтения содержимого таблицы.
При открытии модального окна важно передать его назначение пользователю.
{
"dialogs": {
"settingsTitle": "Настройки профиля",
"settingsDescription":
"Окно изменения параметров профиля"
}
}
<div
role="dialog"
aria-labelledby="dialog-title"
aria-describedby="dialog-description"
>
</div>
title.textContent =
i18next.t("dialogs.settingsTitle");
description.textContent =
i18next.t("dialogs.settingsDescription");
Одно и то же слово может иметь разные значения для скрин-ридера.
{
"open_male": "Открыт",
"open_female": "Открыта"
}
i18next.t("open", {
context: "female"
});
Результат:
Открыта
Контексты позволяют строить грамматически корректные сообщения доступности.
Во время длительных операций необходимо информировать пользователя.
{
"loading": {
"start": "Загрузка данных",
"complete": "Загрузка завершена"
}
}
statusRegion.textContent =
i18next.t("loading.start");
После завершения:
statusRegion.textContent =
i18next.t("loading.complete");
В сочетании с aria-live такие уведомления становятся
доступными для программ чтения экрана.
После перевода интерфейса необходимо контролировать качество доступности.
Основные направления проверки:
Наиболее распространённые средства проверки:
Особое внимание уделяется сценариям, в которых текст формируется динамически через I18next, поскольку именно такие элементы чаще всего становятся источником проблем доступности.
Практикой крупных проектов является выделение отдельного пространства имён для строк доступности.
{
"a11y": {
"close": "Закрыть",
"openMenu": "Открыть меню",
"loading": "Выполняется загрузка",
"error": "Произошла ошибка"
}
}
i18next.t("a11y.close");
Такой подход обеспечивает:
Интеграция I18next с механизмами доступности позволяет создавать многоязычные интерфейсы, одинаково удобные как для зрячих пользователей, так и для людей, использующих скрин-ридеры и другие ассистивные технологии. Полноценная локализация должна охватывать весь информационный слой приложения: видимый текст, скрытые описания, ARIA-атрибуты, уведомления, ошибки, состояния элементов и динамические сообщения.