I have an app that receives a list of supported locales from the backend as a following response:
{locales: [{code: 'enUS'}, {code: 'deDE'}, {code: 'arAR'}]}
I want to use date-fns
library for handling date formatting but I have to import the whole date-fns/locale as I can't know beforehand which locale will be needed:
import * as dateFnsLocales from 'date-fns/locale';
The problem is, some of the locales are in different code format (for example, support for deutsch language is enabled when the backend response includes code: 'deDE', but the corresponding date-fns package is just 'de'. On the other hand date-fns package for english is 'enUS', not just 'en'.
Easy solution imho would be to handle it with some coalescing operator. The example is following:
import * as dateFnsLocales from 'date-fns/locale';
const supportedLocales = {locales: [{code: 'enUS'}, {code: 'deDE'}, {code: 'plPL'}]}
const newArrayWithSupportedLocales = supportedLocales.locales.map((locale) => ({
...locale,
dateFnsLocale: (dateFnsLocales[locale.code] || dateFnsLocales[locale.code.substring(0,2)]),
}));
Unfortunately I get the typescript error:
No index signature with a parameter of type 'string' was found on type 'typeof import("date-fns/locale")'. TS7053
Even if I hardcode the attempt like so:
dateFnsLocale: dateFnsLocales['plPL'.substring(0,2)]
it fails with the same error, even though this:
dateFnsLocale: dateFnsLocales['pl']
works just fine.
Here's the code I am using for doing dynamic lookups using Expo's Localization
object.
import * as Localization from 'expo-localization';
import * as Locales from 'date-fns/locale';
import { Locale } from 'date-fns';
/**
* Looks up a date-fns locale from the Expo localization object. This falls back to `en-US`
* @param localization Expo Localization object containing the locale and region.
* @returns date-fns locale.
*/
export function getDateFnsLocale({ locale, region }: Pick<typeof Localization, 'locale'|'region'>) : Locale {
return (
Locales[locale.substring(0, 2) + region] ?? Locales[locale.substring(0, 2)] ?? Locales.enUS
);
}
Here's the test
import { enUS, fr, frCA } from 'date-fns/locale';
describe('date-fns locale lookup', () => {
it('shound find fr', () => {
expect(getDateFnsLocale({ locale: 'fr', region: null })).toBe(fr);
});
it('shound find fr-CA', () => {
expect(getDateFnsLocale({ locale: 'fr-CA', region: 'CA' })).toBe(frCA);
});
it('shound not find zz-ZZ', () => {
expect(getDateFnsLocale({ locale: 'zz-ZZ', region: 'ZZ' })).toBe(enUS);
});
});