Cómo formatear números para diferentes configuraciones regionales en Next.js (Pages Router) v16
Muestra números con separadores específicos de la configuración regional
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 completamente sus roles. Esto no es una cuestión de preferencia o estilo, sino de legibilidad. Un usuario alemán que vea 10,000.5 podría leerlo como diez, ignorando los separadores de agrupación. Un usuario estadounidense que vea 10.000,5 podría leerlo como diez mil, ignorando el separador decimal. Los mismos dígitos, significados opuestos.
Cuando las aplicaciones muestran números sin formato adaptado a la configuración regional, corren el riesgo de confundir a los usuarios o transmitir información incorrecta. Los importes monetarios, porcentajes, medidas y estadísticas dependen de convenciones regionales que los usuarios han aprendido desde la infancia.
Solución
Formatea 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 de su región.
react-intl proporciona dos enfoques: el componente <FormattedNumber> para formato declarativo en JSX, y el método formatNumber del hook useIntl para formato imperativo. Ambos se basan en la API Intl.NumberFormat del navegador y aplican automáticamente la configuración regional configurada en tu IntlProvider. La salida formateada respeta las convenciones regionales para separadores de miles, puntos decimales y agrupación de dígitos.
Pasos
1. Crea un componente que formatee números de forma declarativa
El componente <FormattedNumber> utiliza las API formatNumber y Intl.NumberFormat y acepta una prop value junto con opciones que corresponden a Intl.NumberFormatOptions.
import { FormattedNumber } from "react-intl";
export default function ProductPrice({ price }: { price: number }) {
return (
<div>
<FormattedNumber value={price} />
</div>
);
}
Por defecto, <FormattedNumber> renderiza el número formateado en un React.Fragment. El componente lee la configuración regional del IntlProvider más cercano y aplica las reglas de formato apropiadas.
2. Formatear números con opciones específicas
Pasa opciones de formato para controlar cómo aparecen los números. Las opciones comunes incluyen minimumFractionDigits, maximumFractionDigits y style.
import { FormattedNumber } from "react-intl";
export default function Statistics({ value }: { value: number }) {
return (
<dl>
<dt>Total Users</dt>
<dd>
<FormattedNumber
value={value}
minimumFractionDigits={0}
maximumFractionDigits={0}
/>
</dd>
<dt>Conversion Rate</dt>
<dd>
<FormattedNumber
value={value / 100}
style="percent"
minimumFractionDigits={2}
/>
</dd>
</dl>
);
}
Estas props corresponden a Intl.NumberFormatOptions, dándote control sobre la precisión y presentación mientras mantienes los separadores específicos de la configuración regional.
3. Formatear números imperativamente con el hook useIntl
Cuando un componente puede expresarse como un componente de función, el hook useIntl proporciona acceso al objeto intl, que incluye un método formatNumber.
import { useIntl } from "react-intl";
export default function DataTable({ rows }: { rows: number[] }) {
const intl = useIntl();
return (
<table>
<tbody>
{rows.map((value, index) => (
<tr key={index}>
<td>{intl.formatNumber(value)}</td>
</tr>
))}
</tbody>
</table>
);
}
La función formatNumber devuelve una cadena de número formateado y acepta un valor que puede ser analizado como un número, junto con opciones que se ajustan a NumberFormatOptions.
4. Formatear números en contextos no JSX
Usa formatNumber cuando necesites números formateados en atributos, variables u otros contextos donde no se pueden usar componentes.
import { useIntl } from "react-intl";
export default function Chart({ dataPoints }: { dataPoints: number[] }) {
const intl = useIntl();
const formattedLabel = intl.formatNumber(dataPoints[0], {
notation: "compact",
maximumFractionDigits: 1,
});
return (
<div>
<img
src="/chart.png"
alt={`Chart showing ${formattedLabel} items`}
title={formattedLabel}
/>
</div>
);
}
La API imperativa es esencial para establecer atributos de texto como title, aria-label o alt, donde los componentes de React no pueden ser renderizados.