Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/gorgeous-numbers-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"enhanced-ms": minor
---

Add support for Polish, Czech, and Chinese (Simplified)
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,19 @@ As mentioned above, `enhanced-ms` is an enhanced version of the popular [`ms`](h

The currently supported languages include:

| Language | Key |
| ----------------- | --- |
| English (default) | en |
| German | de |
| Russian | ru |
| Māori | mi |
| Spanish | es |
| Dutch | nl |
| Italian | it |
| French | fr |
| Language | Key |
| --------------------- | ----- |
| English (default) | en |
| German | de |
| Russian | ru |
| Māori | mi |
| Spanish | es |
| Dutch | nl |
| Italian | it |
| French | fr |
| Czech | cs |
| Polish | pl |
| Chinese (Simplified) | zh-CN |

You can help by adding support for more languages.

Expand Down
100 changes: 100 additions & 0 deletions src/languages/cs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
type Unit = keyof typeof UnitsMap;
const UnitsMap = {
nanosekundy: ['nanosekunda', 'nanosekundy', 'nanosekund'],
mikrosekundy: ['mikrosekunda', 'mikrosekundy', 'mikrosekund'],
milisekundy: ['milisekunda', 'milisekundy', 'milisekund'],
sekundy: ['sekunda', 'sekundy', 'sekund'],
minuty: ['minuta', 'minuty', 'minut'],
hodiny: ['hodina', 'hodiny', 'hodin'],
dny: ['den', 'dny', 'dní'],
týdny: ['týden', 'týdny', 'týdnů'],
měsíce: ['měsíc', 'měsíce', 'měsíců'],
roky: ['rok', 'roky', 'let'],
dekády: ['dekáda', 'dekády', 'dekád'],
století: ['století', 'století', 'století'],
tisíciletí: ['tisíciletí', 'tisíciletí', 'tisíciletí'],
} as const;

function formatTime(unit: Unit, count: number) {
const words = UnitsMap[unit];

let word: string;
if (count === 1) word = words[0]!;
else if (count >= 2 && count <= 4) word = words[1]!;
else word = words[2]!;

return word || '';
}

export default {
decimal: ',',
and: 'a',

units: {
nanosecond: {
name: (c) => formatTime('nanosekundy', c),
abbreviation: 'ns',
matches: ['ns', 'nanosekunda', 'nanosekundy', 'nanosekund'],
},
microsecond: {
name: (c) => formatTime('mikrosekundy', c),
abbreviation: 'μs',
matches: ['μs', 'us', 'mikrosekunda', 'mikrosekundy', 'mikrosekund'],
},
millisecond: {
name: (c) => formatTime('milisekundy', c),
abbreviation: 'ms',
matches: ['ms', 'milisekunda', 'milisekundy', 'milisekund'],
},
second: {
name: (c) => formatTime('sekundy', c),
abbreviation: 's',
matches: ['s', 'sek', 'sekunda', 'sekundy', 'sekund'],
},
minute: {
name: (c) => formatTime('minuty', c),
abbreviation: 'min',
matches: ['m', 'min', 'minuta', 'minuty', 'minut'],
},
hour: {
name: (c) => formatTime('hodiny', c),
abbreviation: 'h',
matches: ['h', 'hod', 'hodina', 'hodiny', 'hodin'],
},
day: {
name: (c) => formatTime('dny', c),
abbreviation: 'd',
matches: ['d', 'den', 'dny', 'dní'],
},
week: {
name: (c) => formatTime('týdny', c),
abbreviation: 'týd.',
matches: ['w', 'týd', 'týden', 'týdny', 'týdnů'],
},
month: {
name: (c) => formatTime('měsíce', c),
abbreviation: 'měs.',
matches: ['mo', 'měs', 'měsíc', 'měsíce', 'měsíců'],
},
year: {
name: (c) => formatTime('roky', c),
abbreviation: 'r.',
matches: ['y', 'r', 'rok', 'roky', 'let'],
},
decade: {
name: (c) => formatTime('dekády', c),
abbreviation: 'dek.',
matches: ['dek', 'dekáda', 'dekády', 'dekád'],
},
century: {
name: (c) => formatTime('století', c),
abbreviation: 'stol.',
matches: ['c', 'stol', 'století'],
},
millennium: {
name: (c) => formatTime('tisíciletí', c),
abbreviation: 'tis.',
matches: ['mil', 'tis', 'tisíciletí'],
},
},
} satisfies import('./helpers/definition-types').LanguageDefinition;
30 changes: 28 additions & 2 deletions src/languages/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
import type { LanguageDefinition } from './helpers/definition-types';

import cs from './cs';
import de from './de';
import en from './en';
import es from './es';
import fr from './fr';
import it from './it';
import mi from './mi';
import nl from './nl';
import pl from './pl';
import ru from './ru';
import zhCN from './zh-CN';

// This prevents the whole language definition being included in the dts output
type Locale = 'de' | 'en' | 'es' | 'fr' | 'it' | 'mi' | 'nl' | 'ru';
type Locale =
| 'cs'
| 'de'
| 'en'
| 'es'
| 'fr'
| 'it'
| 'mi'
| 'nl'
| 'pl'
| 'ru'
| 'zh-CN';
type Languages = Record<Locale, LanguageDefinition>;
export const languages: Languages = { de, en, es, fr, it, mi, nl, ru };
export const languages: Languages = {
cs,
de,
en,
es,
fr,
it,
mi,
nl,
pl,
ru,
'zh-CN': zhCN,
};
104 changes: 104 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
type Unit = keyof typeof UnitsMap;
const UnitsMap = {
nanosekundy: ['nanosekunda', 'nanosekundy', 'nanosekund'],
mikrosekundy: ['mikrosekunda', 'mikrosekundy', 'mikrosekund'],
milisekundy: ['milisekunda', 'milisekundy', 'milisekund'],
sekundy: ['sekunda', 'sekundy', 'sekund'],
minuty: ['minuta', 'minuty', 'minut'],
godziny: ['godzina', 'godziny', 'godzin'],
dni: ['dzień', 'dni', 'dni'],
tygodnie: ['tydzień', 'tygodnie', 'tygodni'],
miesiące: ['miesiąc', 'miesiące', 'miesięcy'],
lata: ['rok', 'lata', 'lat'],
dekady: ['dekada', 'dekady', 'dekad'],
wieki: ['wiek', 'wieki', 'wieków'],
tysiąclecia: ['tysiąclecie', 'tysiąclecia', 'tysiącleci'],
} as const;

function formatTime(unit: Unit, count: number) {
const words = UnitsMap[unit];

const lastDigit = count % 10;
const lastTwoDigits = count % 100;

let word: string;
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) word = words[2]!;
else if (lastDigit === 1) word = words[0]!;
else if (lastDigit >= 2 && lastDigit <= 4) word = words[1]!;
else word = words[2]!;

return word || '';
}

export default {
decimal: ',',
and: 'i',

units: {
nanosecond: {
name: (c) => formatTime('nanosekundy', c),
abbreviation: 'ns',
matches: ['ns', 'nanosekunda', 'nanosekundy', 'nanosekund'],
},
microsecond: {
name: (c) => formatTime('mikrosekundy', c),
abbreviation: 'μs',
matches: ['μs', 'us', 'mikrosekunda', 'mikrosekundy', 'mikrosekund'],
},
millisecond: {
name: (c) => formatTime('milisekundy', c),
abbreviation: 'ms',
matches: ['ms', 'milisekunda', 'milisekundy', 'milisekund'],
},
second: {
name: (c) => formatTime('sekundy', c),
abbreviation: 's',
matches: ['s', 'sek', 'sekunda', 'sekundy', 'sekund'],
},
minute: {
name: (c) => formatTime('minuty', c),
abbreviation: 'min',
matches: ['m', 'min', 'minuta', 'minuty', 'minut'],
},
hour: {
name: (c) => formatTime('godziny', c),
abbreviation: 'godz.',
matches: ['h', 'godz', 'godzina', 'godziny', 'godzin'],
},
day: {
name: (c) => formatTime('dni', c),
abbreviation: 'd',
matches: ['d', 'dzień', 'dni'],
},
week: {
name: (c) => formatTime('tygodnie', c),
abbreviation: 'tydz.',
matches: ['w', 'tydz', 'tydzień', 'tygodnie', 'tygodni'],
},
month: {
name: (c) => formatTime('miesiące', c),
abbreviation: 'mies.',
matches: ['mo', 'mies', 'miesiąc', 'miesiące', 'miesięcy'],
},
year: {
name: (c) => formatTime('lata', c),
abbreviation: 'r.',
matches: ['y', 'r', 'rok', 'lata', 'lat'],
},
decade: {
name: (c) => formatTime('dekady', c),
abbreviation: 'dek.',
matches: ['dek', 'dekada', 'dekady', 'dekad'],
},
century: {
name: (c) => formatTime('wieki', c),
abbreviation: 'w.',
matches: ['c', 'wiek', 'wieki', 'wieków'],
},
millennium: {
name: (c) => formatTime('tysiąclecia', c),
abbreviation: 'tys.',
matches: ['mil', 'tys', 'tysiąclecie', 'tysiąclecia', 'tysiącleci'],
},
},
} satisfies import('./helpers/definition-types').LanguageDefinition;
71 changes: 71 additions & 0 deletions src/languages/zh-CN.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
export default {
decimal: '.',
and: '和',
units: {
nanosecond: {
name: '纳秒',
abbreviation: 'ns',
matches: ['纳秒', 'ns'],
},
microsecond: {
name: '微秒',
abbreviation: 'μs',
matches: ['微秒', 'μs', 'us'],
},
millisecond: {
name: '毫秒',
abbreviation: 'ms',
matches: ['毫秒', 'ms'],
},
second: {
name: '秒',
abbreviation: 's',
matches: ['秒', 's'],
},
minute: {
name: '分钟',
abbreviation: '分',
matches: ['分钟', '分', 'm', 'min'],
},
hour: {
name: '小时',
abbreviation: '时',
matches: ['小时', '时', 'h', 'hour'],
},
day: {
name: '天',
abbreviation: '天',
matches: ['天', '日', 'd', 'day'],
},
week: {
name: '周',
abbreviation: '周',
matches: ['周', '星期', 'w', 'week'],
},
month: {
name: '个月',
abbreviation: '月',
matches: ['个月', '月', 'mo', 'month'],
},
year: {
name: '年',
abbreviation: '年',
matches: ['年', 'y', 'year'],
},
decade: {
name: '十年',
abbreviation: '十年',
matches: ['十年', 'dec', 'decade'],
},
century: {
name: '世纪',
abbreviation: '世纪',
matches: ['世纪', 'c', 'century'],
},
millennium: {
name: '千年',
abbreviation: '千年',
matches: ['千年', 'mil', 'millennium'],
},
},
} satisfies import('./helpers/definition-types').LanguageDefinition;
34 changes: 34 additions & 0 deletions tests/cs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createMs } from 'enhanced-ms';
import { describe, expect, it } from 'vitest';

const ms = createMs({ language: 'cs' });

describe('Czech (Čeština)', () => {
describe('format milliseconds', () => {
it('formats with correct pluralization', () => {
// 1 second -> sekunda
expect(ms(1000)).toBe('1 sekunda');
// 2 seconds -> sekundy
expect(ms(2000)).toBe('2 sekundy');
// 4 seconds -> sekundy
expect(ms(4000)).toBe('4 sekundy');
// 5 seconds -> sekund
expect(ms(5000)).toBe('5 sekund');
});

it('formats with proper unit names', () => {
// 1 day 2 hours 5 minutes
const time = 86400000 + 2 * 3600000 + 5 * 60000;
expect(ms(time)).toBe('1 den 2 hodiny 5 minut');
});
});

describe('parse duration', () => {
it('parses Czech duration strings', () => {
expect(ms('1 sekunda')).toBe(1000);
expect(ms('2 sekundy')).toBe(2000);
expect(ms('5 sekund')).toBe(5000);
expect(ms('1 den 2 hodiny')).toBe(86400000 + 2 * 3600000);
});
});
});
Loading
Loading