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

support compactDisplay: 'long' in currency formatting #892

Open
sparklerfish opened this issue May 16, 2024 · 5 comments
Open

support compactDisplay: 'long' in currency formatting #892

sparklerfish opened this issue May 16, 2024 · 5 comments
Labels
c: numbers Component: numbers, currency, units s: comment Status: more info is needed to move forward

Comments

@sparklerfish
Copy link

It would be useful and consistent for currency formatting to follow the same pattern for compact notation as other numbers.

Example:

new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    notation: 'compact',
    compactDisplay: 'long',
}).format(1000000);

// Expected result -> $1 million
// Actual result ->  $1M

If a currency value is to be presented with this formatting, it currently requires clumsy and error-prone string replacement that does not lend itself to consistent, correct internationalization of the content.

I discovered a relevant CLDR ticket, but it was closed without being pursued. I don't know whether it would be possible to revisit this discussion or to open another ticket to request this. Use cases for this formatting have come up numerous times in my work, and there is seemingly no solution that does not involve hard-coded exceptions to replace characters in the string for each localization. If it is accepted that there are use cases for "1 million", why would there not be use cases for "$1 million"?

@sffc
Copy link
Contributor

sffc commented May 16, 2024

Also see tc39/proposal-unified-intl-numberformat#95

As you found, the CLDR ticket was closed due to a lack of clear use cases. If you can give some illustrative examples, it would be sufficient to reopen the ticket.

@sffc sffc added c: numbers Component: numbers, currency, units s: comment Status: more info is needed to move forward labels May 16, 2024
@sparklerfish
Copy link
Author

sparklerfish commented May 17, 2024

My use cases are typically business simulations in which the design spec includes this formatting for values (which are dynamically calculated from a mathematical model) when they are, for example, used in a sentence. In the following case, you are playing the role of a Talent and Culture executive:
Screenshot 2024-05-16 at 4 18 48 PM

In order to achieve the required formatting, I could:

  • Use Intl.NumberFormat constructor to format as currency, then String.prototype.replace to find and replace the unit strings with their long forms
  • Use Intl.NumberFormat constructor to format as number, then add the currency symbol to the appropriate part of the string

Both approaches are difficult to generalize. Different languages place units on different sides of the number, or vary in whether there is (or how much) spacing between units, currency symbols, and values.

An example of the first approach, handling a couple different languages, could be something like:

const formatter = (val, lang) => {
    const [k, m, b] = (() =>  {
        switch (lang) {
            case 'en':
                return [
                    ['K', ' thousand'],
                    ['M', ' million'],
                    ['B', ' billion'],
                ];
            case 'pl':
                return [
                    ['tys.', 'tysiąc'],
                    ['mln', 'milion'],
                    ['mld', ' miliard'],
                ];
            case 'es':
                return [
                    [], // seems to be 'mil' either way?
                    ['M', 'millón '],
                    [], // ?? unclear whether this should be 1000 M or 1 mil millones
                ];
            default:
                return [[], [], []];
            }
    })();

    const string = new Intl.NumberFormat(lang, {
        style: 'currency',
        currency: 'USD',
        notation: 'compact',
    }).format(val);

    return string
        .replace(...k)
        .replace(...m)
        .replace(...b);
};

As you can see, this gets pretty cumbersome pretty quickly, and leaves a lot of room for human error and inconsistency.

This is a relatively common way of presenting numbers in text in the projects I work on, and always requires writing awkward, custom handlers to fix the formatting. I was surprised at how little I found when searching for information about this issue -- I started by digging into MDN, and, as far as I can tell, it's not even documented that compactDisplay does nothing with currency (nor would anyone have reason to expect it wouldn't!)

It seems reasonable to expect that the notation would work consistently across styles, and if it's assumed that there is utility in formatting 10000000 as "10 million", there's equal reason to consider being able to format it as "$10 million" if the value is currency.

@sffc
Copy link
Contributor

sffc commented May 17, 2024

Thank you for the additional details!

It doesn't exactly give you the requested output, but I'll point out that the following works:

new Intl.NumberFormat("en", {
    style: "currency",
    currency: "USD",
    notation: "compact",
    compactDisplay: "long",
    currencyDisplay: "name"
}).format(1000000)
// '1 million US dollars'

@sffc
Copy link
Contributor

sffc commented May 17, 2024

Also, just to note,

If it is accepted that there are use cases for "1 million", why would there not be use cases for "$1 million"? ... It seems reasonable to expect that the notation would work consistently across styles, and if it's assumed that there is utility in formatting 10000000 as "10 million", there's equal reason to consider being able to format it as "$10 million" if the value is currency.

The TG does not usually see arguments of the form "A is motivated and B is motivated so why aren't A and B supported at the same time" to be a compelling argument. If it were, the surface of ECMA-402 would explode with a lot more data and APIs that need to be shipped and maintained despite not being useful to developers. We therefore require proposals to demonstrate that they are independently useful to the web platform.

@sparklerfish
Copy link
Author

Fair enough on the latter point -- I totally understand that putting effort into an implementation requires a reason to do so, but I struggled a bit describing the use case other than "our clients/designers specify it fairly regularly", heh. And thanks for the syntax tip -- it still presents the challenge of replacing the currency word in various languages, but it's good to know it's another potential way to work around it. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: numbers Component: numbers, currency, units s: comment Status: more info is needed to move forward
Projects
None yet
Development

No branches or pull requests

2 participants