message-format-wg
message-format-wg copied to clipboard
Improved Currency Support
Is your feature request related to a problem? Please describe. Currency and its format is already documented to some extent by Unicode but to my knowledge, MessageFormat support is not as simple as the date or number arguments.
Describe the solution you'd like I would like to see easier to use currency support that is closer to date or number arguments (see example below).
Describe why your solution should shape the standard Currency is a very common scenario and providing an out of the box, easy to use solution would bring more value and reasons to use the syntax.
Additional context or examples
Your total is {amount, currency, short}
It would expect to have either scenario as input:
- Use default system/client locale currency
{amount: 10}
The output would be:
Your total is 10.00$
- Specify the currency:
{amount: {
value: 10,
code: 'CAD'
}}
The output would be:
Your total is CAD $10.00
Also having an extensive choice of format for both numbers and the currency sign would be a must to give full flexibility. Maybe the format could also be overwritten in the input?
ICU MessageFormat supports this via number skeletons:
Your total is {0, number, :: currency/CAD}
What if the currency code needs to be set dynamically?
In Fluent we solve it with partially formatted variables: https://projectfluent.org/fluent/guide/functions.html
bundle.format_pattern(pattern, {
amount: FluentNumber(num, { currency: "USD" }),
});
key = You owe { $amount }
or:
key = You owe { NUMBER($amount, minimumFractionDigits: 1) }
what's important is that we blacklist ECMA402 NumberFormat option currency
from the localization, so they can't override the currency. We haven't found any use case where the localizer should set the currency, so it's only for the developer to set.
what's important is that we blacklist ECMA402 NumberFormat option
currency
from the localization, so they can't override the currency. We haven't found any use case where the localizer should set the currency, so it's only for the developer to set.
Exactly the right thing to do: Nobody wants to see an amount in Japanese Yen but then be charged in US$.
ICU MessageFormat supports this via number skeletons:
Your total is {0, number, :: currency/CAD}
Having to declare the currency within the string itself means you have to know the currency you're dealing with in advance. - which is often not the case. Also - I'd like to see us have no default currency - that is, the user must supply it. - as per Fluent & ECMA402.
We haven't found any use case where the localizer should set the currency, so it's only for the developer to set.
+1. Probably if the localizer needs to set the currency, it would be some sort of static text (terms of use) and would not require to use such functionalities.
Regarding the syntax itself, I know we are not here to discuss this part yet, but I do like the idea of having a currency
type so that the linguist knows this is not just a number going there. Also having predefined formats that linguists can refer to, could give extra flexibility.
But one thing I have noticed is while Unicode tried to define currencies and their formats, if you browse around the web, it's hard to find any consistency on that front.
Prices and currency values are pretty important to us at Amazon. So we have invested in building currency data types, our own price formatter classes/functions across a number of programming languages, and integrating the price formatter into message format.
Declaring the currency in the formatter, as noted by @MickMonaghan, @duerst, and others is the wrong design. The currency belongs with the value. Our formatter instead focuses on different use cases: standalone, in sentence, compact (no decimal portion, smaller symbol where possible), "legal" (i.e. showing the ISO currency code), etc---that is, conveying the intention of the developer to save (many many) lines of configuring code.
We also have a bunch of features related to "format to parts" type functionality (what field order is used, what fields are present, whether there is a space between the symbol and value, etc.).
I'm excited by @sffc's work on number skeletons. I was reluctant to use subformat keywords in our implementation because the history of subformats is that they become restrictive, outmoded, and thus not so useful. The difference between our keywords and the short/medium/long/full ones is that ours are tied to specific consistent uses, rather than arbitrary cases (what does medium
mean?!?), so I think that's maybe okay.
Google has a Money type which is used in many instances, and it would be good if this support was able to align in some way or be extensible with this type.
For Siri, it has been the following options and things to consider.
- Show/hide currency symbol
- Show/hide the subunits when it's 0
- Show/hide fractional subunits, like $1.2345, which would normally apply to per unit pricing when purchased in bulk.
- Approximate the value, like "$8.3 million" instead of "$8,345,123.03"
- Show the native currency symbol when the currency is native to the region, and show the non-native currency symbol when it doesn't match the region.
- Pronounce the native currency when the currency is native to the region, and pronounce the non-native currency when it doesn't match the region. So I can use $ (pronounced dollar and whose translation is unavailable in CLDR) when referring to USD and CA$ for CAD when my region is set to US. I switch it to US$ (pronounced as US dollar according to CLDR) for USD, and $ (dollar) for the CA region.
Things that aren't good to have inside a message.
- Specifying the currency code
- The exact format to show because it can overspecify things that do not need to change.
- Some inexact notion of short, medium and long. That has already been an issue for dates and times.
What has never been needed is to assume that the currency is related to the language or region setting. That would be a bad design choice. The currency should be known by the developer before hand, much like the time zone needs to be known by the developer before hand.
Given various developments, this appears like it might fit into the discussion of default registry entries.
As mentioned in today's telecon (2023-09-18), closing old requirements issues.
If necessary, open new issues (in this case against the default registry)