73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import { LRUCache } from 'lru-cache'
|
|
|
|
import { injectI18n } from '../providers/i18n'
|
|
import { LOCALES } from './i18n.ts'
|
|
|
|
const formatterCache = new LRUCache<string, Intl.NumberFormat>({ max: 15 })
|
|
|
|
// `formatNumber(1234567)` → `1,234,567`
|
|
export function useFormatNumber() {
|
|
const { locale } = injectI18n()
|
|
|
|
function format(value: number | bigint): string {
|
|
const formatter = getStandardFormatter(locale.value)
|
|
return formatter!.format(value)
|
|
}
|
|
|
|
return format
|
|
}
|
|
|
|
// `formatCompactNumber(1234567)` → `1.23M`
|
|
//
|
|
// Use `formatCompactNumberPlural` over `{(here!), plural, one {...} other {...}}`
|
|
export function useCompactNumber() {
|
|
const { locale } = injectI18n()
|
|
|
|
function formatCompactNumber(value: number | bigint): string {
|
|
if (value < 10_000) {
|
|
const standardFormatter = getStandardFormatter(locale.value)
|
|
return standardFormatter.format(value)
|
|
}
|
|
if (value < 1_000_000) {
|
|
const oneDigitCompactFormatter = getCompactFormatter('en', 1)
|
|
return oneDigitCompactFormatter.format(value)
|
|
}
|
|
const twoDigitsCompactFormatter = getCompactFormatter('en', 2)
|
|
return twoDigitsCompactFormatter.format(value)
|
|
}
|
|
|
|
function formatCompactNumberPlural(value: number | bigint): number | bigint {
|
|
if (value < 10_000) {
|
|
return value
|
|
}
|
|
const currentLocale = locale.value
|
|
const localeDefinition = LOCALES.find((l) => l.code === currentLocale)
|
|
return localeDefinition?.compactNumberPlural ?? NaN
|
|
}
|
|
|
|
return { formatCompactNumber, formatCompactNumberPlural }
|
|
}
|
|
|
|
function getStandardFormatter(locale: string): Intl.NumberFormat {
|
|
const cacheKey = `${locale}:standard`
|
|
let formatter = formatterCache.get(cacheKey)
|
|
if (!formatter) {
|
|
formatter = new Intl.NumberFormat(locale)
|
|
formatterCache.set(cacheKey, formatter)
|
|
}
|
|
return formatter
|
|
}
|
|
|
|
function getCompactFormatter(locale: string, maximumFractionDigits: number): Intl.NumberFormat {
|
|
const cacheKey = `${locale}:compact:${maximumFractionDigits}`
|
|
let formatter = formatterCache.get(cacheKey)
|
|
if (!formatter) {
|
|
formatter = new Intl.NumberFormat(locale, {
|
|
notation: 'compact',
|
|
maximumFractionDigits,
|
|
})
|
|
formatterCache.set(cacheKey, formatter)
|
|
}
|
|
return formatter
|
|
}
|