Как форматировать даты для разных локалей в React Router v7
Отображайте даты в региональных форматах
Проблема
У дат нет универсального письменного формата. Например, числовая последовательность 10/12/2025 означает 12 октября в США, но 10 декабря в Великобритании. Даже такие форматы, как «12 окт. 2025», предполагают английские названия месяцев и определённый порядок, который может не совпадать с ожиданиями пользователя. Если приложение показывает даты только в одном фиксированном формате, это выглядит чуждо для пользователей из других регионов, снижая понятность и доверие.
В разных локалях существуют свои правила отображения дат: порядок дня, месяца и года, выбор разделителей, написание месяца полностью или сокращённо. Игнорирование этих особенностей заставляет пользователя мысленно переводить даты в привычный формат, что увеличивает когнитивную нагрузку и риск ошибки.
Решение
Форматируйте даты в соответствии с локалью пользователя, передавая логику отображения специализированным API интернационализации, которые знают региональные стандарты. Вместо ручной сборки строк дат передавайте объекты дат в функции или компоненты, которые применяют правильный порядок, разделители и названия месяцев для выбранной локали.
React-intl предоставляет как декларативные компоненты, так и императивные методы, которые принимают стандартные параметры форматирования дат и возвращают строки с учётом локали. Указывая, какие части даты и уровень детализации нужны, вы контролируете стиль вывода, а библиотека учитывает региональные различия. Такой подход отделяет логику форматирования дат от компонентов отображения и обеспечивает единообразие по всему приложению.
Шаги
1. Форматируйте даты в компонентах с помощью FormattedDate
Используйте компонент FormattedDate из react-intl для отображения дат с учетом локали. Компонент принимает значение даты и параметры форматирования, которые соответствуют Intl.DateTimeFormatOptions.
import { FormattedDate } from "react-intl";
export default function EventCard({ event }) {
return (
<article>
<h2>{event.title}</h2>
<time>
<FormattedDate
value={event.date}
year="numeric"
month="long"
day="numeric"
/>
</time>
<p>{event.description}</p>
</article>
);
}
Компонент FormattedDate использует API formatDate и Intl.DateTimeFormat для создания строки, соответствующей локали, заданной окружающим IntlProvider. Опции year, month и day управляют тем, какие части отображаются и в каком формате.
2. Императивное форматирование дат с помощью useIntl
Используйте хук useIntl, чтобы получить доступ к методу formatDate, когда вам нужна отформатированная дата для нерендеримых контекстов, таких как атрибуты, aria-метки или преобразование данных.
import { useIntl } from "react-intl";
export default function EventList({ events }) {
const intl = useIntl();
return (
<ul>
{events.map((event) => {
const formattedDate = intl.formatDate(event.date, {
year: "numeric",
month: "short",
day: "numeric",
});
return (
<li key={event.id}>
<a
href={`/events/${event.id}`}
aria-label={`${event.title} on ${formattedDate}`}
>
{event.title}
</a>
</li>
);
})}
</ul>
);
}
Функция formatDate принимает значение даты и необязательные Intl.DateTimeFormatOptions, возвращая строку, отформатированную по локали. Это удобно, когда форматированная дата должна быть встроена в другую строку или использоваться как значение пропса.
3. Создайте переиспользуемый помощник для форматирования дат
Вынесите общие шаблоны форматирования дат в вспомогательную функцию, которая оборачивает intl.formatDate, чтобы обеспечить единообразие по всему приложению.
import { useIntl } from "react-intl";
export function useDateFormatter() {
const intl = useIntl();
return {
formatShortDate: (date: Date | number) =>
intl.formatDate(date, {
year: "numeric",
month: "numeric",
day: "numeric",
}),
formatLongDate: (date: Date | number) =>
intl.formatDate(date, {
year: "numeric",
month: "long",
day: "numeric",
}),
formatDateTime: (date: Date | number) =>
intl.formatDate(date, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
}),
};
}
Этот хук централизует логику форматирования и позволяет легко применять единый стиль дат во всем приложении. Компоненты вызывают нужный метод в зависимости от требуемой детализации.
4. Форматируйте даты в загрузчиках маршрутов
Когда требуется форматирование дат при загрузке данных, получите локаль из запроса и используйте createIntl для форматирования дат перед возвратом данных загрузчика.
import type { Route } from "./+types/event";
import { createIntl, createIntlCache } from "react-intl";
const cache = createIntlCache();
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const locale = url.searchParams.get("locale") || "en";
const event = await fetchEvent();
const intl = createIntl({ locale, messages: {} }, cache);
return {
event,
formattedDate: intl.formatDate(event.date, {
year: "numeric",
month: "long",
day: "numeric",
}),
};
}
export default function Event({ loaderData }: Route.ComponentProps) {
return (
<article>
<h1>{loaderData.event.title}</h1>
<time>{loaderData.formattedDate}</time>
</article>
);
}
Функция createIntl создаёт intl-объект, который может форматировать даты вне компонентов React. Такой подход позволяет предварительно форматировать даты на сервере или при статической генерации, снижая нагрузку на клиент.