Как форматировать даты для разных локалей в 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} на ${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. Этот подход предварительно форматирует даты на сервере или во время статической генерации, уменьшая нагрузку на клиентскую сторону.