Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localize numbers in numeric fields #8769

Merged
merged 14 commits into from
May 26, 2023
Merged

Conversation

1ec5
Copy link
Collaborator

@1ec5 1ec5 commented Oct 26, 2021

Fields of type number, roadheight, and roadspeed now interpret their input as a number or semicolon-delimited list of numbers according to the UI language. If the input value can’t be parsed as a localized number, the field falls back to the raw value verbatim. Regardless of how the field displays its value, it always outputs tag values containing numbers in English/POSIX format for consistency with OSM tagging conventions.


Width field in English


Width field in Vietnamese


Width field in Arabic


Max Height in Vietnamese

roadspeed-type fields contain combo boxes with suggested values, which are now localized:


Speed Limit field in Arabic

When using a locale that uses non-European numerals, such as Arabic, you can enter the value using European digits. The numerals are converted into localized digits on the fly as you type.

Ideally, this PR would be nothing more than changing the <input> tag’s type attribute to number instead of text. (In fact, there’s a number input box in the Issues panel and it works great.)

input.attr('type', 'text');

However, browsers such as Firefox are a bit too strict about what can go into a number input box. If a feature is tagged maxheight=below_default or direction=0;180, the built-in number field would be blank. So instead, I’ve attempted to emulate the built-in behavior.

For languages that use non-English number formats, translated placeholders defined in id-tagging-schema should be updated to use the localized number format instead of an English/POSIX number format.

Fixes #3615.

@1ec5 1ec5 added localization Adapting iD across languages, regions, and cultures field An issue with a field in the user interface labels Oct 26, 2021
@1ec5 1ec5 self-assigned this Oct 26, 2021
@1ec5 1ec5 force-pushed the 1ec5-number-field-format-3615 branch 2 times, most recently from 9c3f92e to a733225 Compare October 27, 2021 01:06
@@ -391,5 +391,35 @@ export function coreLocalizer() {
return code; // if not found, use the code
};

localizer.floatFormatter = (locale) => {
if (!('Intl' in window && 'NumberFormat' in Intl &&
'formatToParts' in Intl.NumberFormat.prototype)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Displaying and accepting localized numbers is limited to browsers that support Intl.NumberFormat.prototype.formatToParts.

Copy link
Member

@tyrasd tyrasd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR! It looks great! 😍

I've not yet looked in too much detail into roadspeed.js and roadheight.js, but please find a few comments inline below.

modules/core/localizer.js Outdated Show resolved Hide resolved
modules/core/localizer.js Outdated Show resolved Hide resolved
modules/ui/fields/input.js Show resolved Hide resolved
modules/ui/fields/input.js Outdated Show resolved Hide resolved
modules/ui/fields/input.js Outdated Show resolved Hide resolved
modules/ui/fields/input.js Outdated Show resolved Hide resolved
test/spec/core/localizer.js Show resolved Hide resolved
modules/ui/fields/roadspeed.js Outdated Show resolved Hide resolved
modules/core/localizer.js Outdated Show resolved Hide resolved
@1ec5
Copy link
Collaborator Author

1ec5 commented Feb 9, 2023

I rebased this branch atop the latest develop branch. The conflicts were a bit tricky this time due to f573c37, which I think obsoleted some of the code review feedback above, but I went through the same cases as before and the functionality still seems to work correctly.

@tyrasd tyrasd modified the milestones: 2.24, 2.26 Mar 3, 2023
Copy link
Member

@tyrasd tyrasd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get this merged!

The only small concern I currently still have with this one is what happens when users enter numbers in the "raw" (English) format, and the field is expecting localized input. This might occur regularly because mappers are likely to assume that numbers need to be entered in the same was as they are encoded in OSM tags.

For example, when entering 2.5 (for example in a road width field) when on a locale which uses , as the decimal delimiter (such as vi or de for example), this results in the field value to be set to 25, which is not ideal.

I think we need to somehow special-case the situation when a "raw" decimal is entered.


There's also this bug when using the +/- buttons:

modules/ui/fields/roadspeed.js Outdated Show resolved Hide resolved
modules/ui/fields/roadheight.js Outdated Show resolved Hide resolved
@1ec5
Copy link
Collaborator Author

1ec5 commented Mar 3, 2023

I think we need to somehow special-case the situation when a "raw" decimal is entered.

This suggestion came up previously, but unfortunately I think it would be difficult to have it both ways, unless we assume the user won’t use their own language’s digit-grouping character for some reason: #3615 (comment). We could require the digit-grouping character to be used only to group three digits at a time, but we’d have to be careful not to disadvantage South Asian users who use crore and lakh – even in English.

#8238 introduced a monospaced font for raw OSM tags, so I suspect a new user would intuit that this field would accept localized numbers due to its variable-width font. Granted, it will require some getting used to for longtime users, but that problem will only grow over time. Do you think we should “prime” longstanding users by first styling these fields in monospaced font for a release before landing this feature?

There's also this bug when using the +/- buttons

Haha wow! I tested this case previously, but I guess it crept back in at some point.

@1ec5 1ec5 force-pushed the 1ec5-number-field-format-3615 branch from 01a4e58 to 6419def Compare March 4, 2023 06:42
Co-authored-by: Martin Raifer <martin@raifer.tech>
@1ec5 1ec5 force-pushed the 1ec5-number-field-format-3615 branch from e884929 to 4e11297 Compare March 4, 2023 06:48
modules/ui/fields/input.js Outdated Show resolved Hide resolved
The float formatter function now takes a number of fraction digits to return.
@1ec5

This comment was marked as resolved.

@1ec5 1ec5 requested a review from tyrasd March 5, 2023 07:43
@1ec5
Copy link
Collaborator Author

1ec5 commented Mar 5, 2023

For example, when entering 2.5 (for example in a road width field) when on a locale which uses , as the decimal delimiter (such as vi or de for example), this results in the field value to be set to 25, which is not ideal.

I think we need to somehow special-case the situation when a "raw" decimal is entered.

@tyrasd, I have misgivings about sniffing the format from the user’s input – differing behavior based on opaque rules is a recipe for user confusion. Your example is the easy case: no language uses a digit grouping symbol to separate the tens from the ones. But an equally realistic example of “2.500” could go either way. In my opinion, the fields should be biased towards the user’s language, since the user can always enter raw values in the raw tag editor below.

Anyways, I came up with this fancy regular expression to detect likely “raw” numbers. It catches raw numbers like “1.23”, “0.123”, “1.2345”, and “1234.567” but not formatted numbers like “1.234” and “123.456”. It would be trivial to short-circuit the float parser when the input matches this regular expression:

/^-?(0\.\d*|\d*\.\d{0,2}(\d{4,})?|\d{4,}\.\d{3})$/

Unfortunately, this special case actually turns out to be counterproductive. Fields commit their values continuously on each keystroke rather than waiting for the user to finish typing, so a numeric field reformats the number on each keystroke. In the cases where there are two correct answers, we would instead choose a third, incorrect answer. For example, if a German speaker intends to enter “1.234” to tag 1234, they’ll start typing 1.2. As soon as they type 2, “1.2” becomes “1,2” (1.2). Ultimately, the value becomes 1.234 (displayed as “1,234”) instead of the user’s intended 1234 (“1.234”).

Continuously validating a field causes other problems too, such as preventing the user from prepending more than one character at a time: #9233. But eliminating that behavior might resurrect a previously persistent issue that the field would fail to commit after the user finishes typing and navigates to another part of the UI.

/ref #1361

@tyrasd tyrasd force-pushed the 1ec5-number-field-format-3615 branch from b20b1a3 to 249771d Compare May 26, 2023 11:26
@tyrasd tyrasd added the usability An issue with ease-of-use or design label May 26, 2023
tyrasd added a commit that referenced this pull request May 26, 2023
when a user enters a decimal number using the "international"/English/OSM-raw-data formatting (e.g. as in `0.5`), it is parsed using the basic, non-localized, number parser. In such cases, the content of the input field should not be overwritten with the localized formatting, as that would cause unexpected glitches and make editing harder (e.g. when thousands-grouping characters seemingly "magically" disappear or appear while typing).

see #8769 ff.
@tyrasd tyrasd merged commit 249771d into develop May 26, 2023
@1ec5 1ec5 deleted the 1ec5-number-field-format-3615 branch May 26, 2023 17:43
@tyrasd
Copy link
Member

tyrasd commented May 26, 2023

FYI: I was still concerned that users might enter number in the "raw" format, which I addressed in the following way:

  • implement a fix for addr:housename textbox skips to the end 'onkeypress' #9233, which does not help very much here, as numbers can have different lengths in different formats
  • use your regex to detect likely cases of raw format numbers
  • not updating the input element while typing (a raw number which parses to the same numeric value as the localized formatting of the tag value will prevent the input field from being overwritten with the localized formatting)

I think this will work quite well in almost all cases of numeric osm tag fields, as they are typically large integers (e.g. population), small integers (e.g. capacity) or decimal numbers (e.g. width) with few decimals (as an example: it is very unlikely that someone had actually measured the height of a "8.849" meters high peak to 3 millimeter resolution).

@1ec5
Copy link
Collaborator Author

1ec5 commented May 31, 2023

implement a fix for #9233, which does not help very much here, as numbers can have different lengths in different formats

I’m very happy for this fix, though this PR wouldn’t have affected the addr:housenumber, addr:unit, and addr:postcode fields anyways, since they’re just text fields, not numeric fields.

not updating the input element while typing (a raw number which parses to the same numeric value as the localized formatting of the tag value will prevent the input field from being overwritten with the localized formatting)

I considered making this change too, but in the past, the downside was that some browsers would fail to fire the blur event in some cases, unexpectedly aborting the change: #1361. Are we confident that this is no longer a risk?

it is very unlikely that someone had actually measured the height of a "8.849" meters high peak to 3 millimeter resolution

For a peak’s height, no, but ele is tagged on other kinds of features, and there are other numeric keys that could potentially be expressed to the thousands or thousandths. My earlier example was just import cruft, but this is generic code that could potentially be reused for measurement-typed fields in the future.

I’m also concerned about users expecting to enter raw tag values in these fields. Though the changes you made seem to work, I think we can reinforce the expected user behavior with a small style change: #9677.

@tyrasd
Copy link
Member

tyrasd commented May 31, 2023

Are we confident that this is no longer a risk?

As far as I can tell, what I changed should not interfere with this: The change method is still invoked on every keystroke on('input', …) (in addition to the blur event on('blur', …)). Only the "backfeeding"1 of the value is suppressed in the case where the numeric value is the same as what is already displayed.

[…] measurement-typed fields in the future

Yeah, valid concern. A real example of a potentially ambiguous value would be something like https://www.openstreetmap.org/node/9591246259 (if the number field were to support entering numbers with a measurement unit in the future).

I'd say, let's definitely keep this potential issue in mind and reevaluate when such fields are introduced.

I think we can reinforce the expected user behavior with a small style change: #9677

👍

Footnotes

  1. this is the part of the data binding which is responsible to update the content of the UI field when the tag value changes through some indirect means, e.g. the use of the raw tag editor, some validation routine, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
field An issue with a field in the user interface localization Adapting iD across languages, regions, and cultures usability An issue with ease-of-use or design
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Numeric preset fields should localize numbers
2 participants