Questions to answer:
- How does a numeric input handle locales?
- How can I determine the output?
- How can I change it?
Innocent questions but it's a wild ride.
Regarding input involved we're dealing with this standard: https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number)
Where the locale representation is not really defined. Browser vendors are only "encouraged". And the language can be detected either through given lang
attribute (on html or the input itself) or use the users's preferred locale. Whatever this now means.
Browsers are encouraged to use user interfaces that present dates, times, and numbers according to the conventions of either the locale implied by the input element's language or the user's preferred locale. Using the page's locale will ensure consistency with page-provided data.
Of course browsers have different interpretations of this and now we suffer from different representations depending on the combination of browser and language settings.
Environment:
- My OS is OSX v12.3, with the language set to English and the region to German (which brings the decimal separator config on the OS level)
- My browsers have all set English as the preferred language if possible.
- Firefox has the optiont to use the OS settings to format number disabled (tried that without reliable results so I pinned this)
I've prepared a codepen for analysis. There you'll find three inputs showing the value 555.55. The first input uses default language, the next tries to override it with en
and the third one tries to set de
. In addition I output a few values in the console from the Number.toLocaleString(), a related technology but not strictly bound to inputs. Find screenshots from the results attached to this gist.
The thing you will see is irritating.
-
Chrome render the input with the correct decimal separator. Its heuristic recognizes the German region. Chromes it ignores the
lang
attribute. The standard doesn't set this as a requirement, so standard-wise that's okay but takes the only option to influence the output. Surprisingly the detected language isen-GB
. So English with the regionGB
while I would have expecteden-DE
. -
Firefox uses a dot as the decimal separator. Its heuristic somehow recognizes English as the region. On the bright side, you can use
lang
to override it and a lang value ofde
convinces firefox to use a comma. Confusingly the language detected isen-DE
so Firefox must give the language (en
) a higher priority then the region (DE
) ? -
Safari Safari behaves the opposite of Chrome. Instead of commas dots all the way ignoring the lang values like Chrome but somehow identifying English the the correct locale. Similar to Chrome it finds
en-GB
and within those aspects it's more correct than Chrome. -
Edge (Windows) Not much surprising. Identical result to Chrome as it uses the same engine. The detected language are different as it's a virtual environment. The language of the OS is set to English but region is German. The detected language is
de
orde-DE
(using the datetimeformat resolver). The involved languages are almost opposites (en-GB
vsde-DE
) but the browsers show the same result: a comma. That's a sign that the browser uses a heuristic which doesn't expose its detected language through the involved apis (navigator
,resolveOptions
of intl)
The results are disturbing because the automatic heuristic of the browsers are different (Firefox & Safari yield a dot, while Chrome & Edge yield the command) and if that wouldn't be bad you can't reliable set/enforce the locale as lang
is only respected by Firefox.
If you look at the toLocaleString
outputs in the console you will see that the browsers yield different results too. That's kind of expected if you check the standards. Mozilla speaks of "language-sensitive" and tc39 of host environment locale whatever this means.
The toLocaleString() method of Number values returns a string with a language-sensitive representation of this number. Reference
Funny enough tc39
defines it a little bit more different using the words "current locale" whatever this means
This method produces a String value that represents this Number value formatted according to the conventions of the host environment's current locale.
The results:
Firefox: Input shows dot while toLocaleString
shows the comma. Contradicting results probably due to different heursistics. Worse the detetced language is en
but Firefox decides to output the command matching the region
. Doesn't fit the defention of being language-sensitive.
Chrome: Outputs a dot which is different from the input. The language-senstive part of the standard is adhered as the recongized language throug the navigator
is en
Safari: Same result as the input and fits the expectation language-sensitive
from the standard.
Edge: Outputs a comma which is the same as the input. Detected language is de
so it fits that part too.
That's it. It's a mess. I don't think that any production application that relies on proper localization can work without any form of workarounds