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

Add expression operator for formatting numbers #4119

Closed
lucaswoj opened this issue Feb 1, 2017 · 9 comments · Fixed by #7626
Closed

Add expression operator for formatting numbers #4119

lucaswoj opened this issue Feb 1, 2017 · 9 comments · Fixed by #7626
Labels
cross-platform 📺 Requires coordination with Mapbox GL Native (style specification, rendering tests, etc.) feature 🍏

Comments

@lucaswoj
Copy link
Contributor

lucaswoj commented Feb 1, 2017

From @1ec5 on May 6, 2016 23:21

It’s possible for a style to localize string labels by choosing a language-specific field in the source. But when it comes to numeric types (elevations of peaks, for instance), the viewer is stuck with an unformatted number of the form ####.## using European digits. Ideally, it should be possible for a topo map to show elevations in #,###.## form for English, in # ###,## form for French, and in #,##,###.## form for various Indic languages. Meanwhile, an Arabic or Gujarati map would use the appropriate numeral system.

I’m not sure whether the number format should be controlled by the style (and thus defined in this specification) or determined by the system locale (and thus be implementation-specific). But I figured I’d start here because the conventional approach to localized strings involves changing style properties.

/cc @mikemorris @kkaefer @lucaswoj

Copied from original issue: mapbox/mapbox-gl-style-spec#452

@lucaswoj
Copy link
Contributor Author

lucaswoj commented Feb 1, 2017

👍

While we're thinking about this, we should think about units too. A couple countries (namely Burma and Liberia (😈)) are still using imperial units.

@lucaswoj
Copy link
Contributor Author

lucaswoj commented Feb 1, 2017

From @dpieri on May 26, 2016 19:37

It would be very helpful for our use case to be able to do simple math in labels. We display feet everywhere on our map (I know, I know..) but we rely on Mapbox Terrain for elevation contours. These are in meters and people keep getting confused by this. Currently the text field on our contour labels is {ele}m, I'd love to be able to use {ele*3.28}ft

As far as I can tell, my only option is to create my own contour tileset and convert meters to feet.

Another fix would be to include something like ele_ft in the Mapbox Terrain's contour layer so each style can pick the unit it prefers. It looks like Mapbox Streets v7 takes this approach for peak labels.

@lucaswoj
Copy link
Contributor Author

lucaswoj commented Feb 1, 2017

From @1ec5 on May 26, 2016 19:45

Unit customization and more general math functionality would be covered by #4077. I think we should keep these two concepts separate, because (except for mixed numbers or non-positional systems like Roman or Chinese numerals) number formatting is all about text processing rather than arithmetic.

@1ec5 1ec5 added the cross-platform 📺 Requires coordination with Mapbox GL Native (style specification, rendering tests, etc.) label Feb 3, 2017
@1ec5
Copy link
Contributor

1ec5 commented May 25, 2017

Per #4715 (comment), it would be more feasible to implement this feature as an expression function that takes a locale identifier as an argument, as opposed to a function that takes a number format pattern as an argument.

@kkaefer
Copy link
Contributor

kkaefer commented Mar 12, 2018

This is now possible with expressions.

@kkaefer kkaefer closed this as completed Mar 12, 2018
@1ec5
Copy link
Contributor

1ec5 commented Mar 15, 2018

It isn’t currently practical to format numbers in a locale-sensitive way using expressions. For example, if a feature property is set to the number 1234.56, displaying “1.234,56” would require some gymnastics:

Gymnastics
["let",
  "group", ".",
  "decimal", ",",
  "places", 2,
  "remainder", ["%", ["get", "num"], 1],
  ["let",
   "integer_part", ["-", ["get", "num"], ["var", "remainder"]],
   ["concat",
    ["to-string",
     ["-",
      ["/", ["var", "integer_part"], 1000],
      ["/", ["%", ["var", "integer_part"], 1000], 1000]
     ]
    ],
    ["var", "group"],
    ["to-string", ["%", ["var", "integer_part"], 1000]],
    ["var", "decimal"],
    ["to-string",
     ["let",
      "fractional_part", ["*",
                          ["var", "remainder"],
                          ["^", 10, ["var", "places"]]
                         ],
      ["+",
       ["-", ["var", "fractional_part"], ["%", ["var", "fractional_part"], 1]],
       ["case",
        [">=", ["%", ["var", "fractional_part"], 1], 0.5],
        1,
        0
       ]
      ]
     ]
    ]
   ]
  ]
]

This expression wouldn’t scale beyond the hundred-thousands place, and it wouldn’t work at all for languages like Arabic and Hindi that use different numerals, or for Indic languages like Hindi that group lakhs and crores instead of millions.

As noted in #4119 (comment), the intent of this issue is to add an expression operator that formats a number as appropriate for the given locale identifier. This can be implemented trivially in the various platforms we support:

@1ec5 1ec5 reopened this Mar 15, 2018
@1ec5 1ec5 changed the title Provide a way to format & localize numbers Add expression operator for formatting numbers Mar 15, 2018
@ChrisLoer
Copy link
Contributor

I think the functionality is pretty much the same, but on the Javascript side we can use Intl.NumberFormat just to have an interface similar to Intl.Collator (which we're planning to use for string collation in PR #6270), and Intl.DateTimeFormat (not sure if there's an outstanding request for localized date/time support...).

@1ec5
Copy link
Contributor

1ec5 commented Nov 26, 2018

Supercluster adds a point_count_abbreviated feature property that’s commonly displayed in text-field but that isn’t localizable: mapbox/supercluster#110. Unfortunately, the lack of a number formatting operator means this property can’t easily be reimplemented as an expression in the gl-language plugin, where it would be more feasible to pull in CLDR-based locale data.

@ChrisLoer
Copy link
Contributor

What do you think of making a NumberFormatter type that's an optional argument to the to-string coercion?

['to-string', <number>, ['number-formatter', { 'locale': 'de', 'style': 'currency' }]

This is the closest analog to collator expressions, and has the same advantage that it allows you to test what locale actually gets loaded. On the other hand, adding types to the expression language is a pain, and we could also do something like:

['number-format', <number>, { 'locale': 'de', 'style': 'currency' }]

And we'd just return a string with whatever result we got from whatever locale happened to load.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cross-platform 📺 Requires coordination with Mapbox GL Native (style specification, rendering tests, etc.) feature 🍏
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants