如何在 Next.js(Pages Router)v16 中显示货币信息

展示货币代码、名称和符号

问题

应用程序经常需要显示货币信息,但不一定要显示具体价格。例如,货币选择器可能会列出可用货币,文档可能会引用汇率,支付表单可能会展示支持哪些货币。仅显示 "USD" 对非技术用户来说很难理解,而硬编码 "US Dollar" 则需要手动翻译和维护。像 "$" 这样的货币符号也容易混淆——同一个符号可能代表美元、加元或澳元。合适的展示方式取决于具体场景和用户的语言环境。

解决方案

使用 react-intl 的格式化功能,根据不同场景显示合适的货币信息。对于完整的货币名称,可以使用 formatDisplayName 并指定货币类型,这样 "US Dollar" 会自动根据用户语言本地化。对于货币符号,可以用 Intl.NumberFormat 配合 formatToParts 提取指定货币代码的本地化符号。对于 ISO 代码,直接展示即可。这种方式可以确保货币信息既清晰又本地化,无需手动翻译。

步骤

1. 创建一个用于提取货币符号的辅助函数

使用 Intl.NumberFormat 配合 formatToParts,从格式化数字中提取货币符号。

export function getCurrencySymbol(
  currencyCode: string,
  locale: string,
): string {
  const parts = new Intl.NumberFormat(locale, {
    style: "currency",
    currency: currencyCode,
    currencyDisplay: "narrowSymbol",
  }).formatToParts(0);

  const currencyPart = parts.find((part) => part.type === "currency");
  return currencyPart ? currencyPart.value : currencyCode;
}

currencyDisplay 选项用于控制展示形式:"symbol"、"narrowSymbol"、"code" 或 "name"。该辅助函数可以返回任意货币代码的本地化符号。

2. 创建一个货币信息展示组件

构建一个组件,根据不同的展示模式显示货币信息。

import { useIntl } from "react-intl";
import { useRouter } from "next/router";
import { getCurrencySymbol } from "../utils/getCurrencySymbol";

interface CurrencyDisplayProps {
  currencyCode: string;
  display: "symbol" | "name" | "code";
}

export default function CurrencyDisplay({
  currencyCode,
  display,
}: CurrencyDisplayProps) {
  const intl = useIntl();
  const router = useRouter();
  const locale = router.locale || "en";

  if (display === "symbol") {
    const symbol = getCurrencySymbol(currencyCode, locale);
    return <span>{symbol}</span>;
  }

  if (display === "name") {
    const name = intl.formatDisplayName(currencyCode, { type: "currency" });
    return <span>{name}</span>;
  }

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

使用 formatDisplayName 方法和 type: 'currency' 参数可以返回本地化的货币名称。该组件会根据 display 属性自动调整输出内容。

3. 在不同场景中使用该组件

在需要展示货币信息但不显示价格的地方应用货币显示组件。

import CurrencyDisplay from "../components/CurrencyDisplay";

export default function PaymentOptions() {
  const acceptedCurrencies = ["USD", "EUR", "GBP", "JPY"];

  return (
    <div>
      <h2>Accepted Currencies</h2>
      <ul>
        {acceptedCurrencies.map((code) => (
          <li key={code}>
            <CurrencyDisplay currencyCode={code} display="name" />
            {" ("}
            <CurrencyDisplay currencyCode={code} display="symbol" />
            {")"}
          </li>
        ))}
      </ul>
    </div>
  );
}

该组件会渲染带有符号的本地化货币名称,例如英文中的 "US Dollar ($)" 或法文中的 "Dollar américain ($)",并会根据用户的语言环境自动适配。