JavaScript/Objekte/Intl

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Das Intl-Objekt ist ein vordefiniertes Objekt der JavaScript-Laufzeitumgebung, in dem sich Konstruktorfunktionen für Objekte finden, die bei der Verarbeitung von Texten und Zahlen aus unterschiedlichen Sprachen oder Kulturen helfen. Diese Objekte sind kein Teil der JavaScript-Spezifikation (ECMA-262), sondern eigenständig als das ECMAScript® Internationalization API (ECMA-402) standardisiert.

Details zu den jeweiligen Helfern findest du, wenn du den Links in der Liste der Konstruktorfunktionen folgst. In diesem Artikel sollen einige einführende Informationen und Beispiele folgen.

Locales

Zentraler Punkt all dieser Objekte ist das Locale. Das Locale beschreibt die konkreten kulturellen Regeln, die von den Helferobjekten angewendet werden sollen, und sein Aufbau ist ein Teil des Unicode-Regelwerks. Im einfachsten Fall wird ein Locale durch ein Sprachkürzel wie "de-DE" oder "en-US" identifiziert. Das ist allerdings nur die Spitze des Eisbergs, ein solches Kürzel kann noch um Angaben wie Schrift (z.B. in China relevant) oder Sprachvarianten ergänzt werden, bei denen es aber fraglich ist, ob dein Browser sie überhaupt kennt.

Die Regionenangabe in einem Locale bestimmt auch kulturelle Aspekte wie Namen für Monate („Jänner“ in de-AT), 12- oder 24-stündige Uhrzeit. Um die verfügbaren Informationen zu einem Locale zu erhalten, kannst du ein Intl.Locale-Objekt zu einem Sprachkürzel erzeugen und dessen Eigenschaften inspizieren. Mit Hilfe der Intl.Locale()-Konstruktorfunktion kannst du auch spezielle Locales erzeugen, bei denen die einzelnen Locale-Eigenschaften individuell festgelegt sind.

Alle Intl-Objekte besitzen Konstruktorfunktionen, die als erstes Argument eine Locale-Angabe erwarten. Dabei kann es sich um ein einzelnes Locale handeln oder ein Array aus mehreren Locales, aus diesen wird das erste verwendet, das der Computer unterstützt. Eine Locale-Angabe kann dabei ein Sprachkürzel sein oder ein Intl.Locale-Objekt. Der zweite Parameter aller Konstruktorfunktionen ist ein Objekt mit Optionen. Welche dabei möglich sind, hängt von der jeweiligen Konstruktorfunktion ab.

localeMatcher

Alle Konstruktorfunktionen, die von Intl bereitgestellt werden, unterstützen die Option localeMatcher. Hiermit kann der Algorithmus ausgewählt werden, der zu den gewünschten Locales das passende Locale des verwendeten Computers ermittelt. Der Standardwert ist hier "best fit", du kannst aber auch "lookup" angeben, um festzulegen, dass der in RFC-4647, Abschnitt 3.4 beschriebene Algorithmus verwendet wird. Wenn dir das nichts sagt, lass die Option einfach weg, eine eingehende Diskussion dieses Themas sprengt den Rahmen unseres Wikis.

Beispiele

Zahlen formatieren mit Intl.NumberFormat

Mit einem Intl.NumberFormat-Objekt kannst du Zahlen formatieren und dabei die Stellenzahl, Dezimaltrennzeichen, Währungen oder Einheiten und Rundungsregeln festlegen. Die Vorgehensweise ist dabei so, dass du mit Hilfe des Intl.NumberFormat-Konstruktors einen Formatierer erzeugst und dessen format-Methode verwendest, um einen oder mehrere Werte damit zu formatieren.

Das erste Beispiel erzeugt ein NumberFormat-Objekt für Euro-Beträge. Der Konstruktor bekommt de-DE als Locale, das Objekt wird deshalb ein Dezimalkomma verwenden. Im Optionsobjekt ist style:"currency" angegeben, die Ausgabe wird also als Währungsbetrag erfolgen. Das Währungssymbol ist kein Teil des Locale und muss deshalb durch die currency-Option als ISO 4217-Währungscode festgelegt werden. Die Anzahl der Nachkommastellen wird, weil ein Euro 100 Cent hat, automatisch auf 2 festgelegt. Der Rundungsmodus wird durch den Currency-Style nicht verändert, aber NumberFormat rundet standardmäßig kaufmännisch.

Darstellen von Geldbeträgen
const betragOutput = document.getElementById("endbetrag");
const summe = 12.3;

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

betragOutput.textContent = euro.format(summe);    // Ergebnis ist "12,30 €".

Außer currency gibt es noch die Stile decimal, percent und unit. Der Standardwert ist decimal.

Es gibt weitere Optionen, mit denen man die ausgegebene Stellenzahl bestimmen kann. Die Option minimumIntegerDigits ermöglicht es dir, eine Mindestzahl von Stellen vor dem Komma zu erzwingen und damit eine Ausgabe mit führenden Nullen zu realisieren. Das Locale de-DE würde auch einen Tausenderpunkt hinzufügen, den man mit einem Dezimalpunkt verwechseln könnte. Darum habe ich hier die schweizerische Variante benutzt, die ein Tausender-Hochkomma verwendet. Eine gern benutzte Alternative ist übrigens "sv-SE" (schwedisch-Schweden), wodurch man eine Tausender-Leerstelle erhält. Was leider nicht geht, ist die explizite Festlegung des Tausendertrenners. Dieser wird immer aus dem Locale abgeleitet. Man hat nur die Option, ihn mit useGrouping:false ganz abzuschalten.

Darstellen von führenden Nullen
const fn6 = new Intl.NumberFormat("de-CH", { style: "decimal", minimumIntegerDigits: 6 });
console.log(fn6.format(123));      // Ergebnis ist 000’123

const sv6 = new Intl.NumberFormat("sv-SE", { style: "decimal", minimumIntegerDigits: 6 });
console.log(sv6.format(123));      // Ergebnis ist 000 123

const ng6 = new Intl.NumberFormat("de", { style: "decimal", minimumIntegerDigits: 6, useGrouping: false });
console.log(ng6.format(123));      // Ergebnis ist 000123


Die Optionen minimumFractionDigits und maximumFractionDigits bestimmen, wieviele Stellen mindestens und höchstens hinter dem Komma angezeigt werden. Der Standardwert ist mindestens 0 und höchstens 3 Ziffern.

Darstellen von Zahlen mit festen Formaten
const f3 = new Intl.NumberFormat("de-DE", { style: "deccurrency", currency: "EUR" });

betragOutput.textContent = euro.format(summe);    // Ergebnis ist "12,30 €".

Sortieren mit Intl.Collator

Ein Intl.Collator-Objekt dient dazu, Stringvergleiche im Kontext einer bestimmten Kultur durchzuführen. Über das Optionen-Objekt, das der Konstruktor übergeben bekommt, sind etliche Varianten möglich.

Viele Locales bieten zum Sortieren unterschiedliche Zeichenordnungen (collation) an. Welche von einem Locale unterstützt werden, findest du heraus, indem du ein Locale-Objekt erzeugst und darauf die getCollations()-Methode aufrufst. Eine von diesen ist die Default-Collation des Locale, uns fehlt allerdings die Information, wie man für ein konkretes Locale ermittelt, welche Collation die Default-Collation ist. Für das de-DE Locale ist die Default-Collation jedenfalls eor (european ordering rules). Eine Liste aller Collations wird vom Unicode-Konsortium im CLDR Repository angeboten.

Beachte: In der ECMA-402 Spezifikation steht getCollations(). Im Firefox fehlt diese Abfragemöglichkeit allerdings bisher (Nov. 2023) ganz, und die Chromium- und Safaro-Browser implementieren statt dessen eine Eigenschaft namens collations. Um mit Realität und Spezifikation kompatibel zu sein, muss man deshalb prüfen, ob es die Methode gibt und sie benutzen, wenn sie vorhanden ist.
Anzeigen aller Collations, die ein Locale anbietet
const deutsch = new Intl.Locale("de-DE");
const collations = deutsch.getCollations ? deutsch.getCollations() : deutsch.collations;
console.log(collations);
// Ausgabe: ["emoji", "eor", "phonebk"]

Wir wollen nun zeigen, wie man den Intl.Collator zum Sortieren von Arrays verwendet. Die Array-Methode toSorted(), die seit Juli 2023 auch im Firefox angekommen ist, erzeugt eine sortierte Kopie eines Arrays, statt das bestehende Array zu überschreiben. So wie bei sort() kann man ihr eine Vergleichsfunktion übergeben.

Sortieren eines Arrays mit deutscher Telefonbuch-Reihenfolge
const namen = [ "Göbel", "Goethe", "Goldmann", "Gunther", "Göthe", "Götz" ]
const lexikon = new Intl.Collator("de-DE");
const telbu_DE = new Intl.Collator("de-DE", { collation:"phonebk"} );
const telbu_AT = new Intl.Collator("de-AT", { collation:"phonebk"} );

console.log("Pur           : ", namen.toSorted());
console.log("Lexikon       : ", namen.toSorted((a,b) => lexikon.compare(a,b)));
console.log("Telefonbuch DE: ", namen.toSorted((a,b) => telbu_DE.compare(a,b)));
console.log("Telefonbuch AT: ", namen.toSorted((a,b) => telbu_AT.compare(a,b)));

Das Ergebnis sollte so aussehen:

Pur           :  (6) ['Goethe', 'Goldmann', 'Gunther', 'Göbel', 'Göthe', 'Götz']
Lexikon       :  (6) ['Göbel', 'Goethe', 'Goldmann', 'Göthe', 'Götz', 'Gunther']
Telefonbuch DE:  (6) ['Göbel', 'Goethe', 'Göthe', 'Götz', 'Goldmann', 'Gunther']
Telefonbuch AT:  (6) ['Goethe', 'Goldmann', 'Göbel', 'Göthe', 'Götz', 'Gunther']

Ohne eine Collator-Funktion erfolgt die Sortierung nach Unicode-Codepoints, weshalb alle Worte mit ö am Ende stehen, noch nach Gunther. Das entspricht sicherlich nicht den Regeln der deutschen Sprache.

Die "Lexikon"-Ausgabe entspricht dem, was DIN 5007 in Variante 1 festlegt (d.h. ä, ö, ü und ß werden a, o, u und ss gleichgesetzt).

Bei der Telefonbuch-Variante zeigt sich, dass deutsche und österreichische Telefonbücher nicht gleich sortiert sind. In Österreich wird ä hinter a eingeordnet, ö hinter o, ü hinter u und ß hinter ss. In Deutschland wird hingegen ä mit ae gleichgesetzt, ö mit oe, ü mit ue und ß mit ss.[1]

Date-Objekte formatieren mit Intl.DateTimeFormat

TBD
  1. Wikipedia: Sortierung im Deutschen, abgerufen 05.11.2023