如何在 TanStack Start v1 中显示货币信息
展示货币代码、名称和符号
问题
应用程序经常需要显示货币信息,但不一定要展示格式化的价格。例如,货币选择器可能会列出可用货币,一个关于汇率的文章可能会通过符号引用特定货币,或者金融仪表盘可能会显示货币代码。然而,每种表示方式都有局限性。像 "USD" 这样的 ISO 代码虽然精确,但对非技术用户来说难以理解。像 "US Dollar" 这样的全称虽然清晰,但需要为国际用户进行翻译。像 "$" 这样的符号虽然常见,但容易混淆——同一个符号可能代表美元、加元或澳元。在不同场景下选择不合适的格式会降低信息的清晰度,甚至让用户感到困惑。
本地化进一步加大了挑战。适用于英文的货币名称在其他语言中可能不存在或不准确。某些地区通用的符号在其他地区可能并不熟悉。如果没有一致且支持本地化的方法,应用要么只能将货币信息硬编码为单一语言,要么需要维护庞大的翻译表,而这些表很快就会过时。
解决方案
利用浏览器内置的国际化 API,根据用户的语言环境和具体场景,以合适的格式显示货币信息。Intl.DisplayNames API 可以提供本地化的货币全称,而 Intl.NumberFormat 配合 currencyDisplay 选项可以提取货币符号或代码。根据不同场景选择合适的 API 和格式选项,可以确保货币信息既清晰又本地化,无需维护翻译数据。
建议创建小型、可复用的组件或辅助函数,接收货币代码和语言环境参数,并返回合适的货币表示方式。这样可以将货币显示逻辑集中管理,方便在应用的不同位置以不同格式展示同一货币。
步骤
1. 创建一个用于获取本地化货币名称的辅助函数
使用 Intl.DisplayNames API 结合 type: "currency",可以为任意 ISO 4217 货币代码返回本地化的完整货币名称。
export function getCurrencyName(currencyCode: string, locale: string): string {
const displayNames = new Intl.DisplayNames([locale], { type: "currency" });
return displayNames.of(currencyCode) || currencyCode;
}
该辅助函数接收一个三字母的 ISO 货币代码,并返回用户语言下的完整名称。适用于货币选择器或需要清晰说明的文本场景,优先保证信息清晰。
2. 创建一个用于提取货币符号的辅助函数
在 Intl.NumberFormat 中,currencyDisplay 选项用于控制货币的显示方式,可选值包括 "code"、"symbol"、"narrowSymbol" 和 "name"。
export function getCurrencySymbol(
currencyCode: string,
locale: string,
narrow: boolean = false,
): string {
const formatter = new Intl.NumberFormat(locale, {
style: "currency",
currency: currencyCode,
currencyDisplay: narrow ? "narrowSymbol" : "symbol",
});
const parts = formatter.formatToParts(0);
const currencyPart = parts.find((part) => part.type === "currency");
return currencyPart?.value || currencyCode;
}
该辅助函数会格式化一个零值,并仅提取货币符号。narrow 参数用于控制是否使用紧凑符号(如 "$")或区分性符号(如 "US$")。符号适合用于表格、图表等紧凑型界面。
3. 创建一个用于展示货币信息的组件
构建一个灵活的组件,可根据 display 属性以任意格式渲染货币信息。
interface CurrencyDisplayProps {
code: string;
locale: string;
display: "name" | "symbol" | "narrowSymbol" | "code";
}
export function CurrencyDisplay({
code,
locale,
display,
}: CurrencyDisplayProps) {
let content: string;
if (display === "name") {
content = getCurrencyName(code, locale);
} else if (display === "code") {
content = code.toUpperCase();
} else {
content = getCurrencySymbol(code, locale, display === "narrowSymbol");
}
return <span>{content}</span>;
}
该组件集中管理货币显示逻辑,便于切换不同格式。下拉菜单和说明文本建议使用 "name",紧凑显示建议用 "symbol" 或 "narrowSymbol",需要精确时用 "code"。
4. 在 TanStack Start 路由中使用该组件
在任意路由组件中导入并使用该组件,并从 i18n 上下文或路由加载器传递用户的 locale。
import { createFileRoute } from "@tanstack/react-router";
import { CurrencyDisplay } from "~/components/CurrencyDisplay";
export const Route = createFileRoute("/currencies")({
component: CurrenciesPage,
});
function CurrenciesPage() {
const locale = "en-US";
return (
<div>
<h1>Currency Information</h1>
<p>
Full name: <CurrencyDisplay code="USD" locale={locale} display="name" />
</p>
<p>
Symbol: <CurrencyDisplay code="USD" locale={locale} display="symbol" />
</p>
<p>
Code: <CurrencyDisplay code="USD" locale={locale} display="code" />
</p>
</div>
);
}
该组件会以不同格式渲染同一货币。在实际应用中,应从 i18n 提供器或路由上下文获取 locale,确保所有货币显示都遵循用户的语言偏好。