You should not tell a number field how its locale writes numbers. It asks the platform, then reads its own writing back.
That is the rule we settled on in amountfield, our open-source money input.
The mechanics:
separatorsFor builds one record (decimal, group, digits, minus) entirely from Intl. Decimal and group come out of NumberFormat formatToParts. The ten digits come from formatting 0 through 9 with a formatter that has useGrouping off. The minus comes from the minusSign part of formatToParts(-1).
Every one of those values then passes through withoutBidi. Intl emits directional marks around a number in right-to-left text. They are invisible, they are not digits, and they quietly break string comparison. So we strip them at the boundary, once, instead of handling them everywhere downstream.
We keep the digit set only if those ten formats come back as ten single characters. Otherwise it falls back to ASCII digits. A numbering system whose digits are not one character each would make a character-by-character mapping misread an amount rather than reject it, and silently misreading money is worse than refusing to read it.
asciiNumerals is what puts input into the form the rules actually read: no bidi marks, the locale's minus rewritten as the ASCII one, the locale's digits mapped onto ASCII, ASCII digits left alone. parse and isIncomplete both call it first. So the sign test, the whitespace-to-group rewrite and the grouping rule only ever run on ASCII, one alphabet with one set of rules. Digits from a numbering system we did not teach it stay unmapped and fall out as not-a-number. Refused, not guessed.
The field layer is deliberately different. sanitise drops bidi marks and folds the locale's minus, but leaves the digits exactly as typed, because people should see their own writing in the box. That is why meaningful counts locale.minus and locale.digits as characters worth keeping, and why caretAfter holds the caret on them.
The part worth stealing: whatever writes your value should be the same source that teaches you to read it. Hard-coded separator tables are where locale bugs live, and they drift from the platform the moment a user picks a locale nobody on the team tested.
Where the line sits between normalising messy input and rejecting it outright is something we still argue about internally.