ThePilgrim / perlcldr

Perl module to use the Common Local Data Repository from the Unicode Consortium
7 stars 11 forks source link

default currencies for locales #2

Open patch opened 10 years ago

patch commented 10 years ago

This is in reference to commit 3241a532 included in Locale::CLDR v0.25.1.

Defaulting to unspecified currencies can be pretty dangerous. If I have a product for 399 USD, format it using the ja_JP locale, and have a bug where my currency code is undefined, I'd never want it to fall back to formatting as 399 JPY instead. That's not what the payment system is going to do when attempting to process a charge. Passing the currency code is just as important as passing the number—without both you have an unknown value.

UTS #35, Part 3, §4 (emphasis theirs): “Note: Currency values should _never_ be interchanged without a known currency code. You never want the number 3.5 interpreted as $3.5 by one user and ¥3.5 by another. Locale data contains localization information for currencies, not a currency value for a country. A currency amount logically consists of a numeric value, plus an accompanying currency code (or equivalent). The currency code may be implicit in a protocol, such as where USD is implicit. But if the raw numeric value is transmitted without any context, then it has no definitive interpretation.”

ThePilgrim commented 10 years ago

I read UTS #35 Part3 §4 as about transferring currency data between systems not necessarily formatting the data. The use default currency mechanism in format number is for those occasions where I know where the user is and I also know that the currency is in that users local currency, that way a coder can simply say format this locales local currency without an explicit call to default_currency().

However I hadn't thought about buggy code not passing in the currency code by mistake. Which means I run up against the age old problem of security verses convenience. I'm not sure what the right answer is here. I'm tending towards setting up a warning class to to warn that a default is being used. this can then be explicitly disabled with a no warnings Locale::CLDR::default or something smiler.

patch commented 10 years ago

I think this is one of many CLDR specification examples that is somewhat ambiguous. The main point I read regarding this issue is:

Locale data contains localization information for currencies, not a currency value for a country.

I have a hard time seeing a use case for implicitly defaulting to a display-level currency. The code would still need to call default_currency in order to either fetch the proper price for the locale’s default currency or perform a currency conversion from the native currency to the locale’s default currency. Perhaps I’m missing another use for this feature?

Another issue I have with implicitly selecting a default currency for a locale when formatting prices is that default_currency determines the locale’s region with $territory_id //= ($self->territory_id || $self->likely_subtag->territory_id). The locale en would use the currency USD and es would use EUR. That all seems kind of arbitrary to me for languages used in so many countries worldwide. Is there a part of the specification the recommends deriving default currencies from locales, and especially from likely subtags?

ThePilgrim commented 10 years ago

I've added a warning so that if you end up using the likely subtag's territory ID you at least get some notification. I'm leaving the ticket open as I'm half way convinced. One other option I'm considering is placing a warning in the constructor when any likely subtag is used along the lines of

Warning:- no territory given in locale defaulting to US