如何在 Next.js(Pages Router)v16 中格式化货币金额
显示带有货币符号和分隔符的价格
问题
显示货币值需要协调两个不同的本地化问题:货币本身和用户所在地区的数字格式约定。对于美国英语用户,1200.50 的价格必须显示为 "$1,200.50",而对于德国用户,则应显示为 "1 200,50 €"。货币符号的位置、小数点分隔符、分组分隔符和间距因地区而异。当这些元素未对齐或被硬编码时,用户会看到不熟悉的格式,从而对显示的金额是否正确产生怀疑,削弱了对价格信息的信任。
除了视觉一致性之外,不正确的货币格式还可能引起实际的混淆。习惯于将逗号作为千位分隔符的用户可能会将 "1.200" 误读为一小数点二,而不是一千二百。同样,错误放置的货币符号可能会使价格看起来不专业,或者完全暗示错误的货币。正确的货币格式既尊重货币代码,也尊重用户特定地区的数字约定,确保价格清晰可信。
解决方案
通过结合 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 标签、meta 标签或其他仅限文本的上下文中,无法使用组件的场景。
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 属性中,确保辅助技术以用户语言环境的正确格式播报价格。