Zahlen für verschiedene Locales in Next.js (Pages Router) v16 formatieren
Zahlen mit locale-spezifischen Trennzeichen anzeigen
Problem
Zahlen werden weltweit unterschiedlich geschrieben. Was in den Vereinigten Staaten als 10,000.5 erscheint, wird in Deutschland zu 10.000,5 – Kommas und Punkte tauschen ihre Rollen vollständig. Dies ist keine Frage der Präferenz oder des Stils, sondern der Lesbarkeit. Ein deutscher User, der 10,000.5 sieht, könnte es als zehn lesen und die Gruppierungstrennzeichen ignorieren. Ein amerikanischer User, der 10.000,5 sieht, könnte es als zehntausend lesen und das Dezimaltrennzeichen ignorieren. Dieselben Ziffern, gegenteilige Bedeutungen.
Wenn Anwendungen Zahlen ohne locale-bewusste Formatierung anzeigen, riskieren sie, User zu verwirren oder falsche Informationen zu vermitteln. Währungsbeträge, Prozentsätze, Messungen und Statistiken hängen alle von regionalen Konventionen ab, die User seit ihrer Kindheit gelernt haben.
Lösung
Formatieren Sie Zahlen basierend auf dem Locale des Users unter Verwendung regionaler Regeln für Dezimal- und Gruppierungstrennzeichen. Dies wandelt numerische Werte in Strings um, die den Formatierungsregeln folgen, die Usern in ihrer Region vertraut sind.
react-intl bietet zwei Ansätze: die <FormattedNumber>-Komponente für deklarative Formatierung in JSX und die formatNumber-Methode aus dem useIntl-Hook für imperative Formatierung. Beide basieren auf der Intl.NumberFormat-API des Browsers und wenden automatisch das in Ihrem IntlProvider konfigurierte Locale an. Die formatierte Ausgabe respektiert regionale Konventionen für Tausendertrennzeichen, Dezimalpunkte und Zifferngruppierung.
Schritte
1. Erstellen Sie eine Komponente, die Zahlen deklarativ formatiert
Die <FormattedNumber>-Komponente verwendet die formatNumber- und Intl.NumberFormat-APIs und akzeptiert ein value-Prop zusammen mit Optionen, die Intl.NumberFormatOptions entsprechen.
import { FormattedNumber } from "react-intl";
export default function ProductPrice({ price }: { price: number }) {
return (
<div>
<FormattedNumber value={price} />
</div>
);
}
Standardmäßig rendert <FormattedNumber> die formatierte Zahl in ein React.Fragment. Die Komponente liest das Gebietsschema vom nächstgelegenen IntlProvider und wendet die entsprechenden Formatierungsregeln an.
2. Zahlen mit spezifischen Optionen formatieren
Übergeben Sie Formatierungsoptionen, um zu steuern, wie Zahlen angezeigt werden. Häufige Optionen sind minimumFractionDigits, maximumFractionDigits und 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>
);
}
Diese Props entsprechen Intl.NumberFormatOptions und geben Ihnen Kontrolle über Präzision und Darstellung, während gebietsschemaspezifische Trennzeichen beibehalten werden.
3. Zahlen imperativ mit dem useIntl-Hook formatieren
Wenn eine Komponente als Funktionskomponente ausgedrückt werden kann, bietet der useIntl-Hook Zugriff auf das intl-Objekt, das eine formatNumber-Methode enthält.
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>
);
}
Die formatNumber-Funktion gibt einen formatierten Zahlenstring zurück und akzeptiert einen Wert, der als Zahl geparst werden kann, sowie Optionen, die NumberFormatOptions entsprechen.
4. Zahlen in Nicht-JSX-Kontexten formatieren
Verwenden Sie formatNumber, wenn Sie formatierte Zahlen in Attributen, Variablen oder anderen Kontexten benötigen, in denen Komponenten nicht verwendet werden können.
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>
);
}
Die imperative API ist unerlässlich für das Setzen von Textattributen wie title, aria-label oder alt, wo React-Komponenten nicht gerendert werden können.