Форматирование чисел

Основы работы Intl.NumberFormat

Intl.NumberFormat предоставляет механизм локализованного форматирования чисел с учётом правил конкретного языка и региона. Основная задача — преобразование числовых значений в строковое представление с правильными разделителями, округлением, обозначениями валют и другими параметрами отображения.

Создание форматтера происходит через конструктор:

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

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

Форматирование выполняется методом format:

formatter.format(1234567.89);
// "1 234 567,89"

Локали и их влияние на представление чисел

Локаль задаёт правила визуального представления чисел:

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

Примеры различий:

new Intl.NumberFormat('en-US').format(1234567.89);
// "1,234,567.89"

new Intl.NumberFormat('de-DE').format(1234567.89);
// "1.234.567,89"

new Intl.NumberFormat('hi-IN').format(1234567.89);
// "12,34,567.89"

Группировка цифр зависит от региональных стандартов, а не от фиксированного алгоритма.


Базовые режимы форматирования: style

Параметр style определяет тип представления числа.

decimal

Стандартный числовой формат:

new Intl.NumberFormat('ru-RU', { style: 'decimal' }).format(1000);
// "1 000"

Используется по умолчанию.


currency

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

new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'RUB'
}).format(1234.5);
// "1 234,50 ₽"

Поддерживаются коды валют ISO 4217. Отображение символа валюты зависит от локали.

Дополнительные параметры:

  • currencyDisplay: "symbol" | "narrowSymbol" | "code" | "name"
  • currencySign: "standard" | "accounting"

Пример:

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

percent

Процентное представление чисел:

new Intl.NumberFormat('ru-RU', {
  style: 'percent'
}).format(0.25);
// "25 %"

Значение автоматически умножается на 100.


unit

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

new Intl.NumberFormat('ru-RU', {
  style: 'unit',
  unit: 'kilometer'
}).format(50);
// "50 км"

Дополнительный параметр:

  • unitDisplay: "long" | "short" | "narrow"

Управление разрядностью и округлением

Параметры управления точностью:

  • minimumFractionDigits
  • maximumFractionDigits
  • minimumIntegerDigits
  • minimumSignificantDigits
  • maximumSignificantDigits

Пример контроля дробной части:

new Intl.NumberFormat('ru-RU', {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
}).format(12);
// "12,00"

Ограничение значащих цифр:

new Intl.NumberFormat('ru-RU', {
  minimumSignificantDigits: 3,
  maximumSignificantDigits: 3
}).format(12345.6);
// "12 300"

Алгоритмы округления соответствуют стандарту ICU и учитывают локальные правила.


Группировка разрядов

Параметр useGrouping управляет разделением числа на группы:

new Intl.NumberFormat('ru-RU', {
  useGrouping: true
}).format(1000000);
// "1 000 000"

Возможные значения:

  • true — включено
  • false — отключено
  • "auto" — автоматический выбор
  • "always" — принудительное включение

Нотации представления чисел

Параметр notation изменяет формат вывода больших и малых чисел.

standard

Обычное представление:

new Intl.NumberFormat('ru-RU', {
  notation: 'standard'
}).format(1000000);
// "1 000 000"

scientific

Экспоненциальная форма:

new Intl.NumberFormat('ru-RU', {
  notation: 'scientific'
}).format(12345);
// "1,2345E4"

engineering

Инженерная нотация с кратностью 10³:

new Intl.NumberFormat('ru-RU', {
  notation: 'engineering'
}).format(12345);
// "12,345E3"

compact

Сокращённая форма для больших чисел:

new Intl.NumberFormat('ru-RU', {
  notation: 'compact'
}).format(1500000);
// "1,5 млн"

Дополнительный параметр:

  • compactDisplay: "short" | "long"
new Intl.NumberFormat('ru-RU', {
  notation: 'compact',
  compactDisplay: 'long'
}).format(1500000);
// "1,5 миллиона"

Управление отображением знаков

Параметр signDisplay контролирует отображение плюса и минуса:

new Intl.NumberFormat('ru-RU', {
  signDisplay: 'always'
}).format(10);
// "+10"

Возможные значения:

  • auto — только отрицательные значения
  • always — всегда отображать знак
  • never — скрывать знак
  • exceptZero — скрывать для нуля

Системы счисления

Параметр numberingSystem задаёт используемую цифровую систему:

new Intl.NumberFormat('ar-EG-u-nu-arab').format(1234);
// использование араб-индийских цифр

Поддерживаются системы:

  • латинская
  • арабская
  • индийская
  • тайская и другие, в зависимости от окружения

Разбиение результата на части: formatToParts

Метод formatToParts возвращает структуру форматированного числа:

new Intl.NumberFormat('ru-RU').formatToParts(1234.5);

Результат:

[
  { type: 'integer', value: '1' },
  { type: 'group', value: ' ' },
  { type: 'integer', value: '234' },
  { type: 'decimal', value: ',' },
  { type: 'fraction', value: '5' }
]

Типы частей:

  • integer
  • fraction
  • decimal
  • group
  • literal
  • currency
  • unit

Такой формат позволяет собирать кастомные представления без потери локализации.


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

Метод formatRange позволяет отображать интервалы:

new Intl.NumberFormat('ru-RU').formatRange(10, 20);
// "10–20"

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

Метод formatRangeToParts возвращает структурированное представление диапазона с разделением на элементы первой и второй границы.


Повторное использование экземпляров форматтера

Создание Intl.NumberFormat — относительно дорогостоящая операция. Практика оптимизации предполагает повторное использование экземпляров:

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

function formatPrice(value) {
  return nf.format(value);
}

Такой подход снижает нагрузку при массовом форматировании.


Поведение округления и обработка крайних значений

Форматирование учитывает специальные случаи:

  • NaN → строковое представление "NaN"
  • Infinity → "∞"
  • -Infinity → "-∞"
new Intl.NumberFormat('ru-RU').format(NaN);
// "NaN"

Округление выполняется по правилам, зависящим от конфигурации точности, а не от встроенного Math.round.


Совместимость параметров

Не все комбинации параметров поддерживаются одинаково во всех окружениях. При отсутствии поддержки браузер может игнорировать часть опций и применять ближайшие допустимые значения согласно ICU-таблицам локализации.

Особенно это касается:

  • unit
  • notation: 'compact'
  • numberingSystem

Поведение в таких случаях определяется реализацией движка JavaScript.