MapComplete/src/UI/InputElement/Validators/CurrencyValidator.ts

75 lines
2.4 KiB
TypeScript

import { Validator } from "../Validator"
import { Utils } from "../../../Utils"
export default class CurrencyValidator extends Validator {
private readonly segmenter: Intl.Segmenter
private readonly symbolToCurrencyMapping: Map<string, string>
private readonly supportedCurrencies: Set<string>
constructor() {
super("currency", "Validates monetary amounts")
if (Intl.Segmenter === undefined || Utils.runningFromConsole) {
// Librewolf doesn't support this
return
}
let locale = "en-US"
if (!Utils.runningFromConsole) {
locale ??= navigator.language
}
this.segmenter = new Intl.Segmenter(locale, {
granularity: "word",
})
const mapping: Map<string, string> = new Map<string, string>()
const supportedCurrencies: Set<string> = new Set(Intl.supportedValuesOf("currency"))
this.supportedCurrencies = supportedCurrencies
for (const currency of supportedCurrencies) {
const symbol = (0)
.toLocaleString(locale, {
style: "currency",
currency: currency,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})
.replace(/\d/g, "")
.trim()
mapping.set(symbol.toLowerCase(), currency)
}
this.symbolToCurrencyMapping = mapping
}
reformat(s: string): string {
if (!this.segmenter) {
return s
}
const parts = Array.from(this.segmenter.segment(s))
.map((i) => i.segment)
.filter((part) => part.trim().length > 0)
if (parts.length !== 2) {
return s
}
const mapping = this.symbolToCurrencyMapping
let currency: string = undefined
let amount = undefined
for (const part of parts) {
const lc = part.toLowerCase()
if (this.supportedCurrencies.has(part.toUpperCase())) {
currency = part.toUpperCase()
continue
}
if (mapping.has(lc)) {
currency = mapping.get(lc)
continue
}
amount = part
}
if (amount === undefined || currency === undefined) {
return s
}
return amount + " " + currency
}
}