Настройка форматтеров по умолчанию

Форматирование значений в FormatJS опирается на стандарты Intl и расширяется через слой конфигурации библиотеки react-intl. Одним из ключевых механизмов является задание форматтеров по умолчанию, которые применяются при вызове formatDate, formatNumber, formatTime, formatRelativeTime и других API без необходимости каждый раз передавать полный набор параметров.

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

Объект formats используется для предопределения наборов правил форматирования. Он разделяется на категории:

  • date
  • time
  • number
  • relativeTime
  • plural

Каждая категория содержит именованные пресеты.

Пример конфигурации:

import { IntlProvider } from "react-intl";

const formats = {
  date: {
    short: {
      year: "numeric",
      month: "2-digit",
      day: "2-digit"
    },
    long: {
      year: "numeric",
      month: "long",
      day: "2-digit",
      weekday: "long"
    }
  },
  time: {
    short: {
      hour: "2-digit",
      minute: "2-digit"
    }
  },
  number: {
    integer: {
      maximumFractionDigits: 0
    },
    currencyUSD: {
      style: "currency",
      currency: "USD"
    }
  }
};

export default function App() {
  return (
    <IntlProvider locale="ru" messages={{}} formats={formats}>
      {/* приложение */}
    </IntlProvider>
  );
}

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

Использование именованных форматов

Форматтеры применяются через API formatDate, formatNumber, formatTime или соответствующие компоненты.

import { useIntl } from "react-intl";

function Component() {
  const intl = useIntl();

  const date = intl.formatDate(new Date(), {
    format: "long"
  });

  const price = intl.formatNumber(12345.67, {
    format: "currencyUSD"
  });

  return (
    <>
      <div>{date}</div>
      <div>{price}</div>
    </>
  );
}

При указании format: "long" или format: "currencyUSD" происходит обращение к соответствующему объекту в IntlProvider.formats.

Приоритет параметров форматирования

Механизм разрешения параметров строится по иерархии:

  1. Явно переданные опции в formatDate, formatNumber и аналогичных функциях
  2. Именованные форматы из IntlProvider.formats
  3. Встроенные значения по умолчанию библиотеки
  4. Базовые правила Intl среды выполнения

Любые параметры, переданные напрямую, перекрывают значения из пресета.

intl.formatDate(new Date(), {
  format: "short",
  day: "numeric" // переопределяет значение из short
});

Настройка числовых форматов по умолчанию

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

const formats = {
  number: {
    percent: {
      style: "percent",
      minimumFractionDigits: 2
    },
    compact: {
      notation: "compact"
    }
  }
};

Использование:

intl.formatNumber(0.875, { format: "percent" });
intl.formatNumber(1200000, { format: "compact" });

Форматирование дат и временных значений

Категории date и time объединяют конфигурации для отображения календарных значений. При этом используется стандарт Intl.DateTimeFormat.

const formats = {
  date: {
    weekdayOnly: {
      weekday: "long"
    },
    fullDate: {
      year: "numeric",
      month: "long",
      day: "numeric",
      weekday: "long"
    }
  },
  time: {
    withSeconds: {
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit"
    }
  }
};

Применение:

intl.formatDate(new Date(), { format: "weekdayOnly" });
intl.formatTime(new Date(), { format: "withSeconds" });

Глобальные форматтеры через createIntl

Помимо IntlProvider, конфигурация может быть определена программно через createIntl. Это используется вне React-контекста, например в сервисах или утилитах.

import { createIntl, createIntlCache } from "react-intl";

const cache = createIntlCache();

const intl = createIntl(
  {
    locale: "ru",
    messages: {},
    formats: {
      number: {
        default: {
          minimumFractionDigits: 2
        }
      }
    }
  },
  cache
);

Полученный объект предоставляет те же методы форматирования, что и useIntl.

Переопределение форматов на уровне компонентов

В некоторых случаях требуется локальная модификация форматов без изменения глобальной конфигурации. Для этого параметры передаются напрямую в вызов форматтера.

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

  return (
    <span>
      {intl.formatNumber(value, {
        style: "currency",
        currency: "EUR",
        minimumFractionDigits: 2
      })}
    </span>
  );
}

Такой подход имеет более высокий приоритет, чем любые предустановленные форматы.

Наследование и композиция форматов

Форматы могут комбинироваться через распространение объектов конфигурации. Это позволяет создавать базовые пресеты и расширять их для специфических сценариев.

const baseNumberFormats = {
  integer: {
    maximumFractionDigits: 0
  }
};

const formats = {
  number: {
    ...baseNumberFormats,
    money: {
      style: "currency",
      currency: "USD"
    }
  }
};

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

Поведение при отсутствии формата

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

intl.formatDate(new Date(), {
  format: "nonExistingFormat",
  year: "numeric"
});

В таком случае nonExistingFormat не применяется, но остальные параметры сохраняются.

Локализация и зависимость от locale

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

<IntlProvider locale="en">
<IntlProvider locale="ru">

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

Использование форматов в компонентах FormatJS

FormatJS предоставляет компоненты-обёртки, которые также поддерживают именованные форматы.

import { FormattedDate, FormattedNumber } from "react-intl";

<FormattedDate value={new Date()} format="long" />
<FormattedNumber value={1000} format="integer" />

Компоненты используют те же правила приоритета, что и программный API.

Интеграция с сообщениями и ICU-синтаксисом

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

const messages = {
  balance: "Баланс: {value, number, currencyUSD}"
};

В данном случае currencyUSD берётся из конфигурации formats.number.

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

Создание форматтеров связано с использованием Intl объектов, которые могут быть затратными при частом создании. FormatJS использует внутренний кеш через createIntlCache, уменьшая количество повторных инстанциаций форматтеров.

const cache = createIntlCache();

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

Ошибки конфигурации и типичные ограничения

Некорректные ключи в formats не приводят к исключению, но могут вызывать игнорирование конфигурации. Частая проблема связана с несоответствием структуры:

  • использование неизвестных опций Intl.DateTimeFormat
  • неправильное имя формата
  • конфликт между локалью и параметрами форматирования

Приоритет всегда отдаётся валидным параметрам Intl среды выполнения, а не произвольным полям конфигурации.