Озвучивание экранными читалками

Интерфейс, корректно локализованный для разных языков и регионов, становится более предсказуемым для экранных читалок. Библиотека Intl API напрямую влияет на то, как синтезаторы речи озвучивают:

  • даты;
  • числа;
  • валюты;
  • единицы измерения;
  • списки;
  • относительное время;
  • диапазоны;
  • сегменты текста.

Неправильное форматирование приводит к тому, что экранная читалка читает данные механически или неоднозначно. Особенно заметны ошибки при озвучивании:

  • денежных значений;
  • дат в нестандартном формате;
  • смешанных языков;
  • сокращений;
  • дробных чисел;
  • диапазонов времени.

Проблемы ручного форматирования

Ручное форматирование строк часто создаёт трудности для вспомогательных технологий.

Пример ручной сборки даты

const date = new Date();

const formatted =
  date.getDate() + '.' +
  (date.getMonth() + 1) + '.' +
  date.getFullYear();

console.log(formatted);

Строка:

12.05.2026

может быть озвучена как:

двенадцать точка ноль пять точка две тысячи двадцать шесть

или даже посимвольно, в зависимости от читалки и локали.


Использование Intl.DateTimeFormat

Базовое форматирование

const formatter = new Intl.DateTimeFormat('ru-RU', {
  day: 'numeric',
  month: 'long',
  year: 'numeric'
});

console.log(formatter.format(new Date()));

Результат:

12 мая 2026 г.

Экранная читалка интерпретирует такую строку как естественную дату.


Полные даты и естественное произношение

Нежелательный формат

05/12/26

Проблемы:

  • неоднозначность порядка;
  • сокращённый год;
  • отсутствие текстового месяца.

Предпочтительный формат

const formatter = new Intl.DateTimeFormat('ru-RU', {
  weekday: 'long',
  day: 'numeric',
  month: 'long',
  year: 'numeric'
});

Результат:

вторник, 12 мая 2026 г.

Такой формат:

  • легче воспринимается на слух;
  • уменьшает когнитивную нагрузку;
  • корректно обрабатывается синтезаторами речи.

Озвучивание времени

Короткий формат

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: '2-digit',
  minute: '2-digit'
});

console.log(formatter.format(new Date()));

Результат:

09:05

Некоторые читалки озвучивают подобные значения как:

ноль девять двоеточие ноль пять

Использование расширенного формата времени

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric'
});

Результат:

9:05

Озвучивание становится более естественным:

девять часов пять минут

Форматирование чисел для экранных читалок

Ошибки ручного разделения

const price = '1,234,567.89';

В русской локали подобная запись может озвучиваться неправильно.


Использование Intl.NumberFormat

const formatter = new Intl.NumberFormat('ru-RU');

console.log(formatter.format(1234567.89));

Результат:

1 234 567,89

Преимущества:

  • правильный разделитель дробной части;
  • корректные пробелы между разрядами;
  • адаптация под локаль пользователя.

Озвучивание валют

Нежелательный вариант

1000 RUB

Экранная читалка может прочитать:

один ноль ноль ноль руб

или:

руб

Использование валютного режима

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'RUB'
});

console.log(formatter.format(1000));

Результат:

1 000,00 ₽

Синтезатор речи обычно озвучивает:

одна тысяча рублей

Валюты в разных локалях

const usd = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
});

const de = new Intl.NumberFormat('de-DE', {
  style: 'currency',
  currency: 'EUR'
});

console.log(usd.format(1500));
console.log(de.format(1500));

Результат:

$1,500.00
1.500,00 €

Экранные читалки учитывают региональные правила произношения.


Использование currencyDisplay

Полное название валюты

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'USD',
  currencyDisplay: 'name'
});

console.log(formatter.format(25));

Результат:

25,00 доллара США

Для доступности такой формат значительно лучше сокращений.


Озвучивание процентов

Ручной вариант

25%

Некоторые читалки произносят символ отдельно.


Форматирование процентов

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'percent'
});

console.log(formatter.format(0.25));

Результат:

25 %

Читалки обычно корректно озвучивают:

двадцать пять процентов

Единицы измерения

Использование unit

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'unit',
  unit: 'kilometer-per-hour'
});

console.log(formatter.format(90));

Результат:

90 км/ч

Синтезатор речи способен интерпретировать значение как:

девяносто километров в час

Полное отображение единиц

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'unit',
  unit: 'liter',
  unitDisplay: 'long'
});

console.log(formatter.format(5));

Результат:

5 литров

Длинные формы предпочтительнее для доступности.


Относительное время и естественная речь

Использование Intl.RelativeTimeFormat

const formatter = new Intl.RelativeTimeFormat('ru-RU', {
  numeric: 'auto'
});

console.log(formatter.format(-1, 'day'));

Результат:

вчера

Это лучше для экранных читалок, чем:

1 день назад

Поддержка естественных выражений

const formatter = new Intl.RelativeTimeFormat('ru-RU', {
  numeric: 'auto'
});

console.log(formatter.format(1, 'day'));
console.log(formatter.format(-1, 'week'));

Результат:

завтра
на прошлой неделе

Подобные конструкции воспринимаются быстрее и естественнее.


Озвучивание списков

Проблема ручной конкатенации

const text = 'HTML, CSS и JavaScript';

При разных локалях соединители отличаются.


Использование Intl.ListFormat

const formatter = new Intl.ListFormat('ru-RU', {
  style: 'long',
  type: 'conjunction'
});

console.log(
  formatter.format(['HTML', 'CSS', 'JavaScript'])
);

Результат:

HTML, CSS и JavaScript

Intl.ListFormat автоматически использует:

  • правильные союзы;
  • правила пунктуации;
  • особенности локали.

Озвучивание коротких списков

const formatter = new Intl.ListFormat('en-US', {
  style: 'long',
  type: 'disjunction'
});

console.log(
  formatter.format(['tea', 'coffee', 'juice'])
);

Результат:

tea, coffee, or juice

Экранные читалки правильно выделяют логическое разделение элементов.


Диапазоны дат

Использование formatRange

const formatter = new Intl.DateTimeFormat('ru-RU', {
  day: 'numeric',
  month: 'long'
});

const start = new Date(2026, 4, 10);
const end = new Date(2026, 4, 15);

console.log(
  formatter.formatRange(start, end)
);

Результат:

10–15 мая

Это лучше, чем ручная запись:

10 мая - 15 мая

Диапазоны времени

const formatter = new Intl.DateTimeFormat('ru-RU', {
  hour: 'numeric',
  minute: 'numeric'
});

console.log(
  formatter.formatRange(
    new Date(2026, 0, 1, 9, 0),
    new Date(2026, 0, 1, 18, 0)
  )
);

Результат:

09:00–18:00

Читалки распознают диапазон как единое выражение.


Сегментация текста и озвучивание

Intl.Segmenter

API помогает разбивать текст на:

  • слова;
  • предложения;
  • графемы.

Это важно для:

  • систем чтения текста;
  • навигации по словам;
  • подсветки текущего фрагмента;
  • синхронизации озвучивания.

Разделение текста на слова

const segmenter = new Intl.Segmenter('ru-RU', {
  granularity: 'word'
});

const segments =
  segmenter.segment('Привет, мир!');

for (const item of segments) {
  console.log(item.segment);
}

Результат:

Привет
,
 
мир
!

Навигация экранных читалок

Некоторые вспомогательные технологии используют сегментацию для:

  • перехода по словам;
  • выделения активного текста;
  • корректного произношения сокращений;
  • определения границ предложений.

Смешанные языки и локали

Неправильная локаль

const formatter = new Intl.NumberFormat('ru-RU');

console.log(formatter.format(1234.56));

Если интерфейс английский, а число отформатировано по русским правилам, экранная читалка может переключаться между языковыми моделями некорректно.


Согласованность языка документа

Важно, чтобы:

  • lang в HTML совпадал с локалью;
  • Intl API использовал ту же языковую конфигурацию;
  • форматирование соответствовало региону пользователя.

Использование navigator.language

const locale = navigator.language;

const formatter = new Intl.DateTimeFormat(locale, {
  dateStyle: 'long'
});

console.log(
  formatter.format(new Date())
);

Такой подход помогает синхронизировать:

  • язык интерфейса;
  • произношение;
  • локальные правила записи.

Озвучивание сокращений

Проблемный вариант

12 тыс.

Экранная читалка может произнести:

двенадцать тис

Компактное форматирование чисел

const formatter = new Intl.NumberFormat('ru-RU', {
  notation: 'compact',
  compactDisplay: 'long'
});

console.log(formatter.format(12000));

Результат:

12 тысяч

Полная форма значительно лучше для синтеза речи.


Использование formatToParts

Разделение числа на части

const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'RUB'
});

console.log(
  formatter.formatToParts(1500)
);

Метод позволяет отдельно получить:

  • целую часть;
  • дробную часть;
  • символ валюты;
  • разделители.

Создание доступной разметки

const parts =
  formatter.formatToParts(1500);

const html = parts.map(part => {
  if (part.type === 'currency') {
    return `<span aria-label="рублей">${part.value}</span>`;
  }

  return part.value;
}).join('');

Подобный подход улучшает озвучивание специальных символов.


Локализация сообщений времени

const formatter = new Intl.RelativeTimeFormat('ru-RU', {
  style: 'long'
});

console.log(formatter.format(-5, 'minute'));

Результат:

5 минут назад

Экранные читалки обычно воспринимают такие конструкции как естественную речь.


Поддержка разных календарей

const formatter = new Intl.DateTimeFormat('ja-JP-u-ca-japanese');

console.log(
  formatter.format(new Date())
);

Intl API учитывает:

  • локальные календари;
  • региональные стандарты;
  • правила произношения дат.

Это особенно важно в мультиязычных интерфейсах.


Использование dateStyle и timeStyle

const formatter = new Intl.DateTimeFormat('ru-RU', {
  dateStyle: 'full',
  timeStyle: 'short'
});

console.log(
  formatter.format(new Date())
);

Результат может выглядеть так:

вторник, 12 мая 2026 г., 09:15

Такой формат хорошо подходит для:

  • расписаний;
  • уведомлений;
  • календарей;
  • интерфейсов бронирования.

Проблемы нестандартных символов

Некоторые разработчики используют декоративные разделители:

12 • 05 • 2026

или:

10 → 15 мая

Экранные читалки могут:

  • озвучивать символы отдельно;
  • делать длинные паузы;
  • интерпретировать запись неоднозначно.

Intl API избавляет от необходимости использовать нестандартные конструкции вручную.


Проверка локалей

Использование supportedLocalesOf

console.log(
  Intl.DateTimeFormat.supportedLocalesOf([
    'ru-RU',
    'fr-FR',
    'ar-EG'
  ])
);

Метод помогает убедиться, что:

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

Практические рекомендации

Для дат

Предпочтительно:

  • текстовые месяцы;
  • полные годы;
  • локализованные диапазоны;
  • dateStyle.

Нежелательно:

  • сокращённые годы;
  • ручные разделители;
  • неоднозначные форматы.

Для чисел

Предпочтительно:

  • Intl.NumberFormat;
  • локальные разделители;
  • длинные единицы измерения.

Нежелательно:

  • ручные сокращения;
  • нестандартные обозначения;
  • смешение локалей.

Для валют

Предпочтительно:

  • currencyDisplay: 'name';
  • локализованные символы;
  • корректное округление.

Для текста

Предпочтительно:

  • Intl.ListFormat;
  • Intl.Segmenter;
  • локализованные соединители.

Для времени

Предпочтительно:

  • Intl.RelativeTimeFormat;
  • естественные выражения;
  • локальные правила произношения.