Comment formater le temps relatif dans Next.js (Pages Router) v16

Formatez les horodatages en phrases du type « il y a 2 jours »

Problème

Afficher les horodatages sous forme de phrases de temps relatif comme « il y a 2 jours » ou « dans 3 heures » rend le contenu immédiat et contextuel. Cependant, ces phrases suivent des schémas grammaticaux complexes qui varient considérablement d'une langue à l'autre. L'anglais place « ago » après les quantités passées et « in » avant les quantités futures, mais d'autres langues peuvent utiliser des ordres de mots différents, fléchir les unités de temps en fonction de la quantité ou employer des structures grammaticales entièrement différentes. Construire manuellement ces phrases par concaténation de chaînes produit un résultat incorrect dans toutes les langues sauf celle pour laquelle elle a été écrite, brisant l'expérience utilisateur pour les audiences internationales.

Solution

Utilisez le formatage de temps relatif de react-intl pour convertir les différences de temps numériques en phrases grammaticalement correctes pour la locale de l'utilisateur. Calculez la différence de temps entre un horodatage et le moment actuel, déterminez l'unité appropriée (secondes, minutes, heures, jours) et transmettez les deux valeurs aux API de formatage de react-intl. L'API Intl.RelativeTimeFormat sous-jacente gère automatiquement la grammaire, l'ordre des mots et les règles de flexion spécifiques à chaque locale.

Étapes

1. Créer une fonction auxiliaire pour calculer les valeurs de temps relatif

La différence de temps doit être convertie en valeur numérique et en unité appropriée. Créez une fonction qui compare un horodatage au temps actuel et sélectionne la meilleure unité.

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 };
  }
}

Cette fonction renvoie une valeur numérique signée (négative pour le passé, positive pour le futur) et l'unité la plus appropriée en fonction de l'amplitude de la différence.

2. Formater le temps relatif avec le hook useIntl

La fonction formatRelativeTime renvoie une chaîne de temps relatif formatée et attend une valeur numérique, une unité et des options conformes à Intl.RelativeTimeFormatOptions. Utilisez la fonction auxiliaire de l'étape 1 pour obtenir la valeur et l'unité, puis formatez-les.

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>
  );
}

La méthode formatRelativeTime produit des phrases adaptées à la locale comme « 2 days ago » en anglais ou « il y a 2 jours » en français.

3. Utiliser FormattedRelativeTime pour un formatage déclaratif

FormattedRelativeTime implémente des fonctionnalités avancées comme la mise à jour au fil du temps et utilise l'API formatRelativeTime avec des props pour la valeur, l'unité et les options de formatage relatif. Pour les composants nécessitant des mises à jour automatiques, utilisez la forme composant.

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>
  );
}

La prop updateIntervalInSeconds contrôle la fréquence à laquelle le composant se re-rend, maintenant la phrase affichée à jour au fil du temps.

4. Personnaliser le style de formatage

Le composant accepte RelativeTimeFormatOptions incluant les propriétés numeric et style. Ajustez ces options pour contrôler le format de sortie.

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"
    />
  );
}

Définir numeric="auto" produit des phrases comme « hier » au lieu de « il y a 1 jour » lorsque c'est approprié, et style="narrow" crée des formes plus courtes comme « il y a 2 m » au lieu de « il y a 2 mois ».