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. カスタム小数点精度で価格をフォーマットする
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コンポーネントが使用できないコンテキストに適したプレーンな文字列を返します。