Skip to content

Commit 2147d17

Browse files
authored
Merge pull request #10 from cgjgh/main
2 parents 887cd3b + d59d860 commit 2147d17

File tree

9 files changed

+426
-12
lines changed

9 files changed

+426
-12
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"enhanced-ms": minor
3+
---
4+
5+
Add support for Polish, Czech, and Chinese (Simplified)

README.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,19 @@ As mentioned above, `enhanced-ms` is an enhanced version of the popular [`ms`](h
5050

5151
The currently supported languages include:
5252

53-
| Language | Key |
54-
| ----------------- | --- |
55-
| English (default) | en |
56-
| German | de |
57-
| Russian | ru |
58-
| Māori | mi |
59-
| Spanish | es |
60-
| Dutch | nl |
61-
| Italian | it |
62-
| French | fr |
53+
| Language | Key |
54+
| --------------------- | ----- |
55+
| English (default) | en |
56+
| German | de |
57+
| Russian | ru |
58+
| Māori | mi |
59+
| Spanish | es |
60+
| Dutch | nl |
61+
| Italian | it |
62+
| French | fr |
63+
| Czech | cs |
64+
| Polish | pl |
65+
| Chinese (Simplified) | zh-CN |
6366

6467
You can help by adding support for more languages.
6568

src/languages/cs.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
type Unit = keyof typeof UnitsMap;
2+
const UnitsMap = {
3+
nanosekundy: ['nanosekunda', 'nanosekundy', 'nanosekund'],
4+
mikrosekundy: ['mikrosekunda', 'mikrosekundy', 'mikrosekund'],
5+
milisekundy: ['milisekunda', 'milisekundy', 'milisekund'],
6+
sekundy: ['sekunda', 'sekundy', 'sekund'],
7+
minuty: ['minuta', 'minuty', 'minut'],
8+
hodiny: ['hodina', 'hodiny', 'hodin'],
9+
dny: ['den', 'dny', 'dní'],
10+
týdny: ['týden', 'týdny', 'týdnů'],
11+
měsíce: ['měsíc', 'měsíce', 'měsíců'],
12+
roky: ['rok', 'roky', 'let'],
13+
dekády: ['dekáda', 'dekády', 'dekád'],
14+
století: ['století', 'století', 'století'],
15+
tisíciletí: ['tisíciletí', 'tisíciletí', 'tisíciletí'],
16+
} as const;
17+
18+
function formatTime(unit: Unit, count: number) {
19+
const words = UnitsMap[unit];
20+
21+
let word: string;
22+
if (count === 1) word = words[0]!;
23+
else if (count >= 2 && count <= 4) word = words[1]!;
24+
else word = words[2]!;
25+
26+
return word || '';
27+
}
28+
29+
export default {
30+
decimal: ',',
31+
and: 'a',
32+
33+
units: {
34+
nanosecond: {
35+
name: (c) => formatTime('nanosekundy', c),
36+
abbreviation: 'ns',
37+
matches: ['ns', 'nanosekunda', 'nanosekundy', 'nanosekund'],
38+
},
39+
microsecond: {
40+
name: (c) => formatTime('mikrosekundy', c),
41+
abbreviation: 'μs',
42+
matches: ['μs', 'us', 'mikrosekunda', 'mikrosekundy', 'mikrosekund'],
43+
},
44+
millisecond: {
45+
name: (c) => formatTime('milisekundy', c),
46+
abbreviation: 'ms',
47+
matches: ['ms', 'milisekunda', 'milisekundy', 'milisekund'],
48+
},
49+
second: {
50+
name: (c) => formatTime('sekundy', c),
51+
abbreviation: 's',
52+
matches: ['s', 'sek', 'sekunda', 'sekundy', 'sekund'],
53+
},
54+
minute: {
55+
name: (c) => formatTime('minuty', c),
56+
abbreviation: 'min',
57+
matches: ['m', 'min', 'minuta', 'minuty', 'minut'],
58+
},
59+
hour: {
60+
name: (c) => formatTime('hodiny', c),
61+
abbreviation: 'h',
62+
matches: ['h', 'hod', 'hodina', 'hodiny', 'hodin'],
63+
},
64+
day: {
65+
name: (c) => formatTime('dny', c),
66+
abbreviation: 'd',
67+
matches: ['d', 'den', 'dny', 'dní'],
68+
},
69+
week: {
70+
name: (c) => formatTime('týdny', c),
71+
abbreviation: 'týd.',
72+
matches: ['w', 'týd', 'týden', 'týdny', 'týdnů'],
73+
},
74+
month: {
75+
name: (c) => formatTime('měsíce', c),
76+
abbreviation: 'měs.',
77+
matches: ['mo', 'měs', 'měsíc', 'měsíce', 'měsíců'],
78+
},
79+
year: {
80+
name: (c) => formatTime('roky', c),
81+
abbreviation: 'r.',
82+
matches: ['y', 'r', 'rok', 'roky', 'let'],
83+
},
84+
decade: {
85+
name: (c) => formatTime('dekády', c),
86+
abbreviation: 'dek.',
87+
matches: ['dek', 'dekáda', 'dekády', 'dekád'],
88+
},
89+
century: {
90+
name: (c) => formatTime('století', c),
91+
abbreviation: 'stol.',
92+
matches: ['c', 'stol', 'století'],
93+
},
94+
millennium: {
95+
name: (c) => formatTime('tisíciletí', c),
96+
abbreviation: 'tis.',
97+
matches: ['mil', 'tis', 'tisíciletí'],
98+
},
99+
},
100+
} satisfies import('./helpers/definition-types').LanguageDefinition;

src/languages/index.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
11
import type { LanguageDefinition } from './helpers/definition-types';
22

3+
import cs from './cs';
34
import de from './de';
45
import en from './en';
56
import es from './es';
67
import fr from './fr';
78
import it from './it';
89
import mi from './mi';
910
import nl from './nl';
11+
import pl from './pl';
1012
import ru from './ru';
13+
import zhCN from './zh-CN';
1114

1215
// This prevents the whole language definition being included in the dts output
13-
type Locale = 'de' | 'en' | 'es' | 'fr' | 'it' | 'mi' | 'nl' | 'ru';
16+
type Locale =
17+
| 'cs'
18+
| 'de'
19+
| 'en'
20+
| 'es'
21+
| 'fr'
22+
| 'it'
23+
| 'mi'
24+
| 'nl'
25+
| 'pl'
26+
| 'ru'
27+
| 'zh-CN';
1428
type Languages = Record<Locale, LanguageDefinition>;
15-
export const languages: Languages = { de, en, es, fr, it, mi, nl, ru };
29+
export const languages: Languages = {
30+
cs,
31+
de,
32+
en,
33+
es,
34+
fr,
35+
it,
36+
mi,
37+
nl,
38+
pl,
39+
ru,
40+
'zh-CN': zhCN,
41+
};

src/languages/pl.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
type Unit = keyof typeof UnitsMap;
2+
const UnitsMap = {
3+
nanosekundy: ['nanosekunda', 'nanosekundy', 'nanosekund'],
4+
mikrosekundy: ['mikrosekunda', 'mikrosekundy', 'mikrosekund'],
5+
milisekundy: ['milisekunda', 'milisekundy', 'milisekund'],
6+
sekundy: ['sekunda', 'sekundy', 'sekund'],
7+
minuty: ['minuta', 'minuty', 'minut'],
8+
godziny: ['godzina', 'godziny', 'godzin'],
9+
dni: ['dzień', 'dni', 'dni'],
10+
tygodnie: ['tydzień', 'tygodnie', 'tygodni'],
11+
miesiące: ['miesiąc', 'miesiące', 'miesięcy'],
12+
lata: ['rok', 'lata', 'lat'],
13+
dekady: ['dekada', 'dekady', 'dekad'],
14+
wieki: ['wiek', 'wieki', 'wieków'],
15+
tysiąclecia: ['tysiąclecie', 'tysiąclecia', 'tysiącleci'],
16+
} as const;
17+
18+
function formatTime(unit: Unit, count: number) {
19+
const words = UnitsMap[unit];
20+
21+
const lastDigit = count % 10;
22+
const lastTwoDigits = count % 100;
23+
24+
let word: string;
25+
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) word = words[2]!;
26+
else if (lastDigit === 1) word = words[0]!;
27+
else if (lastDigit >= 2 && lastDigit <= 4) word = words[1]!;
28+
else word = words[2]!;
29+
30+
return word || '';
31+
}
32+
33+
export default {
34+
decimal: ',',
35+
and: 'i',
36+
37+
units: {
38+
nanosecond: {
39+
name: (c) => formatTime('nanosekundy', c),
40+
abbreviation: 'ns',
41+
matches: ['ns', 'nanosekunda', 'nanosekundy', 'nanosekund'],
42+
},
43+
microsecond: {
44+
name: (c) => formatTime('mikrosekundy', c),
45+
abbreviation: 'μs',
46+
matches: ['μs', 'us', 'mikrosekunda', 'mikrosekundy', 'mikrosekund'],
47+
},
48+
millisecond: {
49+
name: (c) => formatTime('milisekundy', c),
50+
abbreviation: 'ms',
51+
matches: ['ms', 'milisekunda', 'milisekundy', 'milisekund'],
52+
},
53+
second: {
54+
name: (c) => formatTime('sekundy', c),
55+
abbreviation: 's',
56+
matches: ['s', 'sek', 'sekunda', 'sekundy', 'sekund'],
57+
},
58+
minute: {
59+
name: (c) => formatTime('minuty', c),
60+
abbreviation: 'min',
61+
matches: ['m', 'min', 'minuta', 'minuty', 'minut'],
62+
},
63+
hour: {
64+
name: (c) => formatTime('godziny', c),
65+
abbreviation: 'godz.',
66+
matches: ['h', 'godz', 'godzina', 'godziny', 'godzin'],
67+
},
68+
day: {
69+
name: (c) => formatTime('dni', c),
70+
abbreviation: 'd',
71+
matches: ['d', 'dzień', 'dni'],
72+
},
73+
week: {
74+
name: (c) => formatTime('tygodnie', c),
75+
abbreviation: 'tydz.',
76+
matches: ['w', 'tydz', 'tydzień', 'tygodnie', 'tygodni'],
77+
},
78+
month: {
79+
name: (c) => formatTime('miesiące', c),
80+
abbreviation: 'mies.',
81+
matches: ['mo', 'mies', 'miesiąc', 'miesiące', 'miesięcy'],
82+
},
83+
year: {
84+
name: (c) => formatTime('lata', c),
85+
abbreviation: 'r.',
86+
matches: ['y', 'r', 'rok', 'lata', 'lat'],
87+
},
88+
decade: {
89+
name: (c) => formatTime('dekady', c),
90+
abbreviation: 'dek.',
91+
matches: ['dek', 'dekada', 'dekady', 'dekad'],
92+
},
93+
century: {
94+
name: (c) => formatTime('wieki', c),
95+
abbreviation: 'w.',
96+
matches: ['c', 'wiek', 'wieki', 'wieków'],
97+
},
98+
millennium: {
99+
name: (c) => formatTime('tysiąclecia', c),
100+
abbreviation: 'tys.',
101+
matches: ['mil', 'tys', 'tysiąclecie', 'tysiąclecia', 'tysiącleci'],
102+
},
103+
},
104+
} satisfies import('./helpers/definition-types').LanguageDefinition;

src/languages/zh-CN.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
export default {
2+
decimal: '.',
3+
and: '和',
4+
units: {
5+
nanosecond: {
6+
name: '纳秒',
7+
abbreviation: 'ns',
8+
matches: ['纳秒', 'ns'],
9+
},
10+
microsecond: {
11+
name: '微秒',
12+
abbreviation: 'μs',
13+
matches: ['微秒', 'μs', 'us'],
14+
},
15+
millisecond: {
16+
name: '毫秒',
17+
abbreviation: 'ms',
18+
matches: ['毫秒', 'ms'],
19+
},
20+
second: {
21+
name: '秒',
22+
abbreviation: 's',
23+
matches: ['秒', 's'],
24+
},
25+
minute: {
26+
name: '分钟',
27+
abbreviation: '分',
28+
matches: ['分钟', '分', 'm', 'min'],
29+
},
30+
hour: {
31+
name: '小时',
32+
abbreviation: '时',
33+
matches: ['小时', '时', 'h', 'hour'],
34+
},
35+
day: {
36+
name: '天',
37+
abbreviation: '天',
38+
matches: ['天', '日', 'd', 'day'],
39+
},
40+
week: {
41+
name: '周',
42+
abbreviation: '周',
43+
matches: ['周', '星期', 'w', 'week'],
44+
},
45+
month: {
46+
name: '个月',
47+
abbreviation: '月',
48+
matches: ['个月', '月', 'mo', 'month'],
49+
},
50+
year: {
51+
name: '年',
52+
abbreviation: '年',
53+
matches: ['年', 'y', 'year'],
54+
},
55+
decade: {
56+
name: '十年',
57+
abbreviation: '十年',
58+
matches: ['十年', 'dec', 'decade'],
59+
},
60+
century: {
61+
name: '世纪',
62+
abbreviation: '世纪',
63+
matches: ['世纪', 'c', 'century'],
64+
},
65+
millennium: {
66+
name: '千年',
67+
abbreviation: '千年',
68+
matches: ['千年', 'mil', 'millennium'],
69+
},
70+
},
71+
} satisfies import('./helpers/definition-types').LanguageDefinition;

tests/cs.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { createMs } from 'enhanced-ms';
2+
import { describe, expect, it } from 'vitest';
3+
4+
const ms = createMs({ language: 'cs' });
5+
6+
describe('Czech (Čeština)', () => {
7+
describe('format milliseconds', () => {
8+
it('formats with correct pluralization', () => {
9+
// 1 second -> sekunda
10+
expect(ms(1000)).toBe('1 sekunda');
11+
// 2 seconds -> sekundy
12+
expect(ms(2000)).toBe('2 sekundy');
13+
// 4 seconds -> sekundy
14+
expect(ms(4000)).toBe('4 sekundy');
15+
// 5 seconds -> sekund
16+
expect(ms(5000)).toBe('5 sekund');
17+
});
18+
19+
it('formats with proper unit names', () => {
20+
// 1 day 2 hours 5 minutes
21+
const time = 86400000 + 2 * 3600000 + 5 * 60000;
22+
expect(ms(time)).toBe('1 den 2 hodiny 5 minut');
23+
});
24+
});
25+
26+
describe('parse duration', () => {
27+
it('parses Czech duration strings', () => {
28+
expect(ms('1 sekunda')).toBe(1000);
29+
expect(ms('2 sekundy')).toBe(2000);
30+
expect(ms('5 sekund')).toBe(5000);
31+
expect(ms('1 den 2 hodiny')).toBe(86400000 + 2 * 3600000);
32+
});
33+
});
34+
});

0 commit comments

Comments
 (0)