用 25 行代码将 Stripe 价格本地化为访客的货币

发布: (2026年5月5日 GMT+8 03:20)
4 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本(文章正文、代码示例等),我将按照要求保留源链接、Markdown 格式和技术术语,仅翻译正文内容。谢谢!

概览

Stripe 的 Price 对象绑定到单一货币(例如 $79 USD)。
为了解决转化率优化,您可以 显示 访客本地货币的价格(ARS、BRL、EUR,……),同时在后端仍以标准的 USD 金额计费。

工作原理

  1. 将标准价格存储为 USD – 切勿修改 Stripe Price。
  2. 在服务器上检测访客的国家(基于 IP)。
  3. 将国家映射到其本地货币
  4. 从外汇 API 获取实时 USD → 本地货币 汇率
  5. 渲染本地化金额(例如 “≈ AR$ 7 900”)并显示在 USD 价格旁边。
  6. 当用户点击 Buy 时,Stripe 以 USD 处理付款;汇率转换仅用于显示。

这种做法让访客看到熟悉的数字,同时保持 Stripe 的会计简洁且防止退款争议。

Source:

实现

辅助函数:localizedPrice

// lib/localized-price.ts
import { headers } from 'next/headers';

interface LocalizedPrice {
  usd: number;
  display: string;
  currency: string;
  rate: number;
}

const APOGEO = 'https://api.apogeoapi.com/v1';

export async function localizedPrice(usdAmount: number): Promise {
  const ip =
    headers().get('x-forwarded-for')?.split(',')[0] ??
    headers().get('x-real-ip') ??
    '';

  if (!ip) return fallback(usdAmount, 'USD', 1);

  // 1️⃣ Detect visitor country
  const ipRes = await fetch(`${APOGEO}/ip/${ip}`, {
    headers: { 'X-API-Key': process.env.APOGEOAPI_KEY! },
    next: { revalidate: 3600 }, // 1 h
  });
  if (!ipRes.ok) return fallback(usdAmount, 'USD', 1);
  const { country } = await ipRes.json();
  const currency: string = country.currency;
  if (currency === 'USD') return fallback(usdAmount, 'USD', 1);

  // 2️⃣ Fetch live FX rate
  const fxRes = await fetch(`${APOGEO}/exchange-rates/${currency}`, {
    headers: { 'X-API-Key': process.env.APOGEOAPI_KEY! },
    next: { revalidate: 14400 }, // 4 h
  });
  if (!fxRes.ok) return fallback(usdAmount, 'USD', 1);
  const { usdRate }: { usdRate: number } = await fxRes.json();

  const localAmount = Math.round(usdAmount * usdRate);
  const display = new Intl.NumberFormat(undefined, {
    style: 'currency',
    currency,
    maximumFractionDigits: 0,
  }).format(localAmount);

  return { usd: usdAmount, display, currency, rate: usdRate };
}

function fallback(usdAmount: number, currency: string, rate: number): LocalizedPrice {
  return {
    usd: usdAmount,
    display: `$${usdAmount} ${currency}`,
    currency,
    rate,
  };
}

在组件中使用该辅助函数

// components/PricingCard.tsx
import { localizedPrice } from '@/lib/localized-price';

export default async function PricingCard() {
  const price = await localizedPrice(79); // Stripe price in USD

  return (
    <>
      <h2>Professional Plan</h2>

      <p>$79 USD</p>

      {price.currency !== 'USD' && (
        <p>≈ {price.display} at today&apos;s rate</p>
      )}

      <button>Buy now</button>
    </>
  );
}

Practical Tips

  • 永不更改 Stripe Price 对象(按货币),保持单一的美元价格并使用仅显示本地化。
  • 适当四舍五入 —— 例如,ARS(阿根廷比索)没有实用的分位,因此 maximumFractionDigits: 0 可去除小数。
  • 优雅的回退 —— 如果外汇 API 不可用,显示美元金额而不是 “$undefined”。
  • 缓存汇率 4 小时(与 API 刷新频率相匹配),以避免过多请求。
  • 自适应定价(Stripe 提供的按货币 Prices)会产生约 2 % 的外汇差价,由 Stripe 收取并隐藏访客原始的显示价格。仅显示方式免费、透明且更简单。

可选:货币切换器

如果您希望用户覆盖自动检测:

  1. 将所选货币存储在 cookie 中。
  2. 将该值传递给 localizedPrice(添加可选的 overrideCurrency 参数)。
  3. 同一辅助函数将返回相应的显示金额。

成本与限制

  • ApogeoAPI 免费层:每月 1 000 次请求。
  • 使用 4 小时缓存,这大约相当于每月 5 000 次页面浏览。
  • 在 . 获取密钥。

原始出版物

Stripe Localized Pricing with FX – ApogeoAPI Blog

0 浏览
Back to Blog

相关文章

阅读更多 »

自己制作框架,有什么建议吗?

《Making my own framework》的封面图片。有什么建议吗?https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fde...