Как форматировать числа для разных локалей в 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>
        Доход:{" "}
        <FormattedNumber value={revenue} style="currency" currency="USD" />
      </p>
      <p>
        Рост: <FormattedNumber value={growthRate} style="percent" />
      </p>
      <p>
        Размер:{" "}
        <FormattedNumber
          value={fileSize}
          style="unit"
          unit="megabyte"
          unitDisplay="short"
        />
      </p>
    </div>
  );
}

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

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

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

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", с учётом локальных сокращений.