实现Currency Formatting:Claude Code 实战指南
了解implementing currency formatting:Claude Code 实战. 包含实用代码示例。
通貨フォーマットを通过 Claude Code正确地实现する
ECサイト、会計应用、国際支持サービスでは、通貨の正確なフォーマットが不可或缺。小数点、桁区切り、通貨記号のルールは国・通貨ごとに異なるため、自前でフォーマットすると不具合の温床になります。借助 Claude Code,Intl.NumberFormatや専用库を活用した堅牢な实现を高效地构建可以。
Intl.NumberFormatの活用
> 多通貨支持の通貨フォーマットユーティリティを作って。
> 日本円、USドル、ユーロに支持して。
> ロケール別显示、為替変換、金額の验证も含めて。
// src/lib/currency.ts
export type CurrencyCode = 'JPY' | 'USD' | 'EUR' | 'GBP' | 'CNY' | 'KRW';
interface FormatOptions {
currency: CurrencyCode;
locale?: string;
compact?: boolean; // "1.2万" 这样的短縮显示
showSign?: boolean; // +/- 符号を显示
}
/**
* 通貨をフォーマットする
*/
export function formatCurrency(
amount: number,
options: FormatOptions
): string {
const { currency, locale = 'en-US', compact = false, showSign = false } = options;
const formatter = new Intl.NumberFormat(locale, {
style: 'currency',
currency,
notation: compact ? 'compact' : 'standard',
signDisplay: showSign ? 'exceptZero' : 'auto',
// 小数通貨は小数点2桁、JPY/KRWは0桁(自動判定)
});
return formatter.format(amount);
}
// Usage example
formatCurrency(1234567, { currency: 'JPY' }); // "¥1,234,567"
formatCurrency(1234.56, { currency: 'USD' }); // "$1,234.56"
formatCurrency(1234.56, { currency: 'EUR', locale: 'de-DE' }); // "1.234,56 €"
formatCurrency(1234567, { currency: 'JPY', compact: true }); // "¥123万"
通貨計算の注意点
// src/lib/currency-math.ts
/**
* 浮動小数点の誤差を避けるため、整数(最小通貨単位)で計算する
* JPY: 1円 = 1 | USD: 1セント = 1 | EUR: 1セント = 1
*/
export class Money {
constructor(
private readonly amountInMinorUnit: number,
private readonly currency: CurrencyCode
) {}
// セント/円の小数桁数
private static decimals(currency: CurrencyCode): number {
return ['JPY', 'KRW'].includes(currency) ? 0 : 2;
}
static fromMajorUnit(amount: number, currency: CurrencyCode): Money {
const decimals = Money.decimals(currency);
const minor = Math.round(amount * Math.pow(10, decimals));
return new Money(minor, currency);
}
toMajorUnit(): number {
const decimals = Money.decimals(this.currency);
return this.amountInMinorUnit / Math.pow(10, decimals);
}
add(other: Money): Money {
this.assertSameCurrency(other);
return new Money(this.amountInMinorUnit + other.amountInMinorUnit, this.currency);
}
subtract(other: Money): Money {
this.assertSameCurrency(other);
return new Money(this.amountInMinorUnit - other.amountInMinorUnit, this.currency);
}
multiply(factor: number): Money {
return new Money(Math.round(this.amountInMinorUnit * factor), this.currency);
}
format(locale?: string): string {
return formatCurrency(this.toMajorUnit(), { currency: this.currency, locale });
}
private assertSameCurrency(other: Money) {
if (this.currency !== other.currency) {
throw new Error(`通貨が異なります: ${this.currency} と ${other.currency}`);
}
}
}
// Usage example
const price = Money.fromMajorUnit(1980, 'JPY');
const tax = price.multiply(0.1);
const total = price.add(tax);
console.log(total.format()); // "¥2,178"
為替レート変換
// src/lib/exchange.ts
interface ExchangeRates {
base: CurrencyCode;
rates: Record<CurrencyCode, number>;
updatedAt: string;
}
let cachedRates: ExchangeRates | null = null;
export async function getExchangeRates(base: CurrencyCode = 'JPY'): Promise<ExchangeRates> {
// 缓存が1时间以内なら再利用
if (cachedRates && Date.now() - new Date(cachedRates.updatedAt).getTime() < 3600000) {
return cachedRates;
}
const res = await fetch(`https://api.exchangerate-api.com/v4/latest/${base}`);
const data = await res.json();
cachedRates = {
base,
rates: data.rates,
updatedAt: new Date().toISOString(),
};
return cachedRates;
}
export async function convertCurrency(
amount: number,
from: CurrencyCode,
to: CurrencyCode
): Promise<{ converted: number; rate: number }> {
const rates = await getExchangeRates(from);
const rate = rates.rates[to];
return {
converted: Math.round(amount * rate * 100) / 100,
rate,
};
}
通貨输入组件
// src/components/CurrencyInput.tsx
'use client';
import { useState } from 'react';
interface Props {
value: number;
currency: CurrencyCode;
onChange: (value: number) => void;
}
export function CurrencyInput({ value, currency, onChange }: Props) {
const [displayValue, setDisplayValue] = useState(value.toLocaleString());
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const raw = e.target.value.replace(/[^0-9.-]/g, '');
setDisplayValue(e.target.value);
const num = parseFloat(raw);
if (!isNaN(num)) onChange(num);
};
const handleBlur = () => {
setDisplayValue(value.toLocaleString());
};
const symbol = new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
currencyDisplay: 'narrowSymbol',
}).formatToParts(0).find((p) => p.type === 'currency')?.value || '';
return (
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">{symbol}</span>
<input
type="text"
value={displayValue}
onChange={handleChange}
onBlur={handleBlur}
className="w-full border rounded-lg pl-8 pr-4 py-2 text-right"
inputMode="decimal"
/>
</div>
);
}
浮動小数点の落とし穴
JavaScriptで0.1 + 0.2 === 0.30000000000000004となる問題は有名です。通貨計算では必ず最小単位(セント/円)の整数で扱い、显示時にのみ小数に変換するのが鉄則です。
関連文章
日期のフォーマットは日期・时间の扱い、国際化全般はi18n实现指南。
Intl.NumberFormatの详情仕様はMDN(developer.mozilla.org/Intl/NumberFormat)中可以查看。
#Claude Code
#currency
#フォーマット
#Intl
#internationalization
Related Posts
Use Cases
Use Cases
用 Claude Code 加速个人项目开发【附实战案例】
详解如何用 Claude Code 大幅提升个人项目的开发速度。包含从创意到上线的完整实战案例和工作流。
Use Cases
Use Cases
如何用 Claude Code 自动化代码重构
详解如何利用 Claude Code 高效完成代码重构自动化。包含实用提示词和真实项目中的重构模式。
Use Cases
Use Cases
Complete CORS Configuration Guide:Claude Code 实战指南
了解complete cors configuration guide:Claude Code 实战. 包含实用技巧和代码示例。