Hello,
I’ve recently been working on unifying date formats in Foreman and Katello and adding React components for that (Redmine #21312).
You might have noticed that the first attempt got reverted due to adding too large npm dependencies. After that I explored some alternative implementations and would like to know other devels’ opinions prior to sending a new PR.
The goal of the date unification was providing React components for Foreman, Katello and other plugins that could be used either from erb helpers or js (both React and Angular). After initial research of what is currently used across plugins we agreed on sticking to 4 formats (examples for en_US):
LongDateTime October 13, 2017, 1:54 PM
ShortDateTime Oct 13, 1:54 PM
Date 9/3/2010
RelativeTime 2 days ago
See the discussion in the original PR for details.
I created prototypes of solutions using two libraries Format.js and moment.js. Both have its pros and cons which I describe below and would like to know which one you like more or if you have some more ideas.
Format.js
is a collection of js libraries for formatting dates, numbers and translations. It provides bindings for multiple frameworks (react, ember, handlebars… we’d use only the first one). It uses Intl API for formatting dates and numbers - it’s an internacionalization standard that browsers are adopting. We need only subset of the functionality, that is currently supported in: Chrome 24+, Firefox 29+, Internet Explorer 11+, Opera 15+, Safari 10+ and all versions of Edge.
There’s a blogpost describing purpose of Intl API nicely.
The biggest benefit of Intl API is that it provides true localization for dates. You only specify which components of the datetime you want to display and it builds a date in correct order of month, date, punctuation, etc. for the language. E.g.
en-US January 3, 2018
cs-CZ 3. ledna 2018
fr-FR 3 janvier 2018
The relevant part of Format.js for us is react-intl. Apart from wrapping the standard Intl API functionality it adds relative date formatting and message formatting. Although the API has been adopted by most of the modern browsers, we still need to have a fallback for the older ones (or for Phantom that lacks it and which we use for testing). This is usually solved by requiring a fallback Intl package. Unfortunately it’s quite large so it should be better loaded lazily only when needed.
Additional raw size of the dependencies for this solution is: 98.6 k for react-intl and 486 k for the fallback intl.
My prototype of that solution is at:
https://github.com/theforeman/foreman/compare/develop...tstrachota:dates_intl
Unfortunately I haven’t managed to get the lazy loading working. I tried to use webpack’s import but for some reason it seems not to work with the dev server.
moment.js
is a library for parsing and manipulating dates in js. It requires no additional dependencies. The drawback is that it provides only limited number of truly localized formats (see Multiple Locale Support in docs) and it’s not that flexible. For our case specifically it means that we’re not able to create ShortDateTime with moment.js in the same format as we use it now (moment always adds year - “Oct 13, 1:54 PM” vs. “Oct 13, 2018 1:54 PM”).
To solve that we can either agree on using different format of ShortDateTime or define it ourselves and maintain formats for all transaltions ourselves (I’d like to avoid that).
Additional raw size of this dependency is 203.7 k.
The prototype lives here:
https://github.com/theforeman/foreman/compare/develop...tstrachota:dates_moment
I didn’t get timezones working, but there’s some support for that so it should be doable.
Given all the above, the possible solutions in my mind are:
- use react-intl with the intl dependency loaded conditionally for the browsers that need it
- use moment.js and select some other format for ShortDateTime
- use moment.js and maintain format for ShortDateTime ourselves
I still tend to prefer no 1). What do you think?
T.