Skip to content

render/forms: normalizeLocaleNumber matches the minus sign as a literal byte, so a U+2212 locale cannot round-trip #583

Description

@Yaraslaut

Split out of #574, which listed it as one of two "smaller fixes while there" and whose PR (#581) deliberately did not take it: it is an API change to both control edges and all their call sites, and unlike the group-separator defect it does not produce a wrong value — it rejects a valid entry. Filing it so closing #574 does not lose it.

Verification status: reproduced

Revision: fix-574-quantity-provenance-locale @ 3a1effd0 (PR #581), i.e. after the group-separator fix. The sign behaviour is unchanged by that PR.

morph::render::normalizeLocaleNumber(text, decimalSeparator, groupSeparator) takes both separators as std::string_view precisely because a real locale's separator is not always one byte (fr-FR groups with U+202F). The sign got no such treatment: it is matched as the literal byte '-', in include/morph/render/locale_format.hpp:

char const chr = text[i];
if (chr == '-') {

So a locale whose minus sign is U+2212 MINUS SIGN (−, 3 UTF-8 bytes) cannot round-trip:

normalize("−5", dec=".", grp="")  = NULLOPT

— the first byte of U+2212 is not a digit, not '-', and matches neither separator, so the entry is reported malformed. formatCanonicalNumber, the display-direction inverse, has the mirror-image problem: it emits a literal '-' whatever the locale.

The same is true of the QML mirror in src/qt/forms/qml/DynamicForm.qml, which compares ch === "-".

Why it matters, and why it is smaller than #574 was

This one rejects, it does not silently mis-convert. A user who types −5 is told the entry is malformed, which is wrong but visible and recoverable — the opposite of "1.5" → 15, which was the whole reason #574 was a defect. So the cost is a usability failure in a locale that uses the typographic minus, not a wrong number on the wire.

Qt's QLocale::negativeSign() returns U+2212 for several locales, and DynamicForm.qml reads the rest of its separators straight off Qt.locale(), so a renderer that passed qtLocale.negativeSign through would be handing this function something it cannot accept today.

Suggested shape

A fourth parameter, std::string_view negativeSign = "-", matched as a whole string the way the separators already are, and the same on formatCanonicalNumber so the pair stays inverse. Both edges must change together — docs/spec/forms/forms.md, "Locale data formatting", records that a divergence between the C++ function and its QML mirror is a divergence in what the product accepts.

Not verified

  • Which locales Qt actually reports U+2212 for on each platform, and whether any application in this repository configures one. The claim above is about QLocale's documented behaviour, not a measurement.
  • Whether a positiveSign parameter is wanted for symmetry. Neither edge accepts a leading + today at all, in any locale, which is a separate question.

What would change the verdict

Close this if the control edge is deliberately restricted to ASCII - on entry, with the renderer expected to normalise the sign before calling — but nothing says that today, and the separators set the opposite precedent in the same function.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: formsSubsystem: formsbugSomething isn't workingtriage: validWell-framed; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions