Skip to content

Commit 8855c86

Browse files
committed
feat: add factory method for locale aware formatter
1 parent 6794b6a commit 8855c86

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

src/format/formatters.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { createFormatters } from './formatters';
3+
4+
describe('createFormatters', () => {
5+
it('binds the given locale by default', () => {
6+
const fmt = createFormatters('de-DE');
7+
expect(fmt.formatNumber(1234567)).toBe('1.234.567');
8+
expect(fmt.formatCompact(1200)).toBe('1200');
9+
});
10+
11+
it('formats dates and currency in the bound locale', () => {
12+
const fmt = createFormatters('de-DE');
13+
expect(fmt.formatDate('2026-06-19')).toBe('19.6.2026');
14+
expect(fmt.formatCurrency(1234.5, { currency: 'EUR' })).toMatch(/1\.234,50/);
15+
});
16+
17+
it('formats relative time in the bound locale', () => {
18+
const fmt = createFormatters('de-DE');
19+
const now = new Date('2026-06-19T12:00:00Z');
20+
expect(fmt.formatRelative(new Date('2026-06-19T09:00:00Z'), { now })).toMatch(/Stunden/);
21+
});
22+
23+
it('allows overriding the locale per call', () => {
24+
const fmt = createFormatters('de-DE');
25+
// fr-CH uses U+202F (narrow no-break space) as thousands separator
26+
expect(fmt.formatNumber(1234567, { locale: 'fr-CH' })).toBe('1 234 567');
27+
});
28+
29+
it('is independent across instances (no shared state)', () => {
30+
const de = createFormatters('de-DE');
31+
const fr = createFormatters('fr-CH');
32+
expect(de.formatNumber(1234567)).toBe('1.234.567');
33+
expect(fr.formatNumber(1234567)).toBe('1 234 567');
34+
});
35+
});

src/format/formatters.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { formatDate, formatTime, formatDateTime, formatRelative } from './date';
2+
import { formatNumber, formatCompact, formatCurrency, formatPercent } from './number';
3+
4+
/**
5+
* Returns the locale-aware `format*` functions pre-bound to `locale`, so call sites
6+
* don't need to repeat `{ locale }` on every call. Each returned function still accepts
7+
* its normal options and can override the locale per-call if needed. Stateless: safe to
8+
* call once per request/component, no shared state across concurrent calls.
9+
*/
10+
export function createFormatters(locale: string) {
11+
return {
12+
formatDate: (input: Parameters<typeof formatDate>[0], options: Parameters<typeof formatDate>[1] = {}) =>
13+
formatDate(input, { locale, ...options }),
14+
15+
formatTime: (input: Parameters<typeof formatTime>[0], options: Parameters<typeof formatTime>[1] = {}) =>
16+
formatTime(input, { locale, ...options }),
17+
18+
formatDateTime: (input: Parameters<typeof formatDateTime>[0], options: Parameters<typeof formatDateTime>[1] = {}) =>
19+
formatDateTime(input, { locale, ...options }),
20+
21+
formatRelative: (input: Parameters<typeof formatRelative>[0], options: Parameters<typeof formatRelative>[1] = {}) =>
22+
formatRelative(input, { locale, ...options }),
23+
24+
formatNumber: (value: Parameters<typeof formatNumber>[0], options: Parameters<typeof formatNumber>[1] = {}) =>
25+
formatNumber(value, { locale, ...options }),
26+
27+
formatCompact: (value: Parameters<typeof formatCompact>[0], options: Parameters<typeof formatCompact>[1] = {}) =>
28+
formatCompact(value, { locale, ...options }),
29+
30+
formatCurrency: (value: Parameters<typeof formatCurrency>[0], options: Parameters<typeof formatCurrency>[1] = {}) =>
31+
formatCurrency(value, { locale, ...options }),
32+
33+
formatPercent: (value: Parameters<typeof formatPercent>[0], options: Parameters<typeof formatPercent>[1] = {}) =>
34+
formatPercent(value, { locale, ...options }),
35+
};
36+
}

src/format/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './number';
22
export * from './date';
33
export * from './duration';
44
export * from './swiss';
5+
export * from './formatters';

0 commit comments

Comments
 (0)