Skip to content

Commit 043106c

Browse files
author
Mikhail Bashkirov
committed
feat(localize): add reusable generators for month and weekday names
1 parent 97fe0f0 commit 043106c

File tree

5 files changed

+166
-0
lines changed

5 files changed

+166
-0
lines changed

packages/localize/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export { formatDate } from './src/date/formatDate.js';
22
export { getDateFormatBasedOnLocale } from './src/date/getDateFormatBasedOnLocale.js';
3+
export { getMonthNames } from './src/date/getMonthNames.js';
4+
export { getWeekdayNames } from './src/date/getWeekdayNames.js';
35
export { parseDate } from './src/date/parseDate.js';
46
export {
57
formatNumber,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { normalizeDate } from './normalizeDate.js';
2+
3+
const monthsLocaleCache = {};
4+
5+
export function getMonthNames({ locale }) {
6+
let months = monthsLocaleCache[locale];
7+
8+
if (months) {
9+
return months;
10+
}
11+
12+
months = [];
13+
14+
const formatter = new Intl.DateTimeFormat(locale, { month: 'long' });
15+
for (let i = 0; i < 12; i += 1) {
16+
const date = new Date(2019, i, 1);
17+
const formattedDate = formatter.format(date);
18+
const normalizedDate = normalizeDate(formattedDate);
19+
months.push(normalizedDate);
20+
}
21+
22+
monthsLocaleCache[locale] = months;
23+
24+
return months;
25+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { normalizeDate } from './normalizeDate.js';
2+
3+
const weekdayNamesCache = {};
4+
5+
/**
6+
* @desc Return cached weekday names for locale for all styles ('long', 'short', 'narrow')
7+
* @param {string} locale locale
8+
* @returns {Object} like { long: ['Sunday', 'Monday'...], short: ['Sun', ...], narrow: ['S', ...] }
9+
*/
10+
function getCachedWeekdayNames(locale) {
11+
let weekdays = weekdayNamesCache[locale];
12+
13+
if (weekdays) {
14+
return weekdays;
15+
}
16+
17+
weekdayNamesCache[locale] = { long: [], short: [], narrow: [] };
18+
19+
['long', 'short', 'narrow'].forEach(style => {
20+
weekdays = weekdayNamesCache[locale][style];
21+
const formatter = new Intl.DateTimeFormat(locale, { weekday: style });
22+
23+
const date = new Date('2019/04/07'); // start from Sunday
24+
for (let i = 0; i < 7; i += 1) {
25+
const weekday = formatter.format(date);
26+
const normalizedWeekday = normalizeDate(weekday);
27+
weekdays.push(normalizedWeekday);
28+
date.setDate(date.getDate() + 1);
29+
}
30+
});
31+
32+
return weekdayNamesCache[locale];
33+
}
34+
35+
// TODO: consider using a database with information for the `firstDayOfWeek`?
36+
// https://github.com/unicode-cldr/cldr-core/blob/35.0.0/supplemental/weekData.json#L60
37+
// https://github.com/tc39/ecma402/issues/6#issuecomment-114079502
38+
39+
/**
40+
* @desc Returns weekday names for locale
41+
* @param {string} options.locale locale
42+
* @param {string} [options.style=long] long, short or narrow
43+
* @param {number} [options.firstDayOfWeek=0] 0 (Sunday), 1 (Monday), etc...
44+
* @returns {Array} like: ['Sunday', 'Monday', 'Tuesday', ...etc].
45+
*/
46+
export function getWeekdayNames({ locale, style = 'long', firstDayOfWeek = 0 } = {}) {
47+
const weekdays = getCachedWeekdayNames(locale)[style];
48+
const orderedWeekdays = [];
49+
for (let i = firstDayOfWeek; i < firstDayOfWeek + 7; i += 1) {
50+
orderedWeekdays.push(weekdays[i % 7]);
51+
}
52+
return orderedWeekdays;
53+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { expect } from '@open-wc/testing';
2+
3+
import { getMonthNames } from '../../src/date/getMonthNames.js';
4+
5+
function s(strings) {
6+
return strings[0].split(' ');
7+
}
8+
9+
describe('getMonthNames', () => {
10+
it('generates month names for a given locale', () => {
11+
expect(getMonthNames({ locale: 'en-GB' })).to.deep.equal(
12+
s`January February March April May June July August September October November December`,
13+
);
14+
expect(getMonthNames({ locale: 'nl-NL' })).to.deep.equal(
15+
s`januari februari maart april mei juni juli augustus september oktober november december`,
16+
);
17+
expect(getMonthNames({ locale: 'zh-CH' })).to.deep.equal(
18+
s`一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月`,
19+
);
20+
});
21+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { expect } from '@open-wc/testing';
2+
3+
import { getWeekdayNames } from '../../src/date/getWeekdayNames.js';
4+
5+
function s(strings) {
6+
return strings[0].split(' ');
7+
}
8+
9+
describe('getWeekdayNames', () => {
10+
it('generates weekday names for a given locale with defaults (from Sunday, long style)', () => {
11+
expect(getWeekdayNames({ locale: 'en-GB' })).to.deep.equal(
12+
s`Sunday Monday Tuesday Wednesday Thursday Friday Saturday`,
13+
);
14+
expect(getWeekdayNames({ locale: 'nl-NL' })).to.deep.equal(
15+
s`zondag maandag dinsdag woensdag donderdag vrijdag zaterdag`,
16+
);
17+
expect(getWeekdayNames({ locale: 'zh-CH' })).to.deep.equal(
18+
s`星期日 星期一 星期二 星期三 星期四 星期五 星期六`,
19+
);
20+
});
21+
22+
it('allows to specify a day when a week starts', () => {
23+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 7 })).to.deep.equal(
24+
s`Sunday Monday Tuesday Wednesday Thursday Friday Saturday`,
25+
);
26+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 1 })).to.deep.equal(
27+
s`Monday Tuesday Wednesday Thursday Friday Saturday Sunday`,
28+
);
29+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 2 })).to.deep.equal(
30+
s`Tuesday Wednesday Thursday Friday Saturday Sunday Monday`,
31+
);
32+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 3 })).to.deep.equal(
33+
s`Wednesday Thursday Friday Saturday Sunday Monday Tuesday`,
34+
);
35+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 4 })).to.deep.equal(
36+
s`Thursday Friday Saturday Sunday Monday Tuesday Wednesday`,
37+
);
38+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 5 })).to.deep.equal(
39+
s`Friday Saturday Sunday Monday Tuesday Wednesday Thursday`,
40+
);
41+
expect(getWeekdayNames({ locale: 'en-GB', firstDayOfWeek: 6 })).to.deep.equal(
42+
s`Saturday Sunday Monday Tuesday Wednesday Thursday Friday`,
43+
);
44+
});
45+
46+
it('supports "short" style', () => {
47+
expect(getWeekdayNames({ locale: 'en-GB', style: 'short' })).to.deep.equal(
48+
s`Sun Mon Tue Wed Thu Fri Sat`,
49+
);
50+
expect(getWeekdayNames({ locale: 'nl-NL', style: 'short' })).to.deep.equal(
51+
s`zo ma di wo do vr za`,
52+
);
53+
expect(getWeekdayNames({ locale: 'zh-CH', style: 'short' })).to.deep.equal(
54+
s`周日 周一 周二 周三 周四 周五 周六`,
55+
);
56+
});
57+
58+
it('supports "narrow" style', () => {
59+
expect(getWeekdayNames({ locale: 'en-GB', style: 'narrow' })).to.deep.equal(s`S M T W T F S`);
60+
expect(getWeekdayNames({ locale: 'nl-NL', style: 'narrow' })).to.deep.equal(s`Z M D W D V Z`);
61+
expect(getWeekdayNames({ locale: 'zh-CH', style: 'narrow' })).to.deep.equal(
62+
s`日 一 二 三 四 五 六`,
63+
);
64+
});
65+
});

0 commit comments

Comments
 (0)