Wie man relative Zeitangaben in Next.js (Pages Router) v16 formatiert

Zeitstempel als '2 Tage zuvor' Ausdrücke formatieren

Problem

Die Anzeige von Zeitstempeln als relative Zeitangaben wie "vor 2 Tagen" oder "in 3 Stunden" lässt Inhalte unmittelbar und kontextbezogen wirken. Diese Phrasen folgen jedoch komplexen grammatikalischen Mustern, die sich zwischen Sprachen drastisch unterscheiden. Im Englischen steht "ago" nach Zeitangaben in der Vergangenheit und "in" vor zukünftigen Angaben, während andere Sprachen unterschiedliche Wortstellungen verwenden, Zeiteinheiten je nach Menge beugen oder völlig andere grammatikalische Strukturen einsetzen. Die manuelle Konstruktion dieser Phrasen durch String-Verkettung erzeugt in jeder Sprache außer der, für die sie geschrieben wurde, fehlerhafte Ausgaben und beeinträchtigt das Nutzererlebnis für internationale Zielgruppen.

Lösung

Verwenden Sie die relative Zeitformatierung von react-intl, um numerische Zeitdifferenzen in grammatikalisch korrekte Phrasen für die Locale des Benutzers umzuwandeln. Berechnen Sie die Zeitdifferenz zwischen einem Zeitstempel und dem aktuellen Moment, bestimmen Sie die geeignete Einheit (Sekunden, Minuten, Stunden, Tage) und übergeben Sie beide Werte an die Formatierungs-APIs von react-intl. Die zugrunde liegende Intl.RelativeTimeFormat-API verarbeitet automatisch die sprachspezifische Grammatik, Wortstellung und Beugungsregeln.

Schritte

1. Erstellen einer Hilfsfunktion zur Berechnung relativer Zeitwerte

Die Zeitdifferenz muss in einen numerischen Wert und eine geeignete Einheit umgewandelt werden. Erstellen Sie eine Funktion, die einen Zeitstempel mit der aktuellen Zeit vergleicht und die beste Einheit auswählt.

export function getRelativeTimeValue(date: Date | number) {
  const now = Date.now();
  const timestamp = typeof date === "number" ? date : date.getTime();
  const diffInSeconds = (timestamp - now) / 1000;

  const minute = 60;
  const hour = minute * 60;
  const day = hour * 24;
  const week = day * 7;
  const month = day * 30;
  const year = day * 365;

  const absDiff = Math.abs(diffInSeconds);

  if (absDiff < minute) {
    return { value: Math.round(diffInSeconds), unit: "second" as const };
  } else if (absDiff < hour) {
    return {
      value: Math.round(diffInSeconds / minute),
      unit: "minute" as const,
    };
  } else if (absDiff < day) {
    return { value: Math.round(diffInSeconds / hour), unit: "hour" as const };
  } else if (absDiff < week) {
    return { value: Math.round(diffInSeconds / day), unit: "day" as const };
  } else if (absDiff < month) {
    return { value: Math.round(diffInSeconds / week), unit: "week" as const };
  } else if (absDiff < year) {
    return { value: Math.round(diffInSeconds / month), unit: "month" as const };
  } else {
    return { value: Math.round(diffInSeconds / year), unit: "year" as const };
  }
}

Diese Funktion gibt einen vorzeichenbehafteten numerischen Wert (negativ für Vergangenheit, positiv für Zukunft) und die am besten geeignete Einheit basierend auf der Größenordnung der Differenz zurück.

2. Formatieren der relativen Zeit mit dem useIntl hook

Die formatRelativeTime-Funktion gibt einen formatierten relativen Zeitstring zurück und erwartet einen numerischen Wert, eine Einheit und Optionen, die Intl.RelativeTimeFormatOptions entsprechen. Verwenden Sie den Helper aus Schritt 1, um den Wert und die Einheit zu erhalten, und formatieren Sie diese dann.

import { useIntl } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function CommentTimestamp({ date }: { date: Date }) {
  const intl = useIntl();
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <time dateTime={date.toISOString()}>
      {intl.formatRelativeTime(value, unit)}
    </time>
  );
}

Die formatRelativeTime-Methode erzeugt sprachspezifische Ausdrücke wie "vor 2 Tagen" auf Deutsch oder "il y a 2 jours" auf Französisch.

3. Verwendung von FormattedRelativeTime für deklarative Formatierung

FormattedRelativeTime implementiert erweiterte Funktionen wie zeitabhängige Aktualisierungen und verwendet die formatRelativeTime-API mit Props für Wert, Einheit und relative Formatierungsoptionen. Für Komponenten, die automatische Aktualisierungen benötigen, verwenden Sie die Komponentenform.

import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function LiveTimestamp({ date }: { date: Date }) {
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <time dateTime={date.toISOString()}>
      <FormattedRelativeTime
        value={value}
        unit={unit}
        numeric="auto"
        updateIntervalInSeconds={10}
      />
    </time>
  );
}

Die updateIntervalInSeconds-Prop steuert, wie häufig die Komponente neu gerendert wird, wodurch der angezeigte Ausdruck aktuell bleibt, während die Zeit vergeht.

4. Anpassen des Formatierungsstils

Die Komponente akzeptiert RelativeTimeFormatOptions, einschließlich der Eigenschaften numeric und style. Passen Sie diese Optionen an, um das Ausgabeformat zu steuern.

import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function CompactTimestamp({ date }: { date: Date }) {
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <FormattedRelativeTime
      value={value}
      unit={unit}
      numeric="auto"
      style="narrow"
    />
  );
}

Die Einstellung numeric="auto" erzeugt Ausdrücke wie "gestern" anstelle von "vor 1 Tag", wenn es angemessen ist, und style="narrow" erstellt kürzere Formen wie "vor 2 Mon." anstelle von "vor 2 Monaten".