React Router v7에서 다양한 로케일에 맞게 날짜 형식 지정하는 방법
지역별 형식으로 날짜 표시하기
문제
날짜는 보편적인 표기 형식이 없습니다. 숫자 시퀀스 10/12/2025는 미국에서는 10월 12일을 의미하지만 영국에서는 12월 10일을 의미합니다. "Oct 12, 2025"와 같은 형식도 영어 월 이름과 특정 순서 규칙을 가정하는데, 이는 사용자의 기대와 일치하지 않을 수 있습니다. 애플리케이션이 단일 고정 형식으로 날짜를 표시하면 다른 규칙을 따르는 지역의 사용자에게는 이질감을 주어 명확성과 신뢰도가 떨어집니다.
각 로케일마다 일, 월, 년의 순서, 구분 기호 선택, 월 이름의 전체 또는 약어 표기 여부 등 날짜 표현에 관한 고유한 규칙이 있습니다. 이러한 규칙을 무시하면 사용자는 익숙한 형식으로 날짜를 정신적으로 변환해야 하므로 인지 부하가 증가하고 오해의 위험이 높아집니다.
해결책
지역 규칙을 이해하는 국제화 API에 표현 로직을 위임하여 사용자의 로케일에 따라 날짜 값을 형식화합니다. 수동으로 날짜 문자열을 구성하는 대신, 날짜 객체를 형식화 함수나 컴포넌트에 전달하여 활성 로케일에 맞는 올바른 순서, 구분 기호, 월 이름을 적용합니다.
React-intl은 표준 날짜 형식 옵션을 받아들이고 로케일을 인식하는 문자열을 생성하는 선언적 컴포넌트와 명령적 메서드를 모두 제공합니다. 포함할 날짜 부분과 세부 수준을 지정함으로써 출력 스타일을 제어하면서 라이브러리가 지역별 변형을 처리합니다. 이 접근 방식은 날짜 형식 지정 로직을 표시 컴포넌트와 분리하고 애플리케이션 전체에서 일관성을 보장합니다.
단계
1. FormattedDate로 컴포넌트에서 날짜 형식 지정하기
react-intl의 FormattedDate 컴포넌트를 사용하여 로케일별 형식으로 날짜를 렌더링합니다. 이 컴포넌트는 날짜 값과 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 컴포넌트는 formatDate와 Intl.DateTimeFormat API를 사용하여 주변 IntlProvider가 제공하는 로케일과 일치하는 문자열을 생성합니다. year, month, day 옵션은 표시될 부분과 그 형식을 제어합니다.
2. useIntl을 사용하여 명령적으로 날짜 형식 지정하기
속성, aria 레이블 또는 데이터 변환과 같은 렌더링되지 않는 컨텍스트에서 형식이 지정된 날짜 문자열이 필요할 때 useIntl 훅을 사용하여 formatDate 메서드에 접근하세요.
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를 받아 로케일에 맞게 형식이 지정된 문자열을 반환합니다. 이는 형식이 지정된 날짜를 다른 문자열에 포함하거나 prop 값으로 사용해야 할 때 유용합니다.
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 함수는 React 컴포넌트 외부에서 날짜 형식을 지정할 수 있는 intl 객체를 생성합니다. 이 접근 방식은 서버에서 또는 정적 생성 중에 날짜 형식을 미리 지정하여 클라이언트 측 작업을 줄입니다.