Next.js(Pages Router)v16で通貨金額をフォーマットする方法
通貨記号と区切り記号を使用して価格を表示する
問題
金額を表示するには、通貨自体とユーザーの地域の数値フォーマット規則という2つの異なるローカライゼーションの問題を調整する必要があります。1200.50という価格は、米国英語ユーザーには「$1,200.50」と表示される必要がありますが、ドイツのユーザーには「1 200,50 €」と表示される必要があります。通貨記号の位置、小数点区切り文字、桁区切り文字、間隔はすべてロケールによって異なります。これらの要素が不整合であったりハードコードされていると、ユーザーは見慣れないフォーマットを目にし、表示されている金額が正しいかどうか疑問を抱き、価格情報への信頼を損なうことになります。
視覚的な一貫性を超えて、不正確な通貨フォーマットは実際の混乱を引き起こす可能性があります。千の位区切りとしてカンマに慣れているユーザーは、「1.200」を1200ではなく1.2と誤読する可能性があります。同様に、通貨記号の位置が間違っていると、価格が非専門的に見えたり、まったく異なる通貨を示唆したりする可能性があります。適切な通貨フォーマットは、通貨コードとユーザーのロケール固有の数値規則の両方を尊重し、価格が即座に明確で信頼できるものであることを保証します。
解決策
ISO 4217通貨コードとユーザーのアクティブなロケールを組み合わせて、地域に適した数値フォーマットを生成することで通貨値をフォーマットします。このアプローチでは、記号の配置、区切り文字の選択、間隔のルールを国際化ライブラリに委任し、各ロケールと通貨のペアに対して正しい規則を適用します。結果として、アプリケーションコードで手動の文字列操作やロケール固有のロジックを使用せずに、ユーザーの期待に合った価格表示が実現します。
ステップ
1. 再利用可能な通貨フォーマットコンポーネントを作成する
数値と通貨コードを受け取り、react-intlのコンテキストから現在のロケールを使用して価格をフォーマットするコンポーネントを構築します。
import { FormattedNumber } from "react-intl";
interface PriceProps {
value: number;
currency: string;
}
export default function Price({ value, currency }: PriceProps) {
return <FormattedNumber value={value} style="currency" currency={currency} />;
}
FormattedNumberコンポーネントは最も近いIntlProviderからロケールを読み取り、通貨記号とロケール固有の数値フォーマットルールの両方を自動的に適用します。
2. 動的な価格データを持つページでコンポーネントを使用する
数値金額と通貨コードをコンポーネントに渡して価格をレンダリングし、ユーザーのロケールに合わせてフォーマットを適応させます。
import { GetServerSideProps } from "next";
import Price from "../components/Price";
interface Product {
id: string;
name: string;
price: number;
currency: string;
}
interface ProductPageProps {
product: Product;
}
export default function ProductPage({ product }: ProductPageProps) {
return (
<div>
<h1>{product.name}</h1>
<p>
<Price value={product.price} currency={product.currency} />
</p>
</div>
);
}
export const getServerSideProps: GetServerSideProps = async () => {
const product = {
id: "1",
name: "Wireless Headphones",
price: 1299.99,
currency: "USD",
};
return {
props: {
product,
},
};
};
このページは製品データ(通貨コードを含む)を取得し、それをPriceコンポーネントに渡します。コンポーネントはアクティブなロケールに従って金額をフォーマットします。
3. 命令型の通貨フォーマット用ヘルパーを作成する
Reactコンポーネントが使用できないシナリオ(属性の設定やJSX以外のコンテキスト用のデータ準備など)のために、useIntlフックを使用してフォーマット関数を公開します。
import { useIntl } from "react-intl";
export function useCurrencyFormatter() {
const intl = useIntl();
return (value: number, currency: string): string => {
return intl.formatNumber(value, {
style: "currency",
currency,
});
};
}
このフックは通貨値を文字列としてフォーマットする関数を返します。これはaria label、メタタグ、またはコンポーネントが適切でないテキストのみのコンテキストで役立ちます。
4. 属性コンテキストでフォーマッタを適用する
Reactエレメントではなくプレーンテキストを必要とするHTML属性に、命令型フォーマッタを使用します。
import { useCurrencyFormatter } from "../hooks/useCurrencyFormatter";
interface ProductCardProps {
name: string;
price: number;
currency: string;
imageUrl: string;
}
export default function ProductCard({
name,
price,
currency,
imageUrl,
}: ProductCardProps) {
const formatCurrency = useCurrencyFormatter();
const priceLabel = formatCurrency(price, currency);
return (
<article aria-label={`${name}, ${priceLabel}`}>
<img src={imageUrl} alt={name} />
<h2>{name}</h2>
<p>{priceLabel}</p>
</article>
);
}
フォーマッタはローカライズされた通貨文字列を生成し、それをaria-label属性に埋め込むことができます。これにより支援技術がユーザーのロケールに合った正しい形式で価格を通知することを保証します。