如何在 React Router v7 中显示货币信息
显示货币代码、名称和符号
问题
应用程序经常需要显示货币信息,但不一定要展示格式化的价格。例如,货币选择器可能会显示 "USD" 或 "US Dollar",而金融仪表盘可能只显示 "$" 符号。每种格式都有不同的用途,但它们都面临一些共同的挑战。ISO 代码 "USD" 精确,但对非技术用户来说不够直观;全称 "US Dollar" 清晰明了,但需要为国际用户进行翻译;符号 "$" 简洁,但容易产生歧义——它可能代表美元、加元或澳元,具体取决于上下文。选择错误的格式会让用户困惑,降低金融界面的可信度。
在构建多语言应用时,这一挑战会更加突出。英文下适用的货币名称,直接翻译到其他语言可能并不合适,而且不同地区对符号的使用习惯也不一样。如果将这些值硬编码,会增加维护成本,并限制应用的国际化能力。
解决方案
使用 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>;
}
当 locale 为 "en" 且代码为 "CNY" 时,将显示 "Chinese Yuan"。该方法会根据 IntlProvider 提供的当前 locale 自动翻译名称。
2. 创建一个辅助函数以提取和显示货币符号
使用 Intl.NumberFormat 结合 formatToParts,通过筛选 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" 提供最紧凑的表示方式。此方法会自动处理符号在不同 locale 下的位置和格式。
3. 创建一个支持多种显示选项的组件
构建一个灵活的组件,接受 display mode 属性,在代码、符号和名称格式之间切换。
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">
Select currency: <CurrencyInfo code="EUR" display="name" />
</label>
<table>
<thead>
<tr>
<th>
Amount (<CurrencyInfo code="USD" display="symbol" />)
</th>
</tr>
</thead>
</table>
<p>
Transaction currency: <CurrencyInfo code="GBP" display="code" />
</p>
</div>
);
}
每个场景都采用最适合其用途的格式:选择界面用全称,紧凑显示用符号,技术引用用代码。该组件会根据 IntlProvider 提供的用户 locale 自动处理本地化。