### Motivation While using the browser default locale is often good enough, we probably want more full control over locales, especially when we allow users to choose their own locale — it's a poor experience to not have dates and numbers formatted consistently with your chosen locale. ### Changes Ensures (almost) all instances of `<sl-format-date>` as well as `Intl.*` have the correct locale passed into them from our Lit localization system. The one exception here is in `frontend/src/utils/number.ts` where ordinal suffixes aren't localized, so the locale is hardcoded to `en` — I'll revisit this in the future.
37 lines
888 B
TypeScript
37 lines
888 B
TypeScript
/**
|
|
* Internationalized number formatter
|
|
* Usage:
|
|
* ```ts
|
|
* const formatter = numberFormatter()
|
|
* formatter.format(10000); // 10,000
|
|
* formatter.format(10, { ordinal: true }); // 10th
|
|
* ```
|
|
**/
|
|
export function numberFormatter(
|
|
locales?: string | string[],
|
|
opts?: Intl.NumberFormatOptions,
|
|
) {
|
|
const numFormat = new Intl.NumberFormat(locales, opts);
|
|
// TODO localize
|
|
const pluralRules = new Intl.PluralRules("en", { type: "ordinal" });
|
|
|
|
const suffixes = new Map<Intl.LDMLPluralRule, string>([
|
|
["one", "st"],
|
|
["two", "nd"],
|
|
["few", "rd"],
|
|
["other", "th"],
|
|
]);
|
|
|
|
const format = (n: number, opts: { ordinal?: boolean } = {}) => {
|
|
if (opts.ordinal) {
|
|
const rule = pluralRules.select(n);
|
|
const suffix = suffixes.get(rule);
|
|
return `${numFormat.format(n)}${suffix}`;
|
|
}
|
|
|
|
return numFormat.format(n);
|
|
};
|
|
|
|
return { format };
|
|
}
|