Zum Inhalt springen
aviral gupta

// I5.4 · ca. 34 Min. · Aufbau

Formatieren für Menschen mit Intl

Nach dieser Lektion zeigen Sie Zahlen, Euro-Preise, Daten, relative Zeiten und Listen so an, wie Menschen in Deutschland oder den USA es erwarten, mit derselben Ausgabe auf jedem Computer.

Lektion 4 von 5 in I5 Mit Daten arbeiten

Danach können Sie

  • Zahlen, Euro-Preise, Prozente und kompakte Zahlen für ein Locale mit Intl.NumberFormat formatieren
  • Daten und Uhrzeiten mit Intl.DateTimeFormat und fester timeZone formatieren
  • Relative Zeiten, Pluralformen und Listen mit Intl schreiben und mit den geschützten Leerzeichen in der Ausgabe umgehen
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion I5.3. Ein Datumstext von Hand gebaut. Was gibt das aus?

    const d = new Date(Date.UTC(2026, 9, 5));
    console.log(d.getUTCMonth() + 1 + "/" + d.getUTCDate());
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen. Dieselbe Zahl, zwei Locales. Was gibt das aus?

    const n = 1234.5;
    console.log(n.toLocaleString("de-DE"), n.toLocaleString("en-US"));
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie den Optionsnamen, der sagt, welche Währung genutzt wird.

    const eur = new Intl.NumberFormat("de-DE", { style: "currency", ____: "EUR" });
    console.log(eur.format(5));
    { style: "currency",: "EUR" }
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jedem Intl-Werkzeug zu, was es schreibt.

  5. Üben · Aufgabe 5 von 7

    Was gibt das aus?

    console.log(new Intl.NumberFormat("en-US", { style: "percent" }).format(0.256));
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Fünf Euro, deutsch formatiert, verglichen mit getipptem Text. Was gibt das aus?

    const price = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(5);
    console.log(price === "5,00 €", price.length);
  7. Anwenden · Aufgabe 7 von 7

    Kleine Aufgabe: ein deutscher Kassenbon. Sie haben items = [{name: "Tea", price: 3.5}, {name: "Cake", price: 4.2}, {name: "Coffee", price: 2.8}]. Geben Sie das Datum 5. Oktober 2026 in deutscher Langform aus, jeden Artikel mit seinem Preis in Euro, die Summe und eine deutsche Liste der Artikelnamen.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Ein Wert, viele Formate

Derselbe Preis wird für Deutschland und für die USA formatiert, dann ein Prozentwert und eine kompakte Zahl. Ein Datum mit Uhrzeit wird mit timeZone: "UTC" auf Deutsch geschrieben, und derselbe Moment wird als Berliner Zeit gezeigt. Relative Zeit, Pluralregeln und eine Liste folgen. Die letzte Zeile schaut in einen formatierten Preis hinein: Er hat sechs Zeichen, und das fünfte ist kein gewöhnliches Leerzeichen.

main.js

const when = new Date(Date.UTC(2026, 9, 5, 14, 30));

// 1. Numbers and prices: the same number for two locales.
const eurDE = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" });
const eurUS = new Intl.NumberFormat("en-US", { style: "currency", currency: "EUR" });
console.log(eurDE.format(1234.56), "|", eurUS.format(1234.56));
console.log(new Intl.NumberFormat("en-US", { style: "percent" }).format(0.256));
console.log(new Intl.NumberFormat("en-US", { notation: "compact" }).format(1234567));

// 2. Dates: always give a timeZone, or the output depends on the computer.
const long = new Intl.DateTimeFormat("de-DE", { dateStyle: "long", timeStyle: "short", timeZone: "UTC" });
console.log(long.format(when));
const berlin = new Intl.DateTimeFormat("en-GB", { timeStyle: "short", timeZone: "Europe/Berlin" });
console.log("in Berlin:", berlin.format(when));

// 3. Relative time, plural rules and lists.
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
console.log(rtf.format(-1, "day"), "|", rtf.format(3, "day"));
const plural = new Intl.PluralRules("en");
for (const n of [1, 2]) console.log(n, plural.select(n) === "one" ? "file" : "files");
console.log(new Intl.ListFormat("en", { type: "conjunction" }).format(["Map", "Set", "Intl"]));

// 4. The space before € is not an ordinary space.
const price = eurDE.format(5);
console.log(price.length, "U+" + price.codePointAt(4).toString(16).padStart(4, "0"));

Ausführen mit

node main.js

Ausgabe

1.234,56 € | €1,234.56
26%
1.2M
5. Oktober 2026 um 14:30
in Berlin: 16:30
yesterday | in 3 days
1 file
2 files
Map, Set, and Intl
6 U+00a0
  • Deutsch setzt € hinter den Betrag, amerikanisches Englisch davor, für dieselbe Währung.
  • 14:30 UTC ist im Oktober 16:30 in Berlin; die Option timeZone hat nur den Text geändert, nicht den Moment.
  • U+00A0 ist das geschützte Leerzeichen; ein gewöhnliches Leerzeichen wäre U+0020.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Preise in Euro

formatPrice(cents, locale) bekommt einen Betrag in Cent und ein Locale und gibt den Preis in Euro so zurück, wie dieses Locale ihn schreibt: formatPrice(1250, "de-DE") ist "12,50 €" mit einem geschützten Leerzeichen, und formatPrice(1250, "en-US") ist "€12.50". Der Startcode baut den Text von Hand und ignoriert das Locale. Nutzen Sie Intl.NumberFormat.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: Das deutsche Ergebnis hat einen Punkt und ein gewöhnliches Leerzeichen. Welches Werkzeug kennt die Regeln jedes Locales?

  2. Hinweis 2

    new Intl.NumberFormat(locale, { style: "currency", currency: "EUR" })

  3. Hinweis 3

    Teilen Sie vor dem Formatieren durch 100: eur.format(cents / 100).

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function formatPrice(cents, locale) {
  const eur = new Intl.NumberFormat(locale, { style: "currency", currency: "EUR" });
  return eur.format(cents / 100);
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

export function formatPrice(cents, locale) {
  return (cents / 100).toFixed(2) + " €";
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {formatPrice} from './main.js';

test('Deutsch: 12,50 und ein geschütztes Leerzeichen vor dem Eurozeichen', () => {
  const got = formatPrice(1250, 'de-DE');
  assert.equal(got, '12,50\u00a0€', `formatPrice(1250, 'de-DE') gab ${JSON.stringify(got)}`);
});

test('Amerikanisches Englisch: Das Eurozeichen kommt zuerst', () => {
  const got = formatPrice(1250, 'en-US');
  assert.equal(got, '€12.50', `formatPrice(1250, 'en-US') gab ${JSON.stringify(got)}`);
});

test('Tausender werden gruppiert', () => {
  const got = formatPrice(123456, 'de-DE');
  assert.equal(got, '1.234,56\u00a0€', `formatPrice(123456, 'de-DE') gab ${JSON.stringify(got)}`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Übung 2 von 2

Gestern, heute, morgen

daysAgo(timestamp, now) bekommt zwei Timestamps zu UTC-Mitternacht und gibt englischen Text zurück: "yesterday" für einen Tag zurück, "today" für denselben Tag, "tomorrow" für einen Tag voraus und sonst "3 days ago" oder "in 2 days". Der Startcode schreibt immer "N days ago", auch für einen Tag oder für die Zukunft. Nutzen Sie Intl.RelativeTimeFormat mit numeric: "auto".

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    RelativeTimeFormat will für die Vergangenheit eine negative Zahl: format(-1, "day").

  2. Hinweis 2

    Berechnen Sie also (timestamp - now) / DAY, nicht (now - timestamp) / DAY.

  3. Hinweis 3

    const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" }); return rtf.format(days, "day");

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

const DAY = 24 * 60 * 60 * 1000;
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });

export function daysAgo(timestamp, now) {
  const days = Math.round((timestamp - now) / DAY);
  return rtf.format(days, "day");
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

const DAY = 24 * 60 * 60 * 1000;

export function daysAgo(timestamp, now) {
  const days = Math.round((now - timestamp) / DAY);
  return `${days} days ago`;
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {daysAgo} from './main.js';

const now = Date.UTC(2026, 9, 5);
const day = (n) => Date.UTC(2026, 9, 5 + n);

test('Ein Tag zurück ist yesterday', () => {
  assert.equal(daysAgo(day(-1), now), 'yesterday', `bekam ${daysAgo(day(-1), now)}`);
});

test('Drei Tage zurück ist 3 days ago', () => {
  assert.equal(daysAgo(day(-3), now), '3 days ago', `bekam ${daysAgo(day(-3), now)}`);
});

test('Derselbe Tag ist today', () => {
  assert.equal(daysAgo(now, now), 'today', `bekam ${daysAgo(now, now)}`);
});

test('Zwei Tage voraus ist in 2 days', () => {
  assert.equal(daysAgo(day(2), now), 'in 2 days', `bekam ${daysAgo(day(2), now)}`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Häufige Fehler

Einen formatierten Preis an einem Leerzeichen trennen

const price = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(12.5);
const [amount, symbol] = price.split(" ");
console.log(symbol.toUpperCase());

Was Node.js ausgibt

TypeError: Cannot read properties of undefined (reading 'toUpperCase')

Warum, und die Lösung

Das Leerzeichen in "12,50 €" ist ein geschütztes Leerzeichen, U+00A0, nicht " ", split(" ") findet also nichts zum Trennen, und symbol ist undefined. Zerlegen Sie formatierten Text nicht; er ist für Menschen. Brauchen Sie die Teile, nutzen Sie formatToParts(12.5), das sie als Objekte liefert, oder halten Sie die Zahl und den Währungscode getrennt.

Der Stil currency ohne Währung

const price = new Intl.NumberFormat("de-DE", { style: "currency" });
console.log(price.format(5));

Was Node.js ausgibt

TypeError: Currency code is required with currency style.

Warum, und die Lösung

Intl kann die Währung nicht aus dem Locale erraten: Deutschland und Österreich nutzen Euro, aber ein deutscher Shop kann in Dollar verkaufen. Geben Sie immer den Code an: { style: "currency", currency: "EUR" }.

Ein Stadtname als Zeitzone

const time = new Intl.DateTimeFormat("de-DE", { timeStyle: "short", timeZone: "Berlin" });
console.log(time.format(new Date()));

Was Node.js ausgibt

RangeError: Invalid time zone specified: Berlin

Warum, und die Lösung

timeZone nimmt einen IANA-Zeitzonennamen, also Region und Stadt: "Europe/Berlin", "America/New_York". "UTC" und Offsets wie "+01:00" funktionieren ebenfalls. Eine Stadt allein ist kein gültiger Name.

JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Ein Formatierer pro Locale und Stil

Jedes Intl-Werkzeug funktioniert gleich: Sie erzeugen einen Formatierer mit einem Locale, etwa "de-DE" oder "en-US", und Optionen und rufen dann format(value) auf. Intl.NumberFormat schreibt 1234.56 auf Deutsch als 1.234,56 und im amerikanischen Englisch als 1,234.56. { style: "currency", currency: "EUR" } ergänzt das Eurozeichen und zwei Nachkommastellen, und die Option currency ist für diesen Stil Pflicht. style: "percent" multipliziert mit 100, und notation: "compact" schreibt 1234567 als 1.2M. number.toLocaleString(locale, options) nimmt dieselben Optionen, aber bei vielen Werten rät MDN, einen Formatierer zu erzeugen und sein format() wiederzuverwenden.

Daten brauchen eine Zeitzone

Intl.DateTimeFormat formatiert ein Date für ein Locale: dateStyle und timeStyle ("full", "long", "medium", "short") wählen fertige Muster, und Optionen wie weekday: "long" oder hour: "2-digit" wählen einzelne Teile. Ohne die Option timeZone nutzt der Formatierer die Zeitzone des Computers, dasselbe Date kann auf einem anderen Rechner also einen anderen Tag zeigen. Geben Sie timeZone: "UTC" an, wenn der Wert in UTC gespeichert ist, oder den Ort, den Sie meinen, etwa "Europe/Berlin". Derselbe Timestamp wird dann überall als derselbe Text ausgegeben. date.toLocaleDateString(locale, options) funktioniert auch.

Relative Zeit, Plurale, Listen und versteckte Leerzeichen

Intl.RelativeTimeFormat schreibt format(-3, "day") als "3 days ago"; mit numeric: "auto" wird -1 zu "yesterday". Intl.PluralRules sagt Ihnen, welche Form eine Zahl braucht: select(1) ist im Englischen "one", select(2) ist "other". Intl.ListFormat verbindet ["a", "b", "c"] im Englischen zu "a, b, and c" und im Deutschen zu "a, b und c". Die Ausgabe kann geschützte Leerzeichen enthalten: Deutsch schreibt das Leerzeichen vor € und % als U+00A0, und Französisch gruppiert Tausender mit U+202F (1234.5 wird in fr-FR zu "1\u202f234,5"). Sie sehen aus wie Leerzeichen, sind aber andere Zeichen, trennen Sie formatierten Text also nie an " " und vergleichen Sie ihn nie mit einem getippten String. Vergleichen Sie mit "\u00a0" im erwarteten Text, oder vergleichen Sie Zahlen vor dem Formatieren.

Quellen

Zuletzt geprüft am 5. Oktober 2026