React Router v7에서 다양한 로케일에 맞게 숫자 형식을 지정하는 방법

로케일별 구분 기호로 숫자 표시

문제

숫자는 전 세계적으로 다르게 표기됩니다. 미국에서 10,000.5로 표시되는 숫자가 독일에서는 10.000,5가 됩니다. 쉼표와 마침표의 역할이 완전히 바뀝니다. 이것은 선호도나 스타일의 문제가 아니라 가독성의 문제입니다. 독일 사용자가 10,000.5를 보면 자릿수 구분 기호를 무시하고 10으로 읽을 수 있습니다. 미국 사용자가 10.000,5를 보면 소수점 구분 기호를 무시하고 만으로 읽을 수 있습니다.

동일한 숫자가 독자의 지역 규칙에 따라 정반대의 의미를 전달할 수 있습니다. 애플리케이션이 로케일 인식 형식 지정 없이 원시 숫자 값을 표시하면 사용자를 혼란스럽게 하고 제시된 데이터에 대한 신뢰를 훼손할 위험이 있습니다.

솔루션

사용자의 로케일을 기반으로 숫자 형식을 지정하고, 소수점 및 자릿수 구분 기호에 대한 지역 규칙을 사용합니다. 이렇게 하면 숫자 값이 해당 지역 사용자에게 익숙한 형식 지정 규칙을 따르는 문자열로 변환됩니다.

React-intl은 지역별 숫자 규칙의 복잡성을 처리하는 브라우저의 내장 Intl.NumberFormat API를 활용하는 형식 지정 메서드를 제공합니다. 이러한 포맷터를 통해 숫자 값을 전달하면 애플리케이션은 수동 구분 기호 로직 없이 사용자 기대에 부합하는 출력을 생성합니다.

단계

1. useIntl로 숫자 형식을 지정하는 컴포넌트 생성

useIntl 훅은 숫자 값을 받아 로케일에 맞게 포맷된 문자열을 반환하는 formatNumber를 포함한 포맷 메서드에 대한 액세스를 제공합니다.

import { useIntl } from "react-intl";

export default function ProductPrice() {
  const intl = useIntl();
  const price = 1234.56;

  return (
    <div>
      <p>Price: {intl.formatNumber(price)}</p>
    </div>
  );
}

formatNumber 메서드는 현재 로케일에 맞는 올바른 구분 기호를 자동으로 적용합니다. en-US 로케일을 사용하는 사용자는 "1,234.56"을 보는 반면, de-DE 로케일을 사용하는 사용자는 "1.234,56"을 봅니다.

2. 스타일 옵션으로 통화 값 형식 지정

formatNumber 메서드는 통화 포맷을 포함하여 Intl.NumberFormatOptions를 준수하는 옵션을 허용합니다.

import { useIntl } from "react-intl";

export default function ProductPrice() {
  const intl = useIntl();
  const price = 1234.56;

  return (
    <div>
      <p>
        {intl.formatNumber(price, {
          style: "currency",
          currency: "USD",
        })}
      </p>
    </div>
  );
}

이는 en-US의 경우 "$1,234.56"을, de-DE의 경우 "1.234,56 $"를 생성하여 구분 기호와 통화 기호 규칙을 모두 적용합니다.

3. 선언적 형식 지정을 위해 FormattedNumber 사용

FormattedNumber 컴포넌트는 props로 동일한 옵션을 허용하는 선언적 대안을 제공합니다.

import { FormattedNumber } from "react-intl";

export default function Statistics() {
  const totalUsers = 1500000;
  const growthRate = 0.23;

  return (
    <div>
      <p>
        Total users: <FormattedNumber value={totalUsers} />
      </p>
      <p>
        Growth rate: <FormattedNumber value={growthRate} style="percent" />
      </p>
    </div>
  );
}

컴포넌트는 포맷된 숫자를 DOM에 직접 렌더링합니다. en-US의 경우 "1,500,000"과 "23%"를 표시합니다. de-DE의 경우 "1.500.000"과 "23 %"를 표시합니다.

4. 로더 데이터에서 숫자 형식 지정

React Router 7에서 라우트 컴포넌트는 useLoaderData 훅을 통해 로더 데이터에 액세스합니다. 이를 숫자 포맷과 결합하여 서버에서 제공된 값을 표시할 수 있습니다.

import { useLoaderData } from "react-router";
import { FormattedNumber } from "react-intl";

export async function loader() {
  return {
    revenue: 45678.9,
    units: 12500,
  };
}

export default function Dashboard() {
  const { revenue, units } = useLoaderData<typeof loader>();

  return (
    <div>
      <h1>Dashboard</h1>
      <p>
        Revenue:{" "}
        <FormattedNumber value={revenue} style="currency" currency="USD" />
      </p>
      <p>
        Units sold: <FormattedNumber value={units} />
      </p>
    </div>
  );
}

로더는 원시 숫자 데이터를 제공하고, 컴포넌트는 사용자의 로케일에 따라 형식을 지정합니다. 이러한 분리는 데이터 가져오기를 프레젠테이션 관심사와 독립적으로 유지합니다.