Локализация пользовательского интерфейса затрагивает не только видимый текст, но и данные, предназначенные для вспомогательных технологий: экранных дикторов, брайлевских дисплеев, голосового управления и навигационных систем. Атрибуты WAI-ARIA позволяют описывать назначение элементов, состояния интерфейса и связи между компонентами. При интернационализации приложения ARIA-атрибуты становятся частью переводимого контента.
JavaScript API Intl помогает формировать локализованные
строки, которые затем могут использоваться внутри ARIA-атрибутов:
aria-labelaria-descriptionaria-valuetextaria-roledescriptionaria-placeholderaria-livearia-busyaria-currentaria-label для динамических элементов интерфейсаНеправильно локализованные ARIA-атрибуты приводят к тому, что визуально интерфейс переведён, а экранный диктор продолжает озвучивать текст на другом языке.
Атрибут lang напрямую влияет на поведение screen reader.
Если язык документа определён неверно, вспомогательные технологии будут
использовать неправильные правила произношения.
<html lang="ru">
Для отдельных локализованных фрагментов язык может переопределяться:
<button aria-label="Download report" lang="en">
Скачать отчёт
</button>
Экранный диктор переключит голосовой движок на английский только для содержимого кнопки.
aria-labelaria-label используется для задания текстового описания
элемента без видимого контента.
<button aria-label="Закрыть окно">
×
</button>
При локализации строки должны формироваться в соответствии с текущей локалью приложения.
const locale = 'ru';
const labels = {
ru: {
close: 'Закрыть окно'
},
en: {
close: 'Close dialog'
}
};
button.setAttribute(
'aria-label',
labels[locale].close
);
Многие ARIA-атрибуты содержат динамические значения: даты, числа, валюты, проценты.
aria-labelconst formatter = new Intl.DateTimeFormat('ru-RU', {
dateStyle: 'long'
});
const date = formatter.format(new Date());
button.setAttribute(
'aria-label',
`Выбрана дата ${date}`
);
Результат:
Выбрана дата 27 мая 2026 г.
Для английской локали:
const formatter = new Intl.DateTimeFormat('en-US', {
dateStyle: 'long'
});
Результат:
Selected date May 27, 2026
aria-valuetext
и Intl.NumberFormatЭлементам диапазона (slider, progressbar,
spinbutton) часто требуется человекочитаемое значение.
<div
role="slider"
aria-valuenow="75"
aria-valuetext="75 percent"
></div>
Такой текст непригоден для многоязычного интерфейса.
const percentFormatter = new Intl.NumberFormat('ru-RU', {
style: 'percent'
});
const value = 0.75;
slider.setAttribute(
'aria-valuetext',
percentFormatter.format(value)
);
Результат:
75 %
Для немецкой локали форматирование также изменится:
new Intl.NumberFormat('de-DE', {
style: 'percent'
}).format(0.75);
ARIA-описания финансовых элементов должны учитывать локальные правила отображения валют.
const formatter = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'KZT'
});
const amount = formatter.format(150000);
button.setAttribute(
'aria-label',
`Оплатить ${amount}`
);
Результат:
Оплатить 150 000,00 ₸
Intl.ListFormat
для ARIA-описанийПри перечислении элементов необходимо учитывать языковые правила соединения списков.
const text = items.join(', ');
Такой подход не учитывает правила конкретного языка.
const formatter = new Intl.ListFormat('ru', {
style: 'long',
type: 'conjunction'
});
const result = formatter.format([
'HTML',
'CSS',
'JavaScript'
]);
element.setAttribute(
'aria-label',
result
);
Результат:
HTML, CSS и JavaScript
Для английского языка:
HTML, CSS, and JavaScript
Intl.RelativeTimeFormat
в live-regionДинамические уведомления часто озвучиваются через
aria-live.
<div aria-live="polite" id="status"></div>
const formatter = new Intl.RelativeTimeFormat('ru', {
numeric: 'auto'
});
status.textContent = formatter.format(-5, 'minute');
Результат:
5 минут назад
Экранный диктор озвучит строку в корректном формате.
aria-roledescriptionaria-roledescription позволяет переопределять
стандартное описание роли.
<div
role="group"
aria-roledescription="Карусель"
>
</div>
При интернационализации текст должен изменяться вместе с языком интерфейса.
const roleDescriptions = {
ru: 'Карусель',
en: 'Carousel',
fr: 'Carrousel'
};
element.setAttribute(
'aria-roledescription',
roleDescriptions[locale]
);
aria-liveLive-region особенно чувствительны к качеству локализации, поскольку сообщения озвучиваются автоматически.
status.textContent = `${count} files uploaded`;
const pluralRules = new Intl.PluralRules('ru');
function getFilesText(count) {
const category = pluralRules.select(count);
const variants = {
one: 'файл загружен',
few: 'файла загружено',
many: 'файлов загружено',
other: 'файла загружено'
};
return `${count} ${variants[category]}`;
}
status.textContent = getFilesText(5);
Результат:
5 файлов загружено
Intl.DisplayNames для
ARIAAPI Intl.DisplayNames используется для локализованного
отображения языков, регионов и валют.
const languageNames = new Intl.DisplayNames(['ru'], {
type: 'language'
});
const label = languageNames.of('en');
button.setAttribute(
'aria-label',
label
);
Результат:
английский
Смена языка интерфейса должна учитывать доступность.
<button id="lang-switch"></button>
const currentLocale = 'ru';
const displayNames = new Intl.DisplayNames(
[currentLocale],
{ type: 'language' }
);
const nextLanguage = displayNames.of('en');
button.textContent = nextLanguage;
button.setAttribute(
'aria-label',
`Переключить язык на ${nextLanguage}`
);
Intl.Segmenter для screen readerНекоторые языки требуют корректного разбиения текста на слова и предложения.
const segmenter = new Intl.Segmenter('ja', {
granularity: 'word'
});
const segments = segmenter.segment('こんにちは世界');
Такой подход помогает при создании кастомных систем озвучивания и текстовой навигации.
Одна из самых распространённых ошибок — перевод только видимого интерфейса.
<button aria-label="Close">
Закрыть
</button>
Экранный диктор озвучит английский текст, несмотря на русский интерфейс.
<button aria-label="Закрыть">
Закрыть
</button>
ARIA-строки должны храниться рядом с обычными переводами.
const translations = {
ru: {
buttons: {
close: 'Закрыть',
save: 'Сохранить'
},
aria: {
closeDialog: 'Закрыть диалоговое окно',
saveDocument: 'Сохранить документ'
}
}
};
Состояния элементов также должны быть понятны screen reader.
<button
role="switch"
aria-checked="true"
aria-label="Тёмная тема включена"
>
</button>
function updateThemeState(enabled) {
button.setAttribute(
'aria-label',
enabled
? 'Тёмная тема включена'
: 'Тёмная тема выключена'
);
}
aria-descriptionaria-description дополняет основной label.
const formatter = new Intl.NumberFormat('ru-RU');
const value = formatter.format(1250000);
element.setAttribute(
'aria-description',
`Количество пользователей: ${value}`
);
Для таблиц часто используются:
aria-sortaria-colindexaria-rowindexaria-label<th
aria-sort="ascending"
aria-label="Сортировка по возрастанию"
>
Цена
</th>
Календари являются одним из самых сложных компонентов локализации.
const formatter = new Intl.DateTimeFormat('ru-RU', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
const label = formatter.format(new Date());
cell.setAttribute(
'aria-label',
label
);
Результат:
среда, 27 мая 2026 г.
const formatter = new Intl.DateTimeFormat('ru-RU', {
timeStyle: 'short'
});
const time = formatter.format(new Date());
element.setAttribute(
'aria-label',
`Время ${time}`
);
Для RTL-языков необходимо корректно задавать направление текста.
<div dir="rtl" lang="ar">
مرحبا
</div>
ARIA-атрибуты также должны содержать текст в соответствующей локали.
<button
aria-label="إغلاق النافذة"
dir="rtl"
>
</button>
Создание экземпляров Intl внутри частых обновлений может
ухудшать производительность.
function formatPrice(price) {
return new Intl.NumberFormat(
'ru-RU',
{
style: 'currency',
currency: 'RUB'
}
).format(price);
}
const currencyFormatter =
new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB'
});
function formatPrice(price) {
return currencyFormatter.format(price);
}
element.setAttribute(
'aria-label',
'Delete'
);
`${count} items selected`
Без учёта множественных форм такой код работает некорректно для многих языков.
Визуальный интерфейс локализован, а вспомогательные атрибуты — нет.
<button aria-label="Ред. профиля">
Screen reader могут озвучивать сокращения непредсказуемо.
При тестировании необходимо проверять:
aria-label;Intl API обычно используется совместно с:
Пример:
button.setAttribute(
'aria-label',
intl.formatMessage({
id: 'dialog.close'
})
);
При переключении языка необходимо обновлять не только текст DOM-узлов, но и ARIA-атрибуты.
function updateLocale(locale) {
button.textContent =
translations[locale].close;
button.setAttribute(
'aria-label',
translations[locale].closeDialog
);
}
При серверном рендеринге ARIA-атрибуты должны генерироваться сразу в нужной локали.
<button aria-label="Сохранить документ">
Сохранить
</button>
Это особенно важно для screen reader, которые начинают анализировать страницу до полной гидратации JavaScript.
Наиболее критичны локализованные ARIA-атрибуты в:
В этих компонентах одновременно используются: