Comment formater les montants de devise dans TanStack Start v1

Afficher les prix avec les symboles monétaires et les séparateurs

Problème

Les prix combinent deux défis de localisation : la représentation de la devise et le formatage des nombres. La même valeur monétaire apparaît comme $1,200.50 aux États-Unis et 1 200,50 € en Allemagne. Le symbole de devise se déplace, les séparateurs décimaux et de regroupement s'inversent, et même l'espacement change.

Ces conventions ne sont pas des préférences mais des attentes. Afficher des prix dans un format non familier fait douter les utilisateurs de l'exactitude du montant affiché. Un prix présenté comme "1200.50 EUR" à un utilisateur allemand ou "1.200,50$" à un utilisateur américain crée des frictions et érode la confiance.

Solution

Formatez les valeurs monétaires en fonction à la fois de la devise et de la locale de l'utilisateur. Cela combine le placement du symbole monétaire avec les règles de formatage spécifiques à la locale, créant des prix qui correspondent aux attentes régionales concernant l'apparence de l'argent.

Utilisez la méthode formatNumber de react-intl avec l'option style: 'currency' pour appliquer à la fois le code de devise et les conventions de formatage de la locale de l'utilisateur. L'API Intl.NumberFormat du navigateur gère automatiquement le placement des symboles, le choix des séparateurs et l'espacement.

Étapes

1. Créer un composant de formatage de devise

Construisez un composant réutilisable qui accepte une valeur numérique et un code de devise, puis formate le prix en utilisant la locale de l'utilisateur.

import { useIntl } from "react-intl";

interface PriceProps {
  value: number;
  currency: string;
}

export function Price({ value, currency }: PriceProps) {
  const intl = useIntl();

  const formattedPrice = intl.formatNumber(value, {
    style: "currency",
    currency: currency,
  });

  return <span>{formattedPrice}</span>;
}

Le hook useIntl fournit un accès à l'API de formatage. La méthode formatNumber avec style: 'currency' applique à la fois le symbole de devise et le formatage des nombres spécifique à la locale.

2. Utiliser le composant avec différentes devises

Affichez les prix dans votre application en transmettant le montant numérique et le code de devise.

export default function ProductCard() {
  return (
    <div>
      <h2>Premium Plan</h2>
      <Price value={1200.5} currency="USD" />
    </div>
  );
}

Le composant formate automatiquement le prix selon la locale de l'utilisateur. Un utilisateur américain voit "$1,200.50" tandis qu'un utilisateur allemand voit "1.200,50 $".

3. Formater les prix avec une précision décimale personnalisée

Contrôlez le nombre de décimales affichées en ajoutant les options minimumFractionDigits et maximumFractionDigits.

export function PriceWithPrecision({ value, currency }: PriceProps) {
  const intl = useIntl();

  const formattedPrice = intl.formatNumber(value, {
    style: "currency",
    currency: currency,
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });

  return <span>{formattedPrice}</span>;
}

Cela assure un affichage décimal cohérent pour tous les prix, même lorsque la valeur est un nombre entier comme 100.

4. Créer un helper pour le formatage en ligne

Pour les cas où un composant wrapper n'est pas nécessaire, créez une fonction helper de formatage.

import { useIntl } from "react-intl";

export function useFormatCurrency() {
  const intl = useIntl();

  return (value: number, currency: string) => {
    return intl.formatNumber(value, {
      style: "currency",
      currency: currency,
    });
  };
}

Utilisez ce hook lorsque vous avez besoin de prix formatés dans des attributs, des valeurs calculées ou d'autres contextes non-JSX.

export function CheckoutSummary({ total }: { total: number }) {
  const formatCurrency = useFormatCurrency();

  return (
    <button aria-label={`Pay ${formatCurrency(total, "USD")}`}>Checkout</button>
  );
}

Le helper renvoie une simple chaîne de caractères adaptée à tout contexte où les composants JSX ne peuvent pas être utilisés.