Implementacion de formato de moneda con Claude Code
Aprende sobre la implementacion de formato de moneda usando Claude Code. Incluye ejemplos de codigo practicos.
Implementando correctamente el formato de moneda con Claude Code
En sitios de comercio electronico, aplicaciones de contabilidad y servicios internacionales, el formato preciso de moneda es indispensable. Las reglas de punto decimal, separador de miles y simbolo de moneda varian segun el pais y la moneda, por lo que formatear manualmente puede ser fuente de errores. Con Claude Code, puedes construir eficientemente implementaciones robustas usando Intl.NumberFormat o bibliotecas especializadas.
Uso de Intl.NumberFormat
> Crea una utilidad de formato de moneda compatible con multiples monedas.
> Compatible con yen japones, dolar estadounidense y euro.
> Incluye visualizacion por locale, conversion de divisas y validacion de montos.
// src/lib/currency.ts
export type CurrencyCode = 'JPY' | 'USD' | 'EUR' | 'GBP' | 'CNY' | 'KRW';
interface FormatOptions {
currency: CurrencyCode;
locale?: string;
compact?: boolean; // Visualizacion abreviada como "1.2K"
showSign?: boolean; // Mostrar signo +/-
}
/**
* Formatear moneda
*/
export function formatCurrency(
amount: number,
options: FormatOptions
): string {
const { currency, locale = 'es-ES', compact = false, showSign = false } = options;
const formatter = new Intl.NumberFormat(locale, {
style: 'currency',
currency,
notation: compact ? 'compact' : 'standard',
signDisplay: showSign ? 'exceptZero' : 'auto',
// Las monedas decimales usan 2 decimales, JPY/KRW usan 0 (determinacion automatica)
});
return formatter.format(amount);
}
// Ejemplo de uso
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万"
Consideraciones para calculos con moneda
// src/lib/currency-math.ts
/**
* Para evitar errores de punto flotante, calcular con enteros (unidad minima de moneda)
* JPY: 1 yen = 1 | USD: 1 centavo = 1 | EUR: 1 centimo = 1
*/
export class Money {
constructor(
private readonly amountInMinorUnit: number,
private readonly currency: CurrencyCode
) {}
// Decimales de centavo/yen
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(`Las monedas son diferentes: ${this.currency} y ${other.currency}`);
}
}
}
// Ejemplo de uso
const price = Money.fromMajorUnit(19.80, 'USD');
const tax = price.multiply(0.1);
const total = price.add(tax);
console.log(total.format()); // "$21.78"
Conversion de tipo de cambio
// 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 = 'USD'): Promise<ExchangeRates> {
// Reutilizar cache si tiene menos de 1 hora
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,
};
}
Componente de entrada de moneda
// 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('es-ES', {
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>
);
}
La trampa del punto flotante
El problema de que en JavaScript 0.1 + 0.2 === 0.30000000000000004 es bien conocido. En calculos de moneda, la regla es siempre trabajar con enteros de la unidad minima (centavos/yenes) y convertir a decimales solo al momento de mostrar.
Articulos relacionados
Para el formato de fechas, consulta manejo de fecha y hora, y para la internacionalizacion en general, consulta la guia de implementacion de i18n.
La especificacion detallada de Intl.NumberFormat se puede consultar en MDN (developer.mozilla.org/Intl/NumberFormat).
Related Posts
Cómo potenciar tus proyectos personales con Claude Code [Con ejemplos]
Aprende a acelerar drásticamente tus proyectos personales de desarrollo usando Claude Code. Incluye ejemplos reales y un flujo de trabajo práctico desde la idea hasta el despliegue.
Cómo automatizar la refactorización con Claude Code
Aprende a automatizar eficientemente la refactorización de código usando Claude Code. Incluye prompts prácticos y patrones concretos de refactorización para proyectos reales.
Guia completa de configuracion CORS con Claude Code
Aprende sobre la configuracion completa de CORS usando Claude Code. Incluye consejos practicos y ejemplos de codigo.