---
title: "Read numbers the way people type them · Agent Wranglers"
url: https://agentwranglers.se/playbook/app-ui/dates-and-numbers/locale-number-input
updated: 2026-10-20
licence: "All rights reserved"
---

# Read numbers the way people type them

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [Dates and numbers](https://agentwranglers.se/playbook/app-ui/dates-and-numbers)
- Rule: 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: Use a text input with `inputmode="decimal"`, as [mobile inputs](https://agentwranglers.se/playbook/website/accessibility/mobile-form-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](https://agentwranglers.se/playbook/api-design/requests-and-responses/money) requires. Reject ambiguous input instead of guessing.
- 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.

Example:

```ts
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;
}
```

```python
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
```

**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`.

- Previous: [Show relative times with the exact time beside them](https://agentwranglers.se/playbook/app-ui/dates-and-numbers/relative-times)
- [Dates and numbers](https://agentwranglers.se/playbook/app-ui/dates-and-numbers)
