-
-
Notifications
You must be signed in to change notification settings - Fork 35
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 all ISO 4217 currencies and locales #43
Comments
Would you be door to submit a pr with an updated CommonCurrencies class. I don't have the time to do this at the moment. |
I'll look into it this week! |
So far I've found https://github.com/google/closure-library/blob/master/closure/goog/i18n/numberformatsymbols.js based off of the CLDR. |
If your are going to port the code check the licence is compatible. |
I would be great if someone could help build out a full set of iso code. |
I found https://pub.dev/documentation/intl/latest/intl/NumberFormat/NumberFormat.simpleCurrency.html which supports my use case. The |
If I understand correctly, all that is required is to add more code snippets like the below to the
There are a few sources out there with enough information to fill the above with at least close to all the ISO 4217 currencies. This repository, for instance, has a MIT license and provides a JSON file with a format like:
The accompanying library actually provides a formatter based on the above JSON. I'll investigate a little further to validate and come back with a proper source. If I find there is viable info with an appropriate license (again, the above is MIT), I might take some time to help out. If this goes well, I suggest then adding the possibility of creating a currency with a simple static method like:
This will make it easy to integrate with any source that simply provides an ISO 4127 currency code. Better yet, create a Money instance like:
instead of instantiating the currency before, manually. |
Yet another source with MIT license. This one is much more recent and seems to have more complete base info. Sample currency info provided:
|
Thanks for the interest. If I understated you correctly you are proposing that we ship a json file with the package and the proposed new method parses the json file and generates a currency. Can I suggest an alternate method. We use the json file to generate the common currency class. The removes the overhead of parsing json and means we don't have to find a way to ship the json file with the package. |
We should expand the currency to include the additional fields |
Hmm. After some investigation, I think it is a problem to want to keep currency formatting in this library. Investigating further, the localization of a currency does not depend on the currency but on the locale. That means that one currency may be displayed differently depending on the locale. One can maintain a simpler JSON file with the main representation of a currency as per its (main) source country/region; but CLDR, the international standard, maintains a JSON file per locale/country, where all currencies are referenced for each locale/country. This makes it a huge source to maintain localization, best handled by a specialized library like I would therefore tend to use this library for its precise calculation as per currency rules; and leave formatting to more specialized libraries. Django's PyMoney, for instance, does allow formatting. But formatting, as you can see, requires passing a locale: >>> from moneyed.l10n import format_money
>>> format_money(Money(10, USD), locale='en_US')
'$10.00' But, underneath, that method above is a thin wrapper of Python's known babel localization library. In their documentation, you can see the following example, where USD is formatted differently according to locale: >>> format_currency(1099.98, 'USD', locale='en_US')
u'$1,099.98'
>>> format_currency(1099.98, 'USD', locale='es_CO')
u'US$\xa01.099,98' I would therefore recommend focusing on the proper math of manipulating money and leaving formatting to a specialized localization library, like To be honest, my interest in |
As an alternative, because If |
I don't think your interpretation is correct. Common currencies provides the default formatting for a specific currency. With money, if you want to format other currencies with your locale you can do this by providing a custom format. It does make we wonder if we need a standard method to do this. Money.formatUsing('usd') |
Int'l doesn't do the job which is why I created the format method. |
I may be wrong but I have seen enough evidence suggesting that a proper complete way of handling currency formatting requires using locale. An example for France and Germany, both having EUR as currency: France: 999 999 999,99 € The main difference above is number formatting. France uses spaces, Germany uses dots for thousands separator. Overall, we have the following concerns, as per CLDR: a) Whether the currency symbol appears before or after the amount (for example, The above concerns are taken from this post by Shopify. They use Common Locale Database Repository (CLDR) for localization formatting for currency, date, time, and amount. As per Shopify, CLDR:
c) and d) above are supported by something like But it seems to me a combination of localized number formatting and specific currency rules is what provides the proper localized format for a currency. Also, |
Trying it out in dartpad, works as expected, including currency fractional units. import 'package:intl/intl.dart';
void main() {
var formatter = new NumberFormat.currency(name: 'EUR', locale: "fr_FR");
print(formatter.format(1000.567));
// 1 000,57 EUR
formatter = new NumberFormat.currency(name: 'EUR', locale: "de");
print(formatter.format(1000.567));
// 1.000,57 EUR
formatter = new NumberFormat.currency(name: 'EUR', locale: "fr_FR", symbol: "€");
print(formatter.format(1000.567));
// 1 000,57 €
formatter = new NumberFormat.currency(name: 'EUR', locale: "de", symbol: "€");
print(formatter.format(1000.567));
// 1.000,57 €
} A simple wrapper around this would do the trick. Link to Each locale includes currency pattern and default currency code. All this said, this would not exclude the need for an updated |
OK, so that is a slightly different problem than what I thought you
were talking about.
So yes I agree that is an issue.
A key objective of the Money2 package is that it should be a swiss army
knife for utilising Money so I don't see forcing users to resort to intl as
being an option.
intl also won't do what we need.
The intl.NumberFormat doesn't support all of the features of Money so that
would be a backward step.
The formatter is also not compatible with Money2 formatter which would be a
major breaking change.
The formatter is actually not the problem as what we have works and will
work if we move in the direction I outline below.
The issue is that I incorrectly associated currency with a format, when it
should have been a locale.
So I think this means that we need to support locales in the money package.
From your research it looks like we can get a complete set of locales and
then generate the necessary code.
I don't want to force users to ship a json file as there is no consistent
way of doing this. In a flutter app you can use assets but on the cli you
have to use something like 'dcli pack'.
A core aim of Money2 is that it is simple to use. Having to manage an asset
to ship Money2 falls out of my definition of simple :)
I'm also not in love with the performance cost of parsing a large json file
on startup.
Memory usage is not a consideration as the json file will still need to be
loaded into memory. I guess we could use a serialisation technique but this
would either require the user to know the set of currencies they use in
advance (which is some case they would) or simply re-parse the json file
each time they mention a new locale (this sounds problematic).
So the question is how we do this whilst minimising breaking changes.
Using your suggestions of getting a json file containing all of the locales
we can generate a new 'locales' file similar to the existing common
currencies.
The issue is that currently we have a lt of methods of the from
'fromCurrency('USD');
These would need to be changed to fromLocale('en_US');
I'm also not a fan of users using strings such as 'en_US' so we need to
define these.
We could do something like fromLocale(Locales.enUS);
We then deprecate the existing fromCurrency type methods and eventually
removing them in favour of the fromLocale equivalents.
S. Brett Sutton
Noojee Contact Solutions
03 8320 8100
…On Sat, 18 Dec 2021 at 09:02, luissalgadofreire ***@***.***> wrote:
I may be wrong but I have seen enough evidence suggesting that a proper
complete way of handling currency formatting requires using locale.
An example for France and Germany, both having EUR as currency:
France
<https://www.freeformatter.com/germany-standards-code-snippets.html>: 999
999 999,99 €
Germany
<https://www.freeformatter.com/france-standards-code-snippets.html>:
999.999.999,99 €
The main difference above is number formatting. France uses spaces,
Germany uses dots for thousands separator.
Overall, we have the following concerns, as per CLDR
<http://cldr.unicode.org/>:
a) Whether the currency symbol appears before or after the amount (for
example, $250, 250 USD, 250 $)
b) Whether decimals are used (for example, there are no “cents” in
Japanese yen)
c) Whether the decimal sign is a period or a comma (for example, 37,50 or
37.50)
d) How to group numbers (for example, 10,000 or 1,0000, or using spaces)
The above concerns are taken from this post
<https://polaris.shopify.com/foundations/formatting-localized-currency>
by Shopify.
They use Common Locale Database Repository (CLDR)
<http://cldr.unicode.org/> for localization formatting for currency,
date, time, and amount.
As per Shopify, CLDR:
- It’s the recognized international standard
- It automatically formats numbers and currency *based on the
merchant’s locale*
- The repository is maintained by a third party.
c) and d) above are supported by something like intl. b depends on
currency information we can get from ISO 4217. Not sure though if a) is
currency specific or locale specific.
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAG32OFUFG3DC57RBEPZHY3UROXQVANCNFSM5AQE5IVA>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
You are receiving this because you commented.Message ID: <noojee/money.
***@***.***>
|
I decided to port something I already have in Java for my purposes. I also require rounding modes, among other things. I would however suggest you viewing
That way, you would have sane, convenient, powerful money calculations as per now plus enterprise-grade localization of currency formats, with minimum maintenance. You would still have a Swiss army knife for money handling and with your own API but using underlying resources in an efficient way. |
So there is two issues here, localizations and all currences which are separate issues. I got to say I agree with what was said about localization. I'm not sure what is the problem with As for the generation of the currency instances with json, that's definitely a better approach than reading the json file. I could do it if I happen to choose this package or roll my own for price management. However depending on when static meta programming is a thing, it might be worth to wait for it, although, depending on the json completeness, it's really an easy task. |
I would have to go back and look but I think there was a problem with the intl formatter not supporting all the options we do. From recollection, we use the intl formatter but have to break the parts up (decimal, integer) to make it work. I'm also not convinced that supporting the formats for each locale is particularly burdensome as I would be shocked if any of these ever change. |
Okay so what is required here ? Concerning the original issue: Which file should be used to generate the Currencies classes ? |
I ended up implementing my own stuff based on this repo, which has a permissible BSD3 license. There is a considerable difference in their approach. It stores and operates amounts as integers with minor units to avoid rounding issues. It's the alternative to using a decimal type offering the precision that float lacks. However, that is not relevant for I made several additions to the above mentioned repo's code but the main addition pertains to formatting. Take a look at the fundamental files here. You'll find a The The Feel free to use it as you see fit. |
Thank you, are you going to publish it on pub.dev? The only thing I see missing is to compose your own currency registry, currently you are using all the currencies but an user of the API might want to use only two (for example EUR and USD), the implementation does not allow tree shaking like this. Something like the registry in this lib https://pub.dev/packages/money |
I'm afraid I'm not planning on publishing it. I don't mind if you do or if you use it just to pick relevant parts from it to update However, bear in mind that my version leads to storing amounts in |
yes I saw, I guess that could be a problem for currencies like bitcoin. I'll update money2 with the values found there even if I end up not using it in about 2 days once I get onto my money task. |
I believe it will work for any currency, including bitcoin. It's just a matter of preference, that's all. Personally, I don't mind using this method, which I believe is common in the banking sector. |
Don't you risk overflowing for big values ? Bitcoins can have huge values, the int is not 64 bit when running on web platform |
Didn't understand you were referring to int size. If that comes to a problem, one can just use BigInt, which is now an official type in dart 2+. My remark was the fact that amounts are expressed as integers, not decimals, and that is a matter of preference. |
But again, the code is shared as inspiration for the formatting part. The rest is covered already by |
@cedvdb, just a side note. You reminded me of my postponement to evolve from |
There was a reason we move from bigint to decimal. As to the registry, I don't believe that will help with tree shaking unless we remove a chunk of functionality in the parser that is able to 'find' a currency. |
The registry will help if the currencies are provided by the user. EG CurrencyRegistry(allCurrencies);
or
CurrencyRegistry([usd,eur]); // eur and usd imported from money2, the whole array isn't imported and is therefor tree shaken Admittedly that feature might not be worth it, I personally do not have a use for this. I'm also still skeptical about the non use of intl package. Could you highlight what feature was not supported by intl ? Have you had a look at https://api.flutter.dev/flutter/intl/NumberFormat/NumberFormat.currency.html Most people already use it so, there is no need to have two version of formats. Maybe the size of all the formats is negligible but I see no reason to live with duplicates, and there will be duplicates because flutter apps with localization also use intl. It also means that the formats might differ from an official flutter widget. |
Yes, conversions require the possibility of having multiplication/division operations between BigInt and non-BigInt numbers, which BigInt does not support. However, I used rational for those very specific operations. And it works fine, now with huge numbers, also. It turns out Nevertheless, using BigInt or decimal are both valid approaches. The main concern in this thread was formatting. I just shared how I proceeded and honestly am quite convinced using Good luck with the project. |
Last remark - formatting functions at work: test('format()', () {
Money.init(defaultLocale: 'en_US');
expect(Money.simpleDouble(1200000.594, 'USD').format(), 'USD1,200,000.59');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'USD').format(), '1 200 000,59 USD');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'USD').format(), '1.200.000,59 USD');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'EUR').format(), '1 200 000,59 EUR');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'EUR').format(), '1.200.000,59 EUR');
});
test('simpleFormat()', () {
Money.init(defaultLocale: 'en_US');
expect(Money.simpleDouble(1200000.594, 'USD').simpleFormat(), '\$1,200,000.59');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'USD').simpleFormat(), '1 200 000,59 \$');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'USD').simpleFormat(), '1.200.000,59 \$');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'EUR').simpleFormat(), '1 200 000,59 €');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'EUR').simpleFormat(), '1.200.000,59 €');
});
test('compactFormat()', () {
Money.init(defaultLocale: 'en_US');
expect(Money.simpleDouble(1200000.594, 'USD').compactFormat(), 'USD1.2M');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'USD').compactFormat(), '1,2 M USD');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'USD').compactFormat(), '1,2 Mio. USD');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'EUR').compactFormat(), '1,2 M EUR');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'EUR').compactFormat(), '1,2 Mio. EUR');
});
test('compactSimpleFormat()', () {
Money.init(defaultLocale: 'en_US');
expect(Money.simpleDouble(1200000.594, 'USD').compactSimpleFormat(), '\$1.2M');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'USD').compactSimpleFormat(), '1,2 M \$');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'USD').compactSimpleFormat(), '1,2 Mio. \$');
Money.init(defaultLocale: 'fr_FR');
expect(Money.simpleDouble(1200000.594, 'EUR').compactSimpleFormat(), '1,2 M €');
Money.init(defaultLocale: 'de_DE');
expect(Money.simpleDouble(1200000.594, 'EUR').compactSimpleFormat(), '1,2 Mio. €');
}); The first one, As you can see,
That's quite convenient and straight out of |
@bsutton here are all generated dart instances if that helps: https://github.com/cedvdb/dart_price/blob/main/lib/src/currency_map.dart |
Appreciate the contribution.
I'm snowed for the next month or two but this is in my to-do list.
…On Tue, 26 Apr 2022, 11:44 am cedvdb, ***@***.***> wrote:
@bsutton <https://github.com/bsutton> here are all generated classes if
that helps:
https://github.com/cedvdb/dart_price/blob/main/lib/src/currency_map.dart
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAG32ODED4PZ4ZLVQS45DNDVG5C7VANCNFSM5AQE5IVA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Just started getting errors for SEK currency not supported. This is when using |
Luke,
if you raise a PR for SEK support I'm happy to publish a new version.
You need to add it to CommonCurrencies.dart
…On Fri, Dec 29, 2023 at 7:08 AM Luke Pighetti ***@***.***> wrote:
Just started getting errors for SEK currency not supported. This is when
using money2 to parse and format dates from RevenueCat for in-app
purchases and subscriptions
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAG32OCJWJS2J2QW5NAMMH3YLXGUHAVCNFSM5AQE5IVKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBXGE2DKOJVGY4Q>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
A full sets of currency codes is now supported (5.0.1) thanks to https://github.com/fueripe-desu. Locales is still an outstanding issue. |
Alternatively, the currencies listed in https://support.google.com/googleplay/android-developer/answer/9306917 would suffice for my use case.
The missing currencies from that link are:
AED CLP COP CRC CZK DKK EGP HKD HUF IDR ILS LBP MYR PEN PKR RON SAR SEK SGD THB UAH UYU VND
The text was updated successfully, but these errors were encountered: