Форматы для людей с ограниченными возможностями

Интерфейсы, ориентированные на международную аудиторию, должны учитывать не только язык и регион пользователя, но и особенности восприятия информации людьми с ограниченными возможностями. В экосистеме JavaScript библиотека Intl API играет важную роль в создании доступных интерфейсов, поскольку корректное отображение дат, времени, чисел и текстовых единиц напрямую влияет на работу экранных дикторов, систем увеличения текста, голосовых помощников и альтернативных способов ввода.

Неправильно отформатированные данные способны сделать интерфейс практически непригодным для использования:

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

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


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

Часто встречается ручное формирование строк:

const price = 1200;
const result = price + " USD";

Подобный подход имеет ряд проблем:

  1. Не учитывается локаль пользователя.
  2. Экранный диктор может читать строку неестественно.
  3. Отсутствуют разделители тысяч.
  4. Не поддерживаются региональные правила отображения валют.
  5. Невозможно автоматически адаптировать формат под языковые стандарты.

Для пользователя с нарушением зрения строка:

1200 USD

может быть озвучена хуже, чем локализованный вариант:

1,200 US dollars

Intl.NumberFormat и доступность чисел

Локализованное форматирование

Intl.NumberFormat автоматически подбирает формат числа в зависимости от языка и региона.

const formatter = new Intl.NumberFormat("en-US");

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

Результат:

1,234,567.89

Для немецкой локали:

const formatter = new Intl.NumberFormat("de-DE");

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

Результат:

1.234.567,89

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


Форматирование валют

Проблемы сокращённых обозначений

Сокращения валют вроде:

1000$

могут озвучиваться неоднозначно.

Корректный вариант:

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

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

Результат:

$1,000.00

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

Параметр currencyDisplay позволяет управлять способом отображения валюты.

Символ

new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "symbol"
}).format(500);

Результат:

$500.00

Код валюты

new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "code"
}).format(500);

Результат:

USD 500.00

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

Наиболее полезно для доступности.

new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "name"
}).format(500);

Результат:

500.00 US dollars

Полное название лучше воспринимается:

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

Compact notation и проблемы доступности

Современные интерфейсы часто используют сокращённые формы чисел:

1K
2M
5B

В Intl API это реализуется через notation.

new Intl.NumberFormat("en-US", {
  notation: "compact"
}).format(1200);

Результат:

1.2K

Однако подобный формат может быть неудобен:

  • экранный диктор может прочитать «кей»;
  • не все пользователи понимают сокращения;
  • возникают сложности у людей с когнитивными нарушениями.

Для критически важных интерфейсов рекомендуется обычное форматирование.


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

Ошибки ручного отображения

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

const result = value + "%";

Корректный способ:

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

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

Результат:

25 %

Intl API автоматически:

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

Intl.DateTimeFormat и доступность дат

Дата — один из самых сложных элементов для интернационализации.

Строка:

01/02/2025

может означать:

  • 1 февраля;
  • 2 января.

Локализованное форматирование дат

const formatter = new Intl.DateTimeFormat("ru-RU");

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

Для США:

const formatter = new Intl.DateTimeFormat("en-US");

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

Формат автоматически подстраивается под регион.


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

Для доступности предпочтительны полные текстовые варианты.

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

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

Результат:

понедельник, 10 марта 2025 г.

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

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

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

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

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

Использование 12-часового и 24-часового формата

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

new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  hour12: true
}).format(new Date());

new Intl.DateTimeFormat("de-DE", {
  hour: "numeric",
  minute: "numeric",
  hour12: false
}).format(new Date());

Важно учитывать региональные ожидания пользователей.


Intl.RelativeTimeFormat

Intl.RelativeTimeFormat используется для отображения относительного времени:

  • «5 минут назад»;
  • «через 2 дня»;
  • «вчера»;
  • «завтра».

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

Нежелательный подход:

`${minutes} min ago`

Недостатки:

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

Корректное использование

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

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

Результат:

вчера

Numeric auto

Параметр:

numeric: "auto"

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

вчера
сегодня
завтра

Это особенно полезно:

  • для экранных дикторов;
  • пользователей с когнитивными нарушениями;
  • голосовых интерфейсов.

Intl.ListFormat

Intl.ListFormat создаёт корректные списки элементов.


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

items.join(", ")

Недостатки:

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

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

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

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

Результат:

HTML, CSS и JavaScript

Экранные дикторы читают такие конструкции значительно естественнее.


Типы списков

conjunction

Список с союзом «и».

type: "conjunction"

disjunction

Список с союзом «или».

type: "disjunction"

unit

Список единиц измерения.

type: "unit"

Intl.DisplayNames

Intl.DisplayNames преобразует коды в понятные названия.


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

Плохо:

USD
RU
fr

Для некоторых пользователей подобные обозначения непонятны.


Получение локализованных названий

const formatter = new Intl.DisplayNames(["ru"], {
  type: "region"
});

console.log(formatter.of("US"));

Результат:

США

Названия языков

const formatter = new Intl.DisplayNames(["ru"], {
  type: "language"
});

console.log(formatter.of("de"));

Результат:

немецкий

Это особенно важно:

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

Intl.PluralRules

Многие языки имеют сложные правила множественного числа.


Ошибки ручной реализации

if (count === 1) {
  return "item";
}

Такой код не подходит для большинства языков.


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

const pluralRules = new Intl.PluralRules("ru-RU");

console.log(pluralRules.select(5));

Результат:

many

Категории множественного числа

В русском языке:

  • one
  • few
  • many
  • other

Пример локализации

const pluralRules = new Intl.PluralRules("ru-RU");

const forms = {
  one: "сообщение",
  few: "сообщения",
  many: "сообщений",
  other: "сообщения"
};

function formatMessages(count) {
  const rule = pluralRules.select(count);

  return `${count} ${forms[rule]}`;
}

console.log(formatMessages(21));

Результат:

21 сообщение

Корректные склонения улучшают:

  • читаемость;
  • восприятие речи;
  • понимание интерфейса.

Intl.Segmenter

Intl.Segmenter предназначен для разбиения текста.


Зачем это нужно для доступности

Некоторые языки:

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

Пример сегментации

const segmenter = new Intl.Segmenter("ja-JP", {
  granularity: "word"
});

const segments = segmenter.segment("こんにちは世界");

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

Поддержка screen reader

Корректная сегментация помогает:

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

Форматирование единиц измерения

Intl.NumberFormat поддерживает единицы измерения.


Пример

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

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

Результат:

80 км/ч

unitDisplay

short

unitDisplay: "short"

Результат:

80 км/ч

long

Наиболее полезно для доступности.

unitDisplay: "long"

Результат:

80 километров в час

Полные названия:

  • лучше читаются;
  • понятнее озвучиваются;
  • уменьшают неоднозначность.

Форматирование диапазонов

Некоторые методы поддерживают диапазоны.


formatRange

const formatter = new Intl.DateTimeFormat("ru-RU", {
  dateStyle: "medium"
});

console.log(
  formatter.formatRange(
    new Date("2025-01-01"),
    new Date("2025-01-05")
  )
);

Результат:

1–5 янв. 2025 г.

Преимущества для доступности

Intl API:

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

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

Использование полных названий

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

  • currencyDisplay: "name"
  • unitDisplay: "long"
  • dateStyle: "full"

Отказ от ручной конкатенации

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

value + "%"

или

price + " USD"

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

Полезно:

numeric: "auto"

в Intl.RelativeTimeFormat.


Избегание чрезмерных сокращений

Плохо для доступности:

1K
2M
5B

Учет региональных особенностей

Разные страны используют:

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

Совместимость браузеров

Большинство возможностей Intl API поддерживаются:

  • Chrome;
  • Firefox;
  • Safari;
  • Edge;
  • Node.js.

Некоторые современные компоненты (Intl.Segmenter, formatRange) могут отсутствовать в старых браузерах, поэтому в крупных проектах рекомендуется проверка поддержки:

if (Intl.Segmenter) {
  // поддерживается
}

Polyfill для старых окружений

Для устаревших браузеров используются polyfill-библиотеки:

  • @formatjs/intl-numberformat
  • @formatjs/intl-datetimeformat
  • @formatjs/intl-relativetimeformat

Они обеспечивают одинаковое поведение локализации даже в старых средах выполнения JavaScript.