UNPKG

react-time-ago

Version:

Localized relative date/time formatting in React

80 lines (66 loc) 3.17 kB
import memoize from 'memoize-one'; import { intlDateTimeFormatSupported, intlDateTimeFormatSupportedLocale } from './locale.js'; import Cache from './cache.js'; var cache = new Cache(); var INTL_DATE_TIME_FORMAT_SUPPORTED = intlDateTimeFormatSupported(); var FALLBACK_VERBOSE_DATE_FORMATTER = function FALLBACK_VERBOSE_DATE_FORMATTER(date) { return date.toString(); }; /** * Returns a verbose date formatter. * * @param {string} locale - Date formatting locale * @param {object} format - Output format * @param {string} format.day - Day format * @param {string} format.month - Month format * @param {string} format.year - Year format * @param {string} format.weekday - Weekday format * @param {string} format.hour - Hour format * @param {string} format.minute - Minute format * @param {string} format.second - Second format * * @returns {Function} `(date) -> string`. */ function getVerboseDateFormatter(locales, format) { // Fall back to `date.toString()` for old web browsers. // https://caniuse.com/#search=intl if (!INTL_DATE_TIME_FORMAT_SUPPORTED) { return FALLBACK_VERBOSE_DATE_FORMATTER; } // If none of the `locales` are supported // a default system locale will be used. var locale = resolveLocale(locales); // `Intl.DateTimeFormat` format caching key. // E.g. `"{"day":"numeric","month":"short",...}"`. // Didn't benchmark what's faster: // creating a new `Intl.DateTimeFormat` instance // or stringifying a small JSON `format`. // Perhaps strigifying JSON `format` is faster. var formatFingerprint = JSON.stringify(format); // Get `Intl.DateTimeFormat` instance for these `locale` and `format`. // (`locale` can be `undefined`, hence the `String(locale)` conversion) var formatter = cache.get(String(locale), formatFingerprint) || cache.put(String(locale), formatFingerprint, new Intl.DateTimeFormat(locale, format)); // Return date formatter return function (date) { return formatter.format(date); }; } // Even though `getVerboseDateFormatter()` function is called inside a // `useMemo()` hook, it's still invoked every time for different // `<ReactTimeAgo/>` elements on a page. There could be a lot of such // `<ReactTimeAgo/>` elements on a page. And `useMemo()` wouldn't speed up // the initial render. To work around that, simple argument-based memoization // is used. export default memoize(getVerboseDateFormatter); // Caching locale resolving for optimizing pages // with a lot of `<ReactTimeAgo/>` elements (say, 100 or more). // `Intl.DateTimeFormat.supportedLocalesOf(locales)` is not instantaneous. // For example, it could be 25 milliseconds for 200 calls. var resolvedLocales = {}; /** * Resolves a list of possible locales to a single ("best fit") supported locale. * @param {string[]} locales * @return {string} */ function resolveLocale(locales) { var localesFingerprint = locales.toString(); if (resolvedLocales[localesFingerprint]) { return resolvedLocales[localesFingerprint]; } return resolvedLocales[localesFingerprint] = intlDateTimeFormatSupportedLocale(locales); } //# sourceMappingURL=getVerboseDateFormatter.js.map