Formatierte Ausgabe in Teile für das Styling aufteilen

Verwenden Sie formatToParts(), um auf einzelne Komponenten formatierter Ausgaben für benutzerdefiniertes Styling zuzugreifen

Einführung

Die Methode format() bei JavaScript-Formattern gibt vollständige Strings wie "1.234,56 €" oder "15. Januar 2025" zurück. Dies funktioniert gut für einfache Anzeigen, aber Sie können einzelne Teile nicht unterschiedlich stylen. Sie können das Währungssymbol nicht fett machen, den Monatsnamen nicht anders einfärben oder bestimmten Komponenten kein benutzerdefiniertes Markup zuweisen.

JavaScript bietet die Methode formatToParts(), um dieses Problem zu lösen. Anstatt einen einzelnen String zurückzugeben, gibt sie ein Array von Objekten zurück, wobei jedes einen Teil der formatierten Ausgabe repräsentiert. Jeder Teil hat einen Typ wie currency, month oder element und einen Wert, der den tatsächlichen String enthält. Sie können diese Teile dann verarbeiten, um benutzerdefiniertes Styling anzuwenden, komplexe Layouts zu erstellen oder formatierte Inhalte in umfangreiche Benutzeroberflächen zu integrieren.

Die Methode formatToParts() ist bei mehreren Intl-Formattern verfügbar, einschließlich NumberFormat, DateTimeFormat, ListFormat, RelativeTimeFormat und DurationFormat. Dies macht es zu einem konsistenten Muster über alle Internationalisierungs-Formatierungen in JavaScript hinweg.

Warum formatierte Strings nicht einfach gestylt werden können

Wenn Sie einen formatierten String wie "1.234,56 €" erhalten, können Sie nicht einfach erkennen, wo das Währungssymbol endet und die Zahl beginnt. Verschiedene Locales platzieren Symbole an unterschiedlichen Positionen. Einige Locales verwenden unterschiedliche Trennzeichen. Das zuverlässige Parsen dieser Strings erfordert komplexe Logik, die die bereits in der Intl-API implementierten Formatierungsregeln dupliziert.

Betrachten Sie ein Dashboard, das Geldbeträge mit dem Währungssymbol in einer anderen Farbe anzeigt. Mit format() müssten Sie:

  1. Erkennen, welche Zeichen das Währungssymbol sind
  2. Leerzeichen zwischen Symbol und Zahl berücksichtigen
  3. Unterschiedliche Symbolpositionen über Locales hinweg handhaben
  4. Den String sorgfältig parsen, um die Zahl nicht zu beschädigen

Dieser Ansatz ist fragil und fehleranfällig. Jede Änderung an Locale-Formatierungsregeln bricht Ihre Parsing-Logik.

Das gleiche Problem existiert bei Datumsangaben, Listen und anderen formatierten Ausgaben. Sie können formatierte Strings nicht zuverlässig parsen, um Komponenten zu identifizieren, ohne die locale-spezifischen Formatierungsregeln neu zu implementieren.

Die Methode formatToParts() eliminiert dieses Problem, indem sie die Komponenten separat bereitstellt. Sie erhalten strukturierte Daten, die Ihnen unabhängig vom Locale genau sagen, welcher Teil welcher ist.

Wie formatToParts funktioniert

Die Methode formatToParts() funktioniert identisch zu format(), mit Ausnahme ihres Rückgabewerts. Sie erstellen einen Formatter mit denselben Optionen und rufen dann formatToParts() anstelle von format() auf.

Die Methode gibt ein Array von Objekten zurück. Jedes Objekt enthält zwei Properties:

  • type: Identifiziert, was der Teil repräsentiert, wie currency, month oder literal
  • value: Enthält den tatsächlichen String für diesen Teil

Die Teile erscheinen in derselben Reihenfolge, wie sie in der formatierten Ausgabe vorkommen würden. Sie können dies überprüfen, indem Sie alle Values zusammenfügen, was exakt dieselbe Ausgabe wie der Aufruf von format() erzeugt.

Dieses Pattern ist konsistent über alle Formatter hinweg, die formatToParts() unterstützen. Die spezifischen Part-Typen variieren je nach Formatter, aber die Struktur ist immer dieselbe.

Formatierte Zahlen in Teile aufteilen

Der NumberFormat-Formatter bietet formatToParts() zum Aufteilen formatierter Zahlen. Dies funktioniert für einfache Zahlen, Währungen, Prozentsätze und andere numerische Formate.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

const parts = formatter.formatToParts(1234.56);
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "currency", value: "$" },
  { type: "integer", value: "1" },
  { type: "group", value: "," },
  { type: "integer", value: "234" },
  { type: "decimal", value: "." },
  { type: "fraction", value: "56" }
]

Jedes Objekt identifiziert, was der Teil repräsentiert, und liefert seinen Wert. Der Typ currency repräsentiert das Währungssymbol. Der Typ integer repräsentiert Ganzzahlziffern. Der Typ group repräsentiert das Tausendertrennzeichen. Der Typ decimal repräsentiert das Dezimaltrennzeichen. Der Typ fraction repräsentiert Ziffern nach dem Dezimaltrennzeichen.

Sie können überprüfen, ob die Teile mit der formatierten Ausgabe übereinstimmen:

const formatted = parts.map(part => part.value).join("");
console.log(formatted);
// Output: "$1,234.56"

Die verketteten Teile erzeugen exakt dieselbe Ausgabe wie der Aufruf von format().

Styling von Währungssymbolen in formatierten Zahlen

Der primäre Anwendungsfall für formatToParts() ist die Anwendung unterschiedlicher Styles auf verschiedene Komponenten. Sie können das Parts-Array verarbeiten, um bestimmte Typen in HTML-Elemente einzubetten.

Das Währungssymbol fett darstellen:

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

const parts = formatter.formatToParts(1234.56);
const html = parts
  .map(part => {
    if (part.type === "currency") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<strong>$</strong>1,234.56"

Dieser Ansatz funktioniert für jede Markup-Sprache. Sie können HTML, JSX oder jedes andere Format generieren, indem Sie das Parts-Array verarbeiten.

Dezimalteile unterschiedlich stylen:

const formatter = new Intl.NumberFormat("en-US", {
  minimumFractionDigits: 2
});

const parts = formatter.formatToParts(1234.5);
const html = parts
  .map(part => {
    if (part.type === "decimal" || part.type === "fraction") {
      return `<span class="text-gray-500">${part.value}</span>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "1,234<span class="text-gray-500">.50</span>"

Dieses Muster ist üblich bei Preisdarstellungen, bei denen der Dezimalteil kleiner oder heller erscheint.

Aufteilung formatierter Datumsangaben in Teile

Der DateTimeFormat-Formatter bietet formatToParts() zum Aufteilen formatierter Datums- und Zeitangaben.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "month", value: "January" },
  { type: "literal", value: " " },
  { type: "day", value: "15" },
  { type: "literal", value: ", " },
  { type: "year", value: "2025" }
]

Der Typ month repräsentiert den Monatsnamen oder die Monatsnummer. Der Typ day repräsentiert den Tag des Monats. Der Typ year repräsentiert das Jahr. Der Typ literal repräsentiert Leerzeichen, Interpunktion oder anderen vom Formatter eingefügten Text.

Styling von Monatsnamen in formatierten Datumsangaben

Sie können benutzerdefiniertes Styling auf Datumskomponenten anwenden, indem Sie dasselbe Muster wie bei Zahlen verwenden.

Den Monatsnamen fett darstellen:

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
  .map(part => {
    if (part.type === "month") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<strong>January</strong> 15, 2025"

Styling mehrerer Datumskomponenten:

const formatter = new Intl.DateTimeFormat("en-US", {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);

const html = parts
  .map(part => {
    switch (part.type) {
      case "weekday":
        return `<span class="font-bold">${part.value}</span>`;
      case "month":
        return `<span class="text-blue-600">${part.value}</span>`;
      case "year":
        return `<span class="text-gray-500">${part.value}</span>`;
      default:
        return part.value;
    }
  })
  .join("");

console.log(html);
// Output: "<span class="font-bold">Wednesday</span>, <span class="text-blue-600">January</span> 15, <span class="text-gray-500">2025</span>"

Diese granulare Kontrolle ermöglicht präzises Styling für jede Komponente.

Aufteilung formatierter Listen in Teile

Der ListFormat-Formatter bietet formatToParts() zur Aufschlüsselung formatierter Listen.

const formatter = new Intl.ListFormat("en-US", {
  style: "long",
  type: "conjunction"
});

const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
console.log(parts);

Dies gibt ein Array von Objekten aus:

[
  { type: "element", value: "apples" },
  { type: "literal", value: ", " },
  { type: "element", value: "oranges" },
  { type: "literal", value: ", and " },
  { type: "element", value: "bananas" }
]

Der Typ element repräsentiert jedes Element in der Liste. Der Typ literal repräsentiert Trennzeichen und Konjunktionen, die vom Formatter hinzugefügt werden.

Individuelles Styling von Listenelementen

Sie können benutzerdefiniertes Styling auf Listenelemente anwenden, indem Sie dasselbe Muster verwenden.

Listenelemente fett darstellen:

const formatter = new Intl.ListFormat("en-US", {
  style: "long",
  type: "conjunction"
});

const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
const html = parts
  .map(part => {
    if (part.type === "element") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<strong>apples</strong>, <strong>oranges</strong>, and <strong>bananas</strong>"

Styling spezifischer Listenelemente:

const formatter = new Intl.ListFormat("en-US", {
  style: "long",
  type: "conjunction"
});

const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);

let itemIndex = 0;
const html = parts
  .map(part => {
    if (part.type === "element") {
      const currentIndex = itemIndex++;
      if (currentIndex === 0) {
        return `<span class="text-green-600">${part.value}</span>`;
      }
      return part.value;
    }
    return part.value;
  })
  .join("");

console.log(html);
// Output: "<span class="text-green-600">apples</span>, oranges, and bananas"

Dieser Ansatz ermöglicht es Ihnen, bestimmte Elemente hervorzuheben und gleichzeitig die korrekte locale-spezifische Formatierung beizubehalten.

Aufteilung formatierter relativer Zeitangaben in Teile

Der RelativeTimeFormat-Formatter bietet formatToParts() zur Aufschlüsselung relativer Zeitausdrücke.

const formatter = new Intl.RelativeTimeFormat("en-US", {
  numeric: "auto"
});

const parts = formatter.formatToParts(-1, "day");
console.log(parts);

Dies gibt ein Array von Objekten aus:

{/* CODE_PLACEHOLDER_abd978769d38434511f86f02f249689b */

Für numerische relative Zeitangaben:

const formatter = new Intl.RelativeTimeFormat("en-US", {
  numeric: "always"
});

const parts = formatter.formatToParts(-3, "day");
console.log(parts);
// [
//   { type: "integer", value: "3" },
//   { type: "literal", value: " days ago" }
// ]

Der Typ integer repräsentiert den numerischen Wert. Der Typ literal repräsentiert die relative Zeiteinheit und Richtung.

Formatierte Zeitdauern in Teile aufteilen

Der DurationFormat-Formatter bietet formatToParts() zum Aufteilen formatierter Zeitdauern.

const formatter = new Intl.DurationFormat("en-US", {
  style: "long"
});

const parts = formatter.formatToParts({
  hours: 2,
  minutes: 30,
  seconds: 15
});
console.log(parts);

Dies gibt ein Array von Objekten ähnlich dem folgenden aus:

[
  { type: "integer", value: "2" },
  { type: "literal", value: " hours, " },
  { type: "integer", value: "30" },
  { type: "literal", value: " minutes, " },
  { type: "integer", value: "15" },
  { type: "literal", value: " seconds" }
]

Der Typ integer repräsentiert numerische Werte. Der Typ literal repräsentiert Einheitennamen und Trennzeichen.

HTML aus formatierten Teilen erstellen

Sie können eine wiederverwendbare Funktion erstellen, die Teile verarbeitet und Styling-Regeln konsistent anwendet.

function formatWithStyles(parts, styleMap) {
  return parts
    .map(part => {
      const style = styleMap[part.type];
      if (style) {
        return `<span class="${style}">${part.value}</span>`;
      }
      return part.value;
    })
    .join("");
}

const numberFormatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

const parts = numberFormatter.formatToParts(1234.56);
const html = formatWithStyles(parts, {
  currency: "font-bold text-gray-700",
  integer: "text-2xl",
  fraction: "text-sm text-gray-500"
});

console.log(html);
// Output: "<span class="font-bold text-gray-700">$</span><span class="text-2xl">1</span>,<span class="text-2xl">234</span>.<span class="text-sm text-gray-500">56</span>"

Dieses Muster trennt die Styling-Regeln von der Formatierungslogik und erleichtert so die Wartung und Wiederverwendung.

Locale-spezifische Teilreihenfolge verstehen

Das Parts-Array behält automatisch locale-spezifische Formatierungsregeln bei. Verschiedene Locales platzieren Komponenten in unterschiedlichen Reihenfolgen und verwenden unterschiedliche Formate, aber formatToParts() behandelt diese Unterschiede.

const usdFormatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

console.log(usdFormatter.formatToParts(1234.56));
// [
//   { type: "currency", value: "$" },
//   { type: "integer", value: "1" },
//   { type: "group", value: "," },
//   { type: "integer", value: "234" },
//   { type: "decimal", value: "." },
//   { type: "fraction", value: "56" }
// ]

const eurFormatter = new Intl.NumberFormat("de-DE", {
  style: "currency",
  currency: "EUR"
});

console.log(eurFormatter.formatToParts(1234.56));
// [
//   { type: "integer", value: "1" },
//   { type: "group", value: "." },
//   { type: "integer", value: "234" },
//   { type: "decimal", value: "," },
//   { type: "fraction", value: "56" },
//   { type: "literal", value: " " },
//   { type: "currency", value: "€" }
// ]

Die deutsche Formatierung platziert die Währung nach der Zahl mit einem Leerzeichen. Das Gruppentrennzeichen ist ein Punkt, und das Dezimaltrennzeichen ist ein Komma. Ihr Styling-Code verarbeitet das Parts-Array unabhängig vom Locale auf die gleiche Weise, und die Formatierung passt sich automatisch an.

Barrierefreie formatierte Anzeigen erstellen

Sie können formatToParts() verwenden, um Barrierefreiheitsattribute zu formatierter Ausgabe hinzuzufügen. Dies hilft Screenreadern, Werte korrekt anzukündigen.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

function formatAccessible(number) {
  const parts = formatter.formatToParts(number);
  const formatted = parts.map(part => part.value).join("");

  return `<span aria-label="${number} US dollars">${formatted}</span>`;
}

console.log(formatAccessible(1234.56));
// Output: "<span aria-label="1234.56 US dollars">$1,234.56</span>"

Dies stellt sicher, dass Screenreader sowohl den formatierten Anzeigewert als auch den zugrunde liegenden numerischen Wert mit entsprechendem Kontext ankündigen.

formatToParts mit Framework-Komponenten kombinieren

Moderne Frameworks wie React können formatToParts() verwenden, um Komponenten effizient zu erstellen.

function CurrencyDisplay({ value, locale, currency }) {
  const formatter = new Intl.NumberFormat(locale, {
    style: "currency",
    currency: currency
  });

  const parts = formatter.formatToParts(value);

  return (
    <span className="currency-display">
      {parts.map((part, index) => {
        if (part.type === "currency") {
          return <strong key={index}>{part.value}</strong>;
        }
        if (part.type === "fraction" || part.type === "decimal") {
          return <span key={index} className="text-sm text-gray-500">{part.value}</span>;
        }
        return <span key={index}>{part.value}</span>;
      })}
    </span>
  );
}

Diese Komponente wendet unterschiedliche Stile auf verschiedene Teile an und behält dabei die korrekte Formatierung für jede Sprache und Währung bei.

Wann formatToParts verwendet werden sollte

Verwenden Sie format(), wenn Sie eine einfache formatierte Zeichenkette ohne Anpassungen benötigen. Dies ist der häufigste Fall für die meisten Anzeigeszenarien.

Verwenden Sie formatToParts(), wenn Sie Folgendes benötigen:

  • Unterschiedliche Stile auf verschiedene Teile der formatierten Ausgabe anwenden
  • HTML oder JSX mit formatiertem Inhalt erstellen
  • Attribute oder Metadaten zu bestimmten Komponenten hinzufügen
  • Formatierte Ausgabe in komplexe Layouts integrieren
  • Formatierte Ausgabe programmatisch verarbeiten
  • Benutzerdefinierte visuelle Designs erstellen, die granulare Kontrolle erfordern

Die Methode formatToParts() hat etwas mehr Overhead als format(), da sie ein Array von Objekten anstelle einer einzelnen Zeichenkette erstellt. Dieser Unterschied ist für typische Anwendungen vernachlässigbar, aber wenn Sie Tausende von Werten pro Sekunde formatieren, bietet format() eine bessere Performance.

Für die meisten Anwendungen sollten Sie basierend auf Ihren Styling-Anforderungen und nicht auf Performance-Überlegungen wählen. Wenn Sie die Ausgabe nicht anpassen müssen, verwenden Sie format(). Wenn Sie benutzerdefiniertes Styling oder Markup benötigen, verwenden Sie formatToParts().

Häufige Part-Typen über Formatter hinweg

Verschiedene Formatter erzeugen unterschiedliche Part-Typen, aber einige Typen erscheinen über mehrere Formatter hinweg:

  • literal: Leerzeichen, Interpunktion oder anderer durch die Formatierung hinzugefügter Text. Erscheint in Datumsangaben, Zahlen, Listen und Zeitdauern.
  • integer: Ganzzahlige Ziffern. Erscheint in Zahlen, relativen Zeitangaben und Zeitdauern.
  • decimal: Dezimaltrennzeichen. Erscheint in Zahlen.
  • fraction: Dezimalziffern. Erscheint in Zahlen.

Formatierer-spezifische Typen umfassen:

  • Zahlen: currency, group, percentSign, minusSign, plusSign, unit, compact, exponentInteger
  • Daten: weekday, era, year, month, day, hour, minute, second, dayPeriod, timeZoneName
  • Listen: element
  • Relative Zeitangaben: Numerische Werte erscheinen als integer, Text erscheint als literal

Das Verständnis dieser Typen hilft Ihnen, Styling-Code zu schreiben, der jede Formatierer-Ausgabe korrekt verarbeitet.