-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathi18n.js
More file actions
49 lines (46 loc) · 2.1 KB
/
Copy pathi18n.js
File metadata and controls
49 lines (46 loc) · 2.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
export function createMessageFormatter(catalog, getLocale, fallbackLocale = 'en') {
const fallback = catalog[fallbackLocale];
if (!fallback) throw new Error(`Missing fallback locale: ${fallbackLocale}`);
const fallbackKeys = Object.keys(fallback).sort();
for (const [locale, messages] of Object.entries(catalog)) {
const missing = fallbackKeys.filter(key => !(key in messages));
const extra = Object.keys(messages).filter(key => !(key in fallback)).sort();
if (missing.length || extra.length) {
const details = [
missing.length ? `missing: ${missing.join(', ')}` : '',
extra.length ? `extra: ${extra.join(', ')}` : ''
].filter(Boolean).join('; ');
throw new Error(`${locale} message catalog mismatch (${details})`);
}
}
const locale = () => (catalog[getLocale()] ? getLocale() : fallbackLocale);
const interpolate = (template, variables) => Object.entries(variables).reduce(
(value, [name, replacement]) => value.replaceAll(`{${name}}`, String(replacement)),
template
);
function message(key, variables = {}) {
const activeLocale = locale();
let resolvedKey = key;
if (Number.isFinite(Number(variables.count))) {
const category = new Intl.PluralRules(activeLocale).select(Number(variables.count));
if (`${key}_${category}` in fallback) resolvedKey = `${key}_${category}`;
}
const template = catalog[activeLocale][resolvedKey] ?? fallback[resolvedKey];
if (template === undefined) throw new Error(`Unknown message key: ${resolvedKey}`);
return interpolate(template, variables);
}
return Object.freeze({
locale,
message,
number: (value, options = {}) => new Intl.NumberFormat(locale(), options).format(value),
date(value, options = {}) {
const date = value instanceof Date ? value : new Date(value);
return Number.isFinite(date.getTime()) ? new Intl.DateTimeFormat(locale(), options).format(date) : '';
},
unit: (value, unit, options = {}) => new Intl.NumberFormat(
locale(),
{ style: 'unit', unit, ...options }
).format(value),
keys: Object.freeze(fallbackKeys)
});
}