Toute application affichant des dates doit un jour ou l'autre les présenter sous une forme relative et lisible par un humain : « il y a 3 minutes », « dans 2 jours », « la semaine dernière ». L'approche la plus courante consiste à écrire une série de conditions if/else et de chaînes de caractères codées en dur. Mais depuis 2020, tous les navigateurs modernes intègrent une API dédiée qui évite ce travail artisanal : Intl.RelativeTimeFormat.
Le problème des solutions maison
Une fonction de formatage relative faite maison suit généralement le même schéma : calculer le nombre de secondes écoulées, puis tester des seuils (60 secondes, 3600 secondes, 86400 secondes) pour choisir l'unité et retourner une chaîne concaténée. Même en externalisant les chaînes dans des fichiers de traduction – par exemple avec une bibliothèque comme next-intl – la logique de sélection de l'unité reste écrite à la main, et les règles de pluriel des langues cibles ne sont pas appliquées.
Or ces règles varient considérablement d'une langue à l'autre. L'arabe possède six formes plurielles. Le gallois a une forme spéciale pour le nombre 2. Le russe utilise des formes différentes selon que le nombre est 1, 2 à 4, ou 5 et plus. Un formatage maison se trompera systématiquement sur chacun de ces cas.
L'API Intl.RelativeTimeFormat
JavaScript moderne intègre des API d'internationalisation sous l'espace de noms Intl. Intl.RelativeTimeFormat prend en entrée une locale (par exemple 'en', 'fr', 'ar') et un objet d'options. Sa méthode format() gère toutes les transformations : pluriel, direction d'écriture, chiffres et traduction du texte lui-même.
const relativeTimeFormat = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
relativeTimeFormat.format(-1, 'day'); // "yesterday"
relativeTimeFormat.format(3, 'hour'); // "in 3 hours"
relativeTimeFormat.format(-10, 'second'); // "10 seconds ago"
Le premier argument est un nombre signé (négatif pour le passé, positif pour le futur), le second est une unité de temps : "second", "minute", "hour", "day", "week", "month", "quarter" ou "year".
Les options
Deux options principales permettent d'affiner le résultat :
numeric: avec la valeur'auto', le formateur utilise des raccourcis linguistiques naturels ("today","yesterday","next week"). Avec'always', il utilise systématiquement des nombres ("in 0 days","1 day ago").style: trois niveaux de verbosité –'long'("3 months ago"),'short'("3 mo. ago"),'narrow'("3mo ago") – permettent de s'adapter au contexte (interfaces denses, badges de notification, textes accessibles).
Rendu multilingue
La force de l'API apparaît lorsqu'on l'utilise avec plusieurs locales. Un même appel produit automatiquement la forme correcte dans chaque langue :
en: 3 days ago
fr: il y a 3 jours
de: vor 3 Tagen
ar: قبل ٣ أيام
ja: 3 日前
ru: 3 дня назад
zh: 3天前
Le pluriel, le système d'écriture et le jeu de chiffres – l'arabe passe automatiquement aux chiffres arabes orientaux – sont gérés par le moteur JavaScript. Le travail de traduction est déjà intégré dans le navigateur.
Styliser le résultat avec formatToParts()
La méthode format() renvoie une chaîne simple, ce qui empêche de styliser indépendamment la valeur numérique et le texte. formatToParts() résout ce problème en renvoyant un tableau structuré où chaque élément possède un type ('integer', 'literal') et une valeur. On peut alors, par exemple, afficher le nombre en gras et le reste en italique dans un composant React sans avoir à parser la chaîne.
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'always' });
rtf.formatToParts(-5, 'minute');
// [
// { type: 'integer', value: '5', unit: 'minute' },
// { type: 'literal', value: ' minutes ago' }
// ]
En résumé
Intl.RelativeTimeFormat est un outil essentiel de l'espace de noms Intl. Il prend en charge les parties difficiles – pluriel, direction d'écriture, format des nombres et traduction – sans qu'il soit nécessaire d'ajouter une bibliothèque externe. Pour toute application qui doit afficher des dates lisibles pour un public parlant plusieurs langues, cette API est la solution à privilégier.