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>
        총 사용자 수: <FormattedNumber value={totalUsers} />
      </p>
      <p>
        성장률: <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>대시보드</h1>
      <p>
        수익:{" "}
        <FormattedNumber value={revenue} style="currency" currency="USD" />
      </p>
      <p>
        판매 수량: <FormattedNumber value={units} />
      </p>
    </div>
  );
}

로더는 원시 숫자 데이터를 제공하고, 컴포넌트는 사용자의 로케일에 따라 이를 형식화합니다. 이러한 분리는 데이터 가져오기를 표현 관련 문제와 독립적으로 유지합니다.