TanStack Start v1で通貨金額をフォーマットする方法

通貨記号と区切り記号を使用して価格を表示

問題

価格表示には、通貨表記と数値フォーマットという2つのローカライゼーションの課題があります。同じ金額でも、アメリカでは$1,200.50と表示され、ドイツでは1 200,50 €と表示されます。通貨記号の位置が変わり、小数点と桁区切り記号が入れ替わり、さらにスペースの入れ方も変化します。

これらの表記法は単なる好みではなく、ユーザーの期待に応えるものです。価格を馴染みのないフォーマットで表示すると、ユーザーは正しい金額を見ているのか疑問に思います。ドイツのユーザーに「1200.50 EUR」と表示したり、アメリカのユーザーに「1.200,50$」と表示したりすると、摩擦が生じ信頼が損なわれます。

解決策

通貨と共にユーザーのロケールに基づいて金額を表示します。これにより、通貨記号の配置とロケール固有の数値フォーマットルールが組み合わされ、地域ごとの金銭表示の期待に合った価格表示が実現します。

react-intlのformatNumberメソッドをstyle: 'currency'オプションと共に使用して、通貨コードとユーザーのロケールフォーマット規則の両方を適用します。ブラウザのIntl.NumberFormat APIが記号の配置、区切り文字の選択、スペースの挿入を自動的に処理します。

ステップ

1. 通貨フォーマットコンポーネントを作成する

数値と通貨コードを受け取り、ユーザーのロケールを使用して価格をフォーマットする再利用可能なコンポーネントを構築します。

import { useIntl } from "react-intl";

interface PriceProps {
  value: number;
  currency: string;
}

export function Price({ value, currency }: PriceProps) {
  const intl = useIntl();

  const formattedPrice = intl.formatNumber(value, {
    style: "currency",
    currency: currency,
  });

  return <span>{formattedPrice}</span>;
}

useIntlフックはフォーマットAPIへのアクセスを提供します。style: 'currency'を指定したformatNumberメソッドは、通貨記号とロケール固有の数値フォーマットの両方を適用します。

2. 異なる通貨でコンポーネントを使用する

数値の金額と通貨コードを渡すことで、アプリケーション全体で価格を表示できます。

export default function ProductCard() {
  return (
    <div>
      <h2>プレミアムプラン</h2>
      <Price value={1200.5} currency="USD" />
    </div>
  );
}

コンポーネントは自動的にユーザーのロケールに応じて価格をフォーマットします。米国のユーザーには「$1,200.50」と表示され、ドイツのユーザーには「1.200,50 $」と表示されます。

3. カスタム小数点精度で価格をフォーマットする

minimumFractionDigitsmaximumFractionDigitsオプションを追加することで、表示される小数点以下の桁数を制御できます。

export function PriceWithPrecision({ value, currency }: PriceProps) {
  const intl = useIntl();

  const formattedPrice = intl.formatNumber(value, {
    style: "currency",
    currency: currency,
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });

  return <span>{formattedPrice}</span>;
}

これにより、値が100のような整数であっても、すべての価格で一貫した小数点表示が保証されます。

4. インラインフォーマット用のヘルパーを作成する

コンポーネントラッパーが不要な場合は、フォーマット用のヘルパー関数を作成します。

import { useIntl } from "react-intl";

export function useFormatCurrency() {
  const intl = useIntl();

  return (value: number, currency: string) => {
    return intl.formatNumber(value, {
      style: "currency",
      currency: currency,
    });
  };
}

属性、計算値、またはその他の非JSXコンテキストでフォーマットされた価格が必要な場合は、このフックを使用します。

export function CheckoutSummary({ total }: { total: number }) {
  const formatCurrency = useFormatCurrency();

  return (
    <button aria-label={`Pay ${formatCurrency(total, "USD")}`}>Checkout</button>
  );
}

このヘルパーは、JSXコンポーネントが使用できないコンテキストに適したプレーンな文字列を返します。