Cómo formatear números para diferentes configuraciones regionales en React Router v7

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 pueden transmitir significados opuestos dependiendo de las convenciones regionales del lector. Cuando las aplicaciones muestran valores numéricos sin formato según la configuración regional, corren el riesgo de confundir a los usuarios y socavar la confianza en los datos presentados.

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 métodos de formato que aprovechan la API Intl.NumberFormat integrada del 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 lógica manual de separadores.

Pasos

1. Crea un componente que formatee números con useIntl

El hook useIntl proporciona acceso a métodos de formato, incluido 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. Formatea valores de moneda con opciones de estilo

El método formatNumber acepta opciones que cumplen con Intl.NumberFormatOptions, incluyendo 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. Usa FormattedNumber para formato 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 users: <FormattedNumber value={totalUsers} />
      </p>
      <p>
        Growth rate: <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. Formatea números desde datos del loader

En React Router 7, los componentes de ruta acceden a los datos del loader mediante el hook useLoaderData. Combina esto con el formato 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>
        Revenue:{" "}
        <FormattedNumber value={revenue} style="currency" currency="USD" />
      </p>
      <p>
        Units sold: <FormattedNumber value={units} />
      </p>
    </div>
  );
}

El loader 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 preocupaciones de presentación.