Cómo formatear números para diferentes locales en React Router v7
Mostrar números con separadores específicos según el locale
Problema
Los números se escriben de manera diferente en todo el mundo. Lo que aparece como 10,000.5 en Estados Unidos se convierte en 10.000,5 en Alemania—las comas y los puntos intercambian roles por completo. Esto no es una cuestión de preferencia o estilo, sino de legibilidad. Un usuario alemán que ve 10,000.5 podría leerlo como diez, ignorando los separadores de agrupación. Un usuario estadounidense que ve 10.000,5 podría leerlo como diez mil, ignorando el separador decimal.
Los mismos dígitos pueden transmitir significados opuestos dependiendo de las convenciones regionales del lector. Cuando las aplicaciones muestran valores numéricos sin formato adaptado a la configuración regional, corren el riesgo de confundir a los usuarios y socavar la confianza en los datos presentados.
Solución
Formatear los números según la configuración regional del usuario, utilizando reglas regionales para los separadores decimales y de agrupación. Esto convierte los valores numéricos en cadenas que siguen las reglas de formato familiares para los usuarios en su región.
React-intl proporciona métodos de formateo que aprovechan la API Intl.NumberFormat integrada en el navegador, que maneja la complejidad de las convenciones numéricas regionales. Al pasar valores numéricos a través de estos formateadores, la aplicación produce resultados que coinciden con las expectativas del usuario sin necesidad de lógica manual para los separadores.
Pasos
1. Crear un componente que formatee números con useIntl
El hook useIntl proporciona acceso a métodos de formateo, incluyendo formatNumber, que acepta un valor numérico y devuelve una cadena formateada según la configuración regional.
import { useIntl } from "react-intl";
export default function ProductPrice() {
const intl = useIntl();
const price = 1234.56;
return (
<div>
<p>Price: {intl.formatNumber(price)}</p>
</div>
);
}
El método formatNumber aplica automáticamente los separadores correctos para la configuración regional actual. Un usuario con configuración regional en-US ve "1,234.56" mientras que un usuario con configuración regional de-DE ve "1.234,56".
2. Formatear valores de moneda con opciones de estilo
El método formatNumber acepta opciones que se ajustan a Intl.NumberFormatOptions, incluyendo el formato de moneda.
import { useIntl } from "react-intl";
export default function ProductPrice() {
const intl = useIntl();
const price = 1234.56;
return (
<div>
<p>
{intl.formatNumber(price, {
style: "currency",
currency: "USD",
})}
</p>
</div>
);
}
Esto produce "$1,234.56" para en-US y "1.234,56 $" para de-DE, aplicando tanto las convenciones de separadores como de símbolos de moneda.
3. Usar FormattedNumber para formateo declarativo
El componente FormattedNumber proporciona una alternativa declarativa que acepta las mismas opciones como props.
import { FormattedNumber } from "react-intl";
export default function Statistics() {
const totalUsers = 1500000;
const growthRate = 0.23;
return (
<div>
<p>
Total de usuarios: <FormattedNumber value={totalUsers} />
</p>
<p>
Tasa de crecimiento: <FormattedNumber value={growthRate} style="percent" />
</p>
</div>
);
}
El componente renderiza el número formateado directamente en el DOM. Para en-US, esto muestra "1,500,000" y "23%". Para de-DE, muestra "1.500.000" y "23 %".
4. Formatear números desde datos del cargador
En React Router 7, los componentes de ruta acceden a los datos del cargador mediante el hook useLoaderData. Combina esto con el formateo de números para mostrar valores proporcionados por el servidor.
import { useLoaderData } from "react-router";
import { FormattedNumber } from "react-intl";
export async function loader() {
return {
revenue: 45678.9,
units: 12500,
};
}
export default function Dashboard() {
const { revenue, units } = useLoaderData<typeof loader>();
return (
<div>
<h1>Dashboard</h1>
<p>
Ingresos:{" "}
<FormattedNumber value={revenue} style="currency" currency="USD" />
</p>
<p>
Unidades vendidas: <FormattedNumber value={units} />
</p>
</div>
);
}
El cargador proporciona datos numéricos sin procesar, y el componente los formatea según la configuración regional del usuario. Esta separación mantiene la obtención de datos independiente de las cuestiones de presentación.