Moment.js logo

Ce billet prend racine dans un problème d’internationalisation de mon application, plus précisément pour la mise en forme des dates avec Moment.JS.

Mais avant de me lancer, j’aimerais partager mon émotion. J’ai commencé ce blog il y a un peu plus de 10 ans, et c’est mon premier billet sur du développement front. Autant vous dire que je me sens complètement illégitime, mais comme ça fait longtemp que ce sentiment ne me freine plus, je me lance.

Afficher les dates en anglais

Dans un premier temps, mon application doit supporter le français et l’anglais. On stocke la langue préférée d’un utilisateur dans son profil et s’il n’a enregistré aucune préférence, on se base sur celle qui est configurée pour son navigateur. La langue est utilisée pour tous les textes, mais aussi pour adapter le format des nombres, des dates et des heures.

Pour la mise en forme des dates et heures, on utilise Moment.JS.

Voici comment les dates sont affichées en français :

moment.locale('fr');
const date = moment('2000-12-31');
const short = date.format('L');        // 31/12/2000
const medium = date.format('ll');      // 31 déc. 2000
const long = date.format('dddd LL');   // dimanche 31 décembre 2000

Et voici comment elles sont affichées en anglais :

moment.locale('en');
const date = moment('2000-12-31');
const short = date.format('L');        // 12/31/2000
const medium = date.format('ll');      // Dec 31, 2000
const long = date.format('dddd LL');   // Sunday December 31, 2000

Et là, les anglais, australiens et néo-zélandais commencent à râler parce que ce n’est pas leur façon de présenter des dates.

En effet, en utilisant la locale 'en', la librairie utilise le format des américains. En effet les américains sont à peu près les seuls au monde à adopter un format aussi peu logique.

Amazingly comprehensive map of every country in the world that uses the MMDDYYYY format

Map

Je ne dois pas me contenter de supporter l’anglais mais aussi ses différentes variantes : l’anglais américains (en-US), l’anglais britannique (en-GB), l’anglais australiens (en-AU),…​ Il y a ainsi une dizaine de cultures de langue anglaise.

L’anglais américain contre l’anglais britannique

Ou alors, je peux supporter explicitement l’anglais américain (en-US), avec ses dates toutes bizarres, et faire en sorte que l’anglais générique (en) se rapproche de l’anglais britannique (en-GB).

Revenons à Moment.js. Il peut fournir la liste des locales supportées :

moment.locales();

Et là on constate que en-US n’existe pas. Ça semble logique puisque c’est implémenté dans en.

La solution est donc de personnaliser Moment.js, en lui ajoutant la culture manquante puis de reconfigurer la langue en pour qu’elle soit britannique.

    moment.defineLocale('en-us', {parentLocale:'en'});
    moment.updateLocale('en', {...moment.localeData('en-gb')._config, abbr: 'en'});

Dans cette nouvelle configuration, voici comment les dates sont affichées en anglais :

moment.locale('en');
const date = moment('2000-12-31');
const short = date.format('L');        // 31/12/2000
const medium = date.format('ll');      // 31 Dec 2000
const long = date.format('dddd LL');   // Sunday 31 December 2000
Le format ll ne donne pas toujours le résultat attendu lorsqu’on reconfigure Moment.js à la volée. En revanche, ça fonctionne de façon plus stable si la personnalisation est faite dès le démarrage.

Le résultat

En conclusion, l’erreur initiale a été de considérer que la mise en forme des dates dépend de la langue. En réalité, il dépend plus du pays.

Formats de dates par pays

Finalement, il ne faut que 3 lignes de codes pour que l’anglais générique soit celui des britanniques et pas celui des américains. Mais ça reste de la bidouille, et le jour où il faudra virer Moment.js ça ne marchera plus. Vous pouvez les voir à l’oeuvre dans ce bac à sable.