Agent Wranglers

Dates and numbers Recommended

Read numbers the way people type them

Read numbers and amounts in the user's locale, so 1 234,50 in Sweden and 1,234.50 in the US both mean the same amount. Never parse money as a floating-point number.

How to do it

Use a text input with inputmode="decimal", as mobile inputs explains, because type="number" drops input it can't read. Find the locale's group and decimal signs with the formatter. Accept any space where the group sign is a space. Check the groups are 3 digits, then remove them and swap the decimal sign for a dot. Send money as a decimal string or in minor units, as money requires. Reject ambiguous input instead of guessing.

Example

const escapeForRegExp = (sign: string) => sign.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

export function parseAmount(text: string, locale: string): string | null {
  const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);
  const group = parts.find(part => part.type === 'group')?.value ?? ',';
  const decimal = parts.find(part => part.type === 'decimal')?.value ?? '.';
  const input = /\s/.test(group) ? text.trim().replace(/\s/g, group) : text.trim();
  const shape = new RegExp(`^-?(\\d{1,3}(${escapeForRegExp(group)}\\d{3})*|\\d+)(${escapeForRegExp(decimal)}\\d+)?$`);
  return shape.test(input) ? input.replaceAll(group, '').replace(decimal, '.') : null;
}
import re
from decimal import Decimal
from babel import Locale
from babel.numbers import NumberFormatError, get_group_symbol, parse_decimal

def parse_amount(text: str, locale_tag: str) -> Decimal | None:
    locale = Locale.parse(locale_tag, sep="-")
    if get_group_symbol(locale).isspace():
        text = re.sub(r"\s", "", text)
    try:
        return parse_decimal(text, locale=locale, strict=True)
    except NumberFormatError:
        return None

How to check

Unit tests parse 1 234,50 in sv-SE, typed with a plain space, and 1,234.50 in en-US into the same value, 1234.50. The texts 12abc and, in en-US, 1.234,50 are rejected.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers app interface playbook: https://agentwranglers.se/playbook/app-ui/dates-and-numbers/locale-number-input.