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>Premium Plan</h2>
      <Price value={1200.5} currency="USD" />
    </div>
  );
}

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

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

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

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コンポーネントを使用できないあらゆるコンテキストに適したプレーン文字列を返します。