Währungsbeträge in React Router v7 formatieren

Preise mit Währungssymbolen und Trennzeichen anzeigen

Problem

Die Anzeige von Preisen in Webanwendungen erfordert die Handhabung zweier miteinander verbundener Lokalisierungsaspekte: die verwendete Währung und die regionalen Konventionen zur Darstellung von Geldbeträgen. Ein Preis von 1200,50 US-Dollar erscheint für Nutzer in den Vereinigten Staaten als "$1,200.50", in Frankreich jedoch als "1 200,50 $US". Die Position des Währungssymbols, das Dezimaltrennzeichen, die Tausendergruppierung und die Abstände variieren je nach Gebietsschema. Wenn diese Konventionen nicht beachtet werden, können Nutzer Beträge falsch interpretieren oder anzweifeln, ob der Preis korrekt ist, was das Vertrauen in die Anwendung untergräbt.

Die Herausforderung wird noch größer, wenn eine Anwendung mehrere Regionen bedient oder Nutzern ermöglicht, Preise in verschiedenen Währungen anzuzeigen. Das Hartcodieren von Formatstrings oder das manuelle Platzieren von Symbolen erzeugt fragilen Code, der bricht, wenn neue Gebietsschemata oder Währungen hinzugefügt werden. Ohne einen systematischen Ansatz wird die Aufrechterhaltung konsistenter und korrekter Preisanzeigen in einer Anwendung fehleranfällig.

Lösung

Formatieren Sie Währungswerte unter Verwendung sowohl des Zielwährungscodes als auch des aktiven Gebietsschemas des Nutzers. Dieser Ansatz delegiert die komplexen Regeln der Währungsdarstellung an die Internationalisierungs-APIs des Browsers, die bereits die Formatierungskonventionen für Hunderte von Gebietsschema-Währungs-Kombinationen kodieren.

Durch Übergabe eines numerischen Betrags, eines Währungscodes und des aktuellen Gebietsschemas an eine Formatierungsfunktion wendet das System automatisch das korrekte Symbol, die Trennzeichen und das Layout an. Dies stellt sicher, dass Preise immer in einem für den Nutzer vertrauten Format erscheinen, unabhängig davon, welche Währung angezeigt wird oder in welcher Region sich der Nutzer befindet.

Schritte

1. Wiederverwendbare Komponente zur Währungsformatierung erstellen

Erstellen Sie eine Komponente, die FormattedNumber von react-intl mit den Props style und currency verwendet, um Geldbeträge zu formatieren.

import { FormattedNumber } from "react-intl";

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

export function Price({ amount, currency }: PriceProps) {
  return (
    <FormattedNumber value={amount} style="currency" currency={currency} />
  );
}

Die Komponente FormattedNumber verwendet die API formatNumber und akzeptiert Intl.NumberFormatOptions. Die Option style="currency" weist den Formatter an, Währungssymbole einzuschließen, und die Prop currency gibt an, welche Währung angezeigt werden soll.

2. Verwenden Sie die Price-Komponente in Route-Komponenten

Rendern Sie Preise in jeder React Router Route-Komponente, indem Sie den numerischen Wert und den Währungscode übergeben.

import { Price } from "~/components/Price";

export default function ProductPage() {
  const product = {
    name: "Wireless Headphones",
    price: 129.99,
    currency: "USD",
  };

  return (
    <div>
      <h1>{product.name}</h1>
      <p>
        <Price amount={product.price} currency={product.currency} />
      </p>
    </div>
  );
}

Die Price-Komponente formatiert den Betrag automatisch entsprechend der im IntlProvider konfigurierten Locale. Für eine US-Locale wird dies als "$129.99" gerendert; für eine deutsche Locale mit derselben USD-Währung wird es als "129,99 $" gerendert.

3. Formatieren Sie Währungen imperativ, wenn erforderlich

Für Szenarien, in denen Sie den formatierten String direkt benötigen, verwenden Sie den Hook useIntl, um auf die Methode formatNumber zuzugreifen.

import { useIntl } from "react-intl";

export default function CheckoutSummary() {
  const intl = useIntl();
  const subtotal = 89.99;
  const tax = 7.2;
  const total = subtotal + tax;

  const formattedTotal = intl.formatNumber(total, {
    style: "currency",
    currency: "EUR",
  });

  return (
    <div>
      <h2>Order Summary</h2>
      <dl>
        <dt>Subtotal</dt>
        <dd>
          {intl.formatNumber(subtotal, {
            style: "currency",
            currency: "EUR",
          })}
        </dd>
        <dt>Tax</dt>
        <dd>
          {intl.formatNumber(tax, {
            style: "currency",
            currency: "EUR",
          })}
        </dd>
        <dt>Total</dt>
        <dd aria-label={`Total: ${formattedTotal}`}>
          <strong>{formattedTotal}</strong>
        </dd>
      </dl>
    </div>
  );
}

Die Methode formatNumber akzeptiert einen Wert und ein Options-Objekt mit FormatNumberOptions. Dies ist nützlich, wenn Sie den formatierten String für Attribute, Logging oder Nicht-JSX-Kontexte benötigen.

4. Steuern Sie die Dezimalpräzision für ganzzahlige Währungen

Einige Währungen verwenden keine Brucheinheiten. Passen Sie die Anzahl der Dezimalstellen an die Währungskonventionen an.

import { FormattedNumber } from "react-intl";

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

export function Price({ amount, currency }: PriceProps) {
  const isWholeNumberCurrency = currency === "JPY" || currency === "KRW";

  return (
    <FormattedNumber
      value={amount}
      style="currency"
      currency={currency}
      minimumFractionDigits={isWholeNumberCurrency ? 0 : 2}
      maximumFractionDigits={isWholeNumberCurrency ? 0 : 2}
    />
  );
}

Der japanische Yen verwendet keine Untereinheit, daher werden Beträge ohne Dezimalstellen angezeigt. Die Optionen minimumFractionDigits und maximumFractionDigits überschreiben bei Bedarf das standardmäßige Dezimalverhalten.