如何在 React Router v7 中显示货币信息

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

问题

应用程序通常需要显示货币信息,但不一定需要显示格式化的价格。例如,货币选择器可能显示 "USD" 或 "美元",而财务仪表板可能仅显示 "$" 符号。每种格式都有不同的用途,但它们都面临共同的挑战。ISO 代码 "USD" 精确但对非技术用户不够直观;全称 "美元" 清晰但需要为国际用户进行翻译;符号 "$" 简洁但含义模糊——根据上下文,它可能代表美元、加元或澳元。选择错误的格式会让用户感到困惑,并削弱对金融界面的信任。

在构建多语言应用程序时,这一挑战更加复杂。适用于英语的货币名称可能无法直接翻译成其他语言,而符号的使用习惯因地区而异。硬编码这些值会增加维护负担,并限制应用程序的覆盖范围。

解决方案

使用 react-intl 的 formatDisplayName 方法显示本地化的货币名称和代码,并利用浏览器的 Intl.NumberFormat API 提取货币符号。formatDisplayName 方法接受一个货币代码,并根据用户的语言环境返回适当的本地化名称,自动处理翻译。对于符号,可以使用货币格式化一个示例数字,并从结果中提取符号部分。

为每种显示格式(全称、符号或代码)创建专注的辅助函数或组件,这样可以根据上下文选择合适的表示方式。这种方法将货币显示逻辑集中管理,确保应用程序的一致性,同时尊重用户的语言环境偏好。

步骤

1. 创建一个显示本地化货币名称的辅助工具

使用 formatDisplayName 方法和 type: 'currency' 参数,将 ISO 货币代码转换为本地化的全名。

import { useIntl } from "react-intl";

export function CurrencyName({ code }: { code: string }) {
  const intl = useIntl();
  const name = intl.formatDisplayName(code, { type: "currency" });
  return <span>{name}</span>;
}

当语言环境为 "en" 且代码为 "CNY" 时,这将显示 "Chinese Yuan"。该方法会根据 IntlProvider 的当前语言环境自动翻译名称。

2. 创建一个辅助函数以提取和显示货币符号

使用 Intl.NumberFormatformatToParts 提取货币符号,通过过滤 type === "currency" 的部分实现。

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

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

export function CurrencySymbol({ code }: { code: string }) {
  const intl = useIntl();
  const symbol = getCurrencySymbol(intl.locale, code);
  return <span>{symbol}</span>;
}

currencyDisplay 选项控制货币的显示形式,其中 "narrowSymbol" 提供最紧凑的表示形式。此方法会自动处理特定语言环境的符号位置和格式。

3. 创建一个提供多种显示选项的组件

构建一个灵活的组件,接受一个显示模式属性以在代码、符号和名称格式之间切换。

import { useIntl } from "react-intl";

type CurrencyDisplayMode = "code" | "symbol" | "name";

interface CurrencyInfoProps {
  code: string;
  display?: CurrencyDisplayMode;
}

export function CurrencyInfo({ code, display = "symbol" }: CurrencyInfoProps) {
  const intl = useIntl();

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

  if (display === "symbol") {
    const parts = new Intl.NumberFormat(intl.locale, {
      style: "currency",
      currency: code,
      currencyDisplay: "narrowSymbol",
    }).formatToParts(0);
    const symbol =
      parts.find((part) => part.type === "currency")?.value || code;
    return <span>{symbol}</span>;
  }

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

此组件集中管理货币显示逻辑,并使其易于根据 UI 上下文切换格式。在需要清晰度的货币选择器中使用 display="name",在表头等紧凑显示中使用 display="symbol",在技术或财务报告中使用 display="code"

4. 在不同的上下文中使用组件

根据货币信息在界面中出现的位置,应用适当的显示模式。

export default function CurrencyExample() {
  return (
    <div>
      <label htmlFor="currency-select">
        选择货币:<CurrencyInfo code="EUR" display="name" />
      </label>

      <table>
        <thead>
          <tr>
            <th>
              金额 (<CurrencyInfo code="USD" display="symbol" />)
            </th>
          </tr>
        </thead>
      </table>

      <p>
        交易货币:<CurrencyInfo code="GBP" display="code" />
      </p>
    </div>
  );
}

每个上下文都使用最适合其目的的格式:选择界面使用全名,紧凑显示使用符号,精确的技术参考使用代码。组件会根据来自 IntlProvider 的用户区域设置自动处理本地化。