Skip to content

Commit

Permalink
feat(iso-date-adapter): automatically lazy-load dayjs locales (#469)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
`NxIsoDateAdapter.setLocale` is now `async`.
  • Loading branch information
fischeversenker authored and GitHub Enterprise committed Jan 27, 2022
1 parent c87c0b6 commit 74fbbe1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 17 deletions.
2 changes: 0 additions & 2 deletions projects/ng-aquila/src/datefield/datefield.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ Momentjs ships with every locale thus significantly increasing the bundle size.

The ISO date adapter works solely with YYYY-MM-DD strings. Under the hood it uses dayjs to support formatting, parsing and localization. With this adapter you don't have to create a proper Date, Dayjs or Moment Object first to bind it with ngModel or reactive forms.

For localization you have to import the locales yourself. `en` is the default locale. To add e.g. german you use `import 'dayjs/locale/de'`.

Please install the `dayjs` package to use this adapter.

#### Native Date
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { convertToDayjsLocale } from './dayjs-locale-utils';
import { convertToDayjsLocale, getDayjsLocaleData } from './dayjs-locale-utils';

describe('dayjs locale utils', () => {
describe('convertToDayjsLocale', () => {
Expand Down Expand Up @@ -38,4 +38,30 @@ describe('dayjs locale utils', () => {
});
});
});

describe('getDayjsLocaleData', () => {
it('should return the localeData of the requested locale ("de")', async () => {
const deLocaleData = await getDayjsLocaleData('de');
// smoke testing a few of the properties of the 'de' locale
expect(deLocaleData.firstDayOfWeek()).toBe(1);
expect(deLocaleData.weekdaysMin()).toEqual(['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']);
expect(deLocaleData.monthsShort()).toEqual(['Jan', 'Feb', 'März', 'Apr', 'Mai', 'Juni', 'Juli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dez']);
});

it('should return the localeData of the requested locale ("es-us")', async () => {
const esUsLocaleData = await getDayjsLocaleData('es-us');
// smoke testing a few of the properties of the 'es-us' locale
expect(esUsLocaleData.firstDayOfWeek()).toBe(0);
expect(esUsLocaleData.weekdaysMin()).toEqual(['do', 'lu', 'ma', 'mi', 'ju', 'vi', 'sá']);
expect(esUsLocaleData.monthsShort()).toEqual(['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']);
});

it('should fall back to the global localeData for unknown locales', async () => {
const localeData = await getDayjsLocaleData('unknown');
// smoke testing a few of the properties of the global ('en') locale
expect(localeData.firstDayOfWeek()).toBe(0);
expect(localeData.weekdaysMin()).toEqual(['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']);
expect(localeData.monthsShort()).toEqual(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dayjs from 'dayjs';
import supportedLocales from 'dayjs/locale.json';

/**
Expand Down Expand Up @@ -33,3 +34,20 @@ export function convertToDayjsLocale(localeId: string): string {

return dayjsLocale.key;
}

/**
* This function uses a dynamic import to load the dayjs data for the requested locale
* and returns the localeData for this locale.
*
* @param localeId a "language-range" following the BCP 47 standard
* @returns a Promise that resolves with the dayjs localeData for the given locale
*/
export async function getDayjsLocaleData(localeId: string): Promise<dayjs.InstanceLocaleDataReturn> {
return import(`dayjs/locale/${localeId}`)
.then(() => dayjs().locale(localeId).localeData())
.catch(() => {
console.warn(`The requested dayjs locale '${localeId}' could not be loaded.`);
// return the global localeData as fallback
return dayjs.localeData();
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ describe('NxIsoDateAdapter', () => {
);

beforeEach(inject([NxDateAdapter], (dateAdapter: NxIsoDateAdapter) => {
dayjs.locale('en');
adapter = dateAdapter;
adapter.setLocale('en');

assertValidDate = (d: string | null, valid: boolean) => {
expect(adapter.isDateInstance(d)).not.toBeNull();
Expand All @@ -34,9 +32,8 @@ describe('NxIsoDateAdapter', () => {
}));

describe('Localization', () => {
beforeEach(() => {
adapter.setLocale('de');
dayjs.locale('de');
beforeEach(async () => {
await adapter.setLocale('de');
});

it('should parse locale date with explicit format', () => {
Expand All @@ -56,17 +53,17 @@ describe('NxIsoDateAdapter', () => {
});

describe('Localization with locale id that is unknown to dayjs', () => {
it('should automatically fall back to a locale that is known to dayjs', () => {
it('should automatically fall back to a locale that is known to dayjs', async () => {
// 'de-BY' is unknwon to dayjs (and the world). The IsoDateAdapter should fall back to 'de'.
adapter.setLocale('de-BY');
await adapter.setLocale('de-BY');
const date = adapter.parse('01.12.2020', 'MM.DD.YYYY', true);
expect(date).toBe('2020-01-12');
});
});

describe('Localization with a different format between global day.js and the adapter', () => {
beforeEach(() => {
adapter.setLocale('de');
beforeEach(async () => {
await adapter.setLocale('de');
dayjs.locale('en');
});

Expand Down Expand Up @@ -105,9 +102,9 @@ describe('NxIsoDateAdapter', () => {
assertValidDate(adapter.deserialize('2017-01-01'), true);
});

it('setLocale should not modify global moment locale', () => {
it('setLocale should not modify global moment locale', async () => {
expect(dayjs.locale()).toBe('en');
adapter.setLocale('de');
await adapter.setLocale('de');
expect(dayjs.locale()).toBe('en');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import localeData from 'dayjs/plugin/localeData';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import utc from 'dayjs/plugin/utc';

import { convertToDayjsLocale } from './dayjs-locale-utils';
import { convertToDayjsLocale, getDayjsLocaleData } from './dayjs-locale-utils';

dayjs.extend(localeData);
dayjs.extend(customParseFormat);
Expand Down Expand Up @@ -231,9 +231,9 @@ export class NxIsoDateAdapter extends NxDateAdapter<string> {
return this._localeData.narrowDaysOfWeek;
}

setLocale(locale: string) {
async setLocale(locale: string) {
this._dayjsLocale = convertToDayjsLocale(locale);
const data = dayjs().locale(this._dayjsLocale).localeData();
const data = await getDayjsLocaleData(this._dayjsLocale);

this._localeData = {
firstDayOfWeek: data.firstDayOfWeek(),
Expand Down

0 comments on commit 74fbbe1

Please sign in to comment.