Как форматировать числа для разных локалей в TanStack Start v1

Отображение чисел с учётом локальных разделителей

Проблема

Числа записываются по-разному в разных странах. То, что в США выглядит как 10,000.5, в Германии превращается в 10.000,5 — запятая и точка меняются местами. Это не вопрос стиля или предпочтений, а вопрос читаемости. Немец, увидев 10,000.5, может прочитать это как десять, игнорируя разделители разрядов. Американец, увидев 10.000,5, может воспринять это как десять тысяч, не заметив десятичный разделитель. Одни и те же цифры — противоположные значения.

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

Решение

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

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

Шаги

1. Создайте компонент для отображения числа с помощью FormattedNumber

Создайте компонент, который принимает числовое значение и отображает его с учётом локали, используя компонент FormattedNumber из react-intl.

import { FormattedNumber } from "react-intl";

interface PriceDisplayProps {
  value: number;
}

export function PriceDisplay({ value }: PriceDisplayProps) {
  return (
    <div>
      <FormattedNumber value={value} />
    </div>
  );
}

Компонент FormattedNumber автоматически применяет десятичные и разделительные знаки, соответствующие выбранной локали. Он получает локаль из ближайшего IntlProvider в дереве компонентов и форматирует число соответственно.

2. Форматируйте числа с определёнными стилями

Настраивайте форматирование чисел, передавая параметры стиля в FormattedNumber для валюты, процентов или единиц.

import { FormattedNumber } from "react-intl";

interface MetricsProps {
  revenue: number;
  growthRate: number;
  fileSize: number;
}

export function Metrics({ revenue, growthRate, fileSize }: MetricsProps) {
  return (
    <div>
      <p>
        Revenue:{" "}
        <FormattedNumber value={revenue} style="currency" currency="USD" />
      </p>
      <p>
        Growth: <FormattedNumber value={growthRate} style="percent" />
      </p>
      <p>
        Size:{" "}
        <FormattedNumber
          value={fileSize}
          style="unit"
          unit="megabyte"
          unitDisplay="short"
        />
      </p>
    </div>
  );
}

Свойство style управляет режимом форматирования. Для форматирования валюты требуется код currency, для процентов значение автоматически умножается на 100, а для единиц требуется идентификатор unit. Все стили учитывают правила выбранной локали.

3. Императивное форматирование чисел с помощью useIntl

Используйте хук useIntl для форматирования чисел там, где компоненты не подходят, например, при генерации динамических атрибутов или подготовке данных для не-React API.

import { useIntl } from "react-intl";

interface ChartTooltipProps {
  dataPoint: number;
}

export function ChartTooltip({ dataPoint }: ChartTooltipProps) {
  const intl = useIntl();
  const formattedValue = intl.formatNumber(dataPoint, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });

  return <div title={formattedValue}>{formattedValue}</div>;
}

Метод formatNumber сразу возвращает отформатированную строку, что удобно для атрибутов, aria-меток или любых случаев, когда нужно получить значение в виде строки, а не React-элемента.

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

Управляйте точностью, разделением и стилем записи, передавая Intl.NumberFormatOptions как в FormattedNumber, так и в formatNumber.

import { FormattedNumber } from "react-intl";

interface StatisticProps {
  value: number;
  compact?: boolean;
}

export function Statistic({ value, compact }: StatisticProps) {
  return (
    <div>
      <FormattedNumber
        value={value}
        notation={compact ? "compact" : "standard"}
        minimumFractionDigits={0}
        maximumFractionDigits={2}
      />
    </div>
  );
}

Параметры вроде notation, minimumFractionDigits и maximumFractionDigits определяют, как будет отображаться число. Компактная запись сокращает большие числа, например, до «1,2M», с учётом локальных сокращений.