Группировка разрядов — это механизм визуального разделения длинных
числовых значений на блоки (обычно по три цифры), что повышает
читаемость. В международной локализации этот процесс строго регулируется
правилами CLDR (Unicode Common Locale Data Repository), которые
используются в JavaScript через Intl и, в экосистеме
FormatJS, через react-intl.
В разных локалях один и тот же принцип реализуется по-разному:
en-US: 1,234,567ru-RU: 1 234 567 (неразрывный пробел)de-DE: 1.234.567Эти различия не являются косметическими — они отражают стандарты локалей и напрямую влияют на корректность отображения финансовых и статистических данных.
В основе FormatJS лежит стандартный Intl.NumberFormat.
Именно он определяет поведение группировки разрядов.
const formatter = new Intl.NumberFormat('ru-RU');
formatter.format(1234567);
Результат:
1 234 567
FormatJS в react-intl использует тот же механизм:
import { createIntl, createIntlCache } from 'react-intl';
const cache = createIntlCache();
const intl = createIntl(
{
locale: 'ru-RU',
messages: {}
},
cache
);
intl.formatNumber(1234567);
Группировка разрядов управляется параметром useGrouping.
Он определяет, будут ли вставляться разделители между разрядами.
new Intl.NumberFormat('en-US', {
useGrouping: true
}).format(1234567);
Результат:
1,234,567
Отключение группировки:
new Intl.NumberFormat('en-US', {
useGrouping: false
}).format(1234567);
Результат:
1234567
В FormatJS этот параметр передаётся через formatNumber
или компонент FormattedNumber.
В react-intl группировка включена по умолчанию, так как
она определяется локалью и стандартом ICU.
import { FormattedNumber } from 'react-intl';
<FormattedNumber value={1234567} />
Вывод зависит от локали:
en-US → 1,234,567ru-RU → 1 234 567FormatJS позволяет переопределять поведение через объект параметров,
аналогичный Intl.NumberFormatOptions.
<FormattedNumber
value={1234567}
useGrouping={true}
/>
Или через API:
intl.formatNumber(1234567, {
useGrouping: true
});
Группировка определяется не только булевым флагом, но и локальными шаблонами CLDR.
Основные варианты:
Standard grouping Используется в большинстве локалей: группы по три цифры слева направо.
Indian grouping Используется в индийской системе счисления:
12,34,56,789Minimum grouping Применяется при необходимости сокращённого отображения больших чисел.
FormatJS не требует ручного выбора этих правил — они подтягиваются из локали:
new Intl.NumberFormat('en-IN').format(123456789);
Результат:
12,34,56,789
Группировка применяется к различным типам числовых значений:
Пример с десятичными числами:
new Intl.NumberFormat('en-US').format(1234567.89);
Результат:
1,234,567.89
FormatJS сохраняет группировку независимо от дробной части.
При работе с валютами группировка становится частью общего формата:
<FormattedNumber
value={1234567}
style="currency"
currency="USD"
/>
Результат:
$1,234,567.00
Для ru-RU:
1 234 567,00 $
Важно, что группировка сохраняется даже при смене знаков валюты и позиции символа.
FormatJS часто используется не напрямую через Intl, а
через ICU MessageFormat.
import { FormattedMessage } from 'react-intl';
<FormattedMessage
defaultMessage="Баланс: {balance, number}"
values={{
balance: 1234567
}}
/>
Результат:
Баланс: 1 234 567
Группировка здесь не задаётся явно — она наследуется от локали и настроек форматирования числа.
FormatJS позволяет задавать именованные форматы через
IntlProvider:
<IntlProvider
locale="en-US"
defaultFormats={{
number: {
compactGrouping: {
notation: 'compact',
useGrouping: true
}
}
}}
>
Использование:
<FormattedNumber
value={1234567}
format="compactGrouping"
/>
Результат:
1.2M
Хотя это уже компактная запись, группировка здесь теряет традиционный смысл, но логика форматирования остаётся связанной с числовыми разрядами.
В некоторых локалях (например, ru-RU,
fr-FR) разделитель групп — это не символ запятой, а пробел
или узкий неразрывный пробел (U+202F).
Это важно учитывать при:
const formatted = new Intl.NumberFormat('ru-RU').format(1000000);
// "1 000 000"
В FormatJS этот символ сохраняется как часть строки и не является обычным пробелом.
Опция notation может изменять отображение числа, но не
отменяет группировку, если она допустима:
new Intl.NumberFormat('en-US', {
notation: 'standard',
useGrouping: true
}).format(1234567);
При compact группировка заменяется сокращением:
new Intl.NumberFormat('en-US', {
notation: 'compact',
useGrouping: true
}).format(1234567);
Результат:
1.2M
В реальных приложениях FormatJS группировка важна для:
Ключевой принцип: никогда не формировать разделители
вручную через replace или регулярные
выражения.
Пример неправильного подхода:
number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
Проблемы:
Правильный подход:
new Intl.NumberFormat(locale).format(number);
Группировка выполняется после применения правил округления:
new Intl.NumberFormat('en-US', {
maximumFractionDigits: 0
}).format(1234567.89);
Результат:
1,234,568
Сначала происходит округление, затем вставка разделителей.
useGrouping управляет включением и
отключениемIntl.NumberFormatlocale + options + style