Компактная нотация

Компактная нотация в интернационализации предназначена для сокращённого представления чисел и величин, особенно в интерфейсах с ограниченным пространством: дашбордах, мобильных приложениях, финансовых панелях, метриках аналитики. В экосистеме FormatJS она реализуется через стандартные механизмы Intl API и интегрируется в форматирование сообщений ICU.


Основной механизм компактного отображения чисел опирается на параметр notation: 'compact' в Intl.NumberFormat. Он активирует сокращённые формы представления величин:

const nf = new Intl.NumberFormat('en-US', {
  notation: 'compact',
  compactDisplay: 'short'
});

nf.format(1200);     // "1.2K"
nf.format(1500000);  // "1.5M"
nf.format(2300000000); // "2.3B"

Ключевые параметры:

  • notation: 'compact' — включение компактного режима

  • compactDisplay: 'short' | 'long' — стиль сокращения

    • short: “1K”, “1M”
    • long: “1 thousand”, “1 million”

Локаль влияет на правила сокращения. Например:

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

Локализационная зависимость компактных форм

Компактная нотация является частью CLDR-данных, на которых базируется FormatJS. Разные языки используют различные суффиксы и правила округления:

  • английский: K, M, B
  • русский: тыс., млн, млрд
  • японский: 万, 億

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


Интеграция с ICU MessageFormat

В системе сообщений ICU компактная нотация применяется не напрямую как параметр числа, а через предварительно отформатированные значения.

Пример базового использования:

import { defineMessages, useIntl } from 'react-intl';

const messages = defineMessages({
  followers: {
    id: 'user.followers',
    defaultMessage: '{count} подписчиков'
  }
});

const value = new Intl.NumberFormat('ru-RU', {
  notation: 'compact'
}).format(15300);

// value = "15,3 тыс."

Далее результат подставляется в сообщение:

intl.formatMessage(messages.followers, {
  count: value
});

Такой подход разделяет:

  • числовую локализацию
  • текстовую композицию сообщений

Компактные числа в форматировании сообщений FormatJS

В реальных сценариях компактная нотация часто используется в UI-строках, где важна плотность информации:

Примеры метрик

const impressions = new Intl.NumberFormat('en', {
  notation: 'compact'
}).format(984321);

const clicks = new Intl.NumberFormat('en', {
  notation: 'compact'
}).format(12034);

Далее в ICU-шаблоне:

{
  "stats": "{impressions} impressions · {clicks} clicks"
}

Особенности округления

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

new Intl.NumberFormat('en', {
  notation: 'compact',
  maximumFractionDigits: 1
}).format(1599);
// "1.6K"

Параметры:

  • maximumFractionDigits — контроль точности
  • minimumFractionDigits — сохранение разрядности
  • roundingMode (в современных реализациях) — стратегия округления

Поведение на границах разрядов

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

999 -> "999"
1000 -> "1K"
999999 -> "999.9K"
1000000 -> "1M"

Эти границы определяются локализационными правилами CLDR, а не фиксированными степенями 10³.


Использование в FormatJS для UI-компонентов

В архитектуре FormatJS компактные числа часто используются как промежуточный слой форматирования:

function formatCompactNumber(intl, value) {
  return intl.formatNumber(value, {
    notation: 'compact',
    compactDisplay: 'short'
  });
}

Интеграция с React Intl:

import { useIntl } from 'react-intl';

function Stats({ value }) {
  const intl = useIntl();

  const formatted = intl.formatNumber(value, {
    notation: 'compact'
  });

  return <span>{formatted}</span>;
}

Локализация и культурные различия

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

  • В английской системе используется короткая шкала (K, M, B)
  • В ряде европейских языков возможны разные сокращения тысяч
  • В восточноазиатских языках применяются иероглифические разряды

FormatJS делегирует эти различия Intl API, что позволяет избегать ручного управления суффиксами.


Ограничения компактной нотации

Несмотря на универсальность, компактная нотация имеет ограничения:

  • Потеря точности при малых различиях значений
  • Неоднозначность восприятия без контекста
  • Различие форматов между локалями может влиять на UX
  • Не всегда подходит для юридически значимых данных

Сочетание с другими форматами

Компактная нотация часто комбинируется с другими форматами:

Валюты

new Intl.NumberFormat('en', {
  style: 'currency',
  currency: 'USD',
  notation: 'compact'
}).format(1200000);
// "$1.2M"

Проценты

new Intl.NumberFormat('en', {
  style: 'percent',
  notation: 'compact'
}).format(0.153);
// "15%"

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

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

const cache = new Map();

function getFormatter(locale) {
  if (!cache.has(locale)) {
    cache.set(locale, new Intl.NumberFormat(locale, {
      notation: 'compact'
    }));
  }
  return cache.get(locale);
}

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


Взаимодействие с серверным рендерингом

При SSR важно синхронизировать локаль:

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

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


Поведение в разных версиях ECMAScript

Поддержка notation: 'compact' появилась относительно поздно, поэтому:

  • старые окружения требуют полифилов
  • современные браузеры реализуют CLDR-совместимое поведение
  • FormatJS учитывает доступность Intl API и может эмулировать форматирование

Компактная нотация выступает как слой визуальной оптимизации поверх локализованных числовых правил, позволяя выражать большие значения в краткой форме без потери семантической корректности в рамках выбранной локали.