-
Notifications
You must be signed in to change notification settings - Fork 495
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
Allow setting the Currency on #numbers.formatCurrency() #604
Comments
Interestingly, So a |
We need the currency of the amount to properly handle currency symbols. If the locale is |
Yes, but I was asking for the signature of the method. Would a method That locale would then be used at the called thymeleaf/src/main/java/org/thymeleaf/util/NumberUtils.java Lines 279 to 290 in 8fb3bc3
Numbers class with this.locale , i.e. not letting the user specify a Locale .
|
Yes, it is insufficient because neither the number nor the locale carry the currency information of the passed number. |
I've created a dialect internally in my application to work around this, basically what I do is this: public String formatCurrency(final Number target, final Currency currency) {
if (target == null) {
return null;
}
try {
Validate.notNull(locale, "Locale cannot be null");
NumberFormat format = NumberFormat.getCurrencyInstance(locale);
format.setCurrency(currency);
return format.format(target);
} catch (final Exception e) {
throw new TemplateProcessingException("Error formatting currency", e);
}
} the important part is this |
As long as it specifies a country, a
So by specifying a locale, you obtain a completely-correctly formatted currency amount. Take this code: final BigDecimal amount = new BigDecimal("2412.41");
// United States
final Locale usLocale = Locale.US;
final NumberFormat usFormat = NumberFormat.getCurrencyInstance(usLocale);
System.out.println(usFormat.format(amount));
// Spain
final Locale esLocale = new Locale("es","ES");
final NumberFormat esFormat = NumberFormat.getCurrencyInstance(esLocale);
System.out.println(esFormat.format(amount));
// Brazil
final Locale brLocale = new Locale("pt", "BR");
final NumberFormat brFormat = NumberFormat.getCurrencyInstance(brLocale);
System.out.println(brFormat.format(amount)); The output of this is:
Which is proper formatting for all three currencies: dollars use However, from your code and what you say, it looks to me as if what you want to do is to format the amount in your local locale (e.g. Brazilian, as if all amounts were in reais), but then apply to them an arbitrary currency symbol. Using your code you'd get this instead of the above:
Note here dollars use Am I right therefore in thinking that you actually need this kind of mix-locale output from the second output example, and that's why you would need to specify the currency independently from the locale? |
Exactly that, I have a multi-currency application which needs to present values in many currencies (e.g. USD, EUR, BRL). The current built-in currency formatting support that thymeleaf have works ok for country specific applications where the amounts are represented in only one currency (e.g. BRL), but when there are many currencies involved, it does not work. I think that it would be ok to add a new method in the public String formatCurrency(final Number target, final Currency currency) |
I understand. I still see locale-specific currency representation more generally correct whatever your local language or formats, but I understand your need lies elsewhere. Note that what you need can be currently done with this — which is admittedly a somewhat more cumbersome expression: <p th:text="|${currency} ${#numbers.formatDecimal(amount, 1, 'POINT', 2, 'COMMA')}|"> The code above is simply forgetting about the fact that the I'll have to think about the way this could be organised, and what value each of these possibilities add. Thanks for your comments. |
Ok, If you need any help just ask :) |
I’d like to explain why this is useful (although I personally don’t need this feature right now). The way a number is presented depends on the language. For example, English separates thousands with commas and puts a full stop between the integral and the fractional parts of a number. Regardless of what currency an amount might be in, as long as the amount is presented in English, this fact does not change. On the other hand, many other languages put a comma between the integral and the fractional parts of a number and use dots, spaces or apostrophes to separate thousands, and some languages use middle dots or other combinations of symbols. If I understand correctly, sometimes the convention differs between regional dialects of the same language, so “language” here means the full language tag including dialect information. The number of significant digits depends solely on the currency. For example, US dollars and euros are divided into cents and are written with two digits after the decimal point, while Japanese yen are so small that they are not subdivided further, and so they are written without any fractional digits at all. This information is available in Java as Currency.getDefaultFractionDigits(). How a currency symbol is presented next to the number again depends on the language. For example, English puts the currency symbol before the number: $2,412.41, €2,412.41, R$2,412.41. On the other hand, many other languages (I can personally vouch for Russian, but I think most EU languages do so too) put the currency symbol after the number: e. g. in Russian, 2412,41 $; 2412,41 €; 2412,41 R$ (or with more figures: 12 412,41 €). The currency symbol itself, of course, depends on the currency, but also on the language of presentation. Most (?) currencies have a specific symbol that is used in all languages, e. g. $, £ or €, but some languages may want to make the symbol more specific, like “US$”. Some currencies may not have an actual symbol at all, in which case an abbreviation of the currency name may be used instead, which should be translated to the language of presentation. (For example, the Russian ruble used to be like this, using “р.” or “руб.”, short for “рубль” “ruble”. But then folks created and popularized a proper symbol, so currently it has one.) This is probably hard. But in any case, Java provides localized currency symbols as Currency.getSymbol(Locale). All in all, if one has a page written in English, one wants to use English number and currency presentation rules with English-localized currency symbols and an appropriate amount of significant digits for each currency. The page may mention $12,412.41, ¥12,412 and XDR 5 (or possibly SDR 5) all at the same time, and all should be formatted appropriately. If the user switches the page language to Russian, they should see 12 412,41 $, 12 412 ¥ and… uh… I don’t know, but probably either 5 СДР or 5 XDR. The proper formatting of a currency amount is a property not of the currency alone, nor of the presentation language alone, but rather of the combination of both. |
I think a very common constellation is thymeleaf being used in a spring boot application. Here the locale is determined by default by the Accept-Language header of the user agent if I'm not mistaken. Given the current implementation of currency formatting this enables the user to change the worth of the value, since different currencies usually have different values. I'm certain that this is rarely intended... +1 for the overloaded Method suggestion of @jonhkr |
I've got an even more complicated requirement. Currently I'm handling by passing a NumberFormat to the view.
The definition of this sorry its not in Java:
|
I personally think about the same lines as @jonhkr . The locale represents the language that you want to show an amount in. If you have an amount in euro with an English locale, you should show
|
I also have a multi-tenant Saas application where each client has its own currency but all clients are on the same database. (So the currency is saved in the database on a per-client basis such as 'EUR', 'USD' , 'CAD', etc) The view layer needs to present financial data in the currency defined in the database but formatted based on the locale of the browser (eg the number and date formats as defined by the request's locale) IMHO the th tag should take care of rendering the currency symbol and it wouldn't be necessary to pass this to the format function. Rather, the three-character ISO currency code should be used, along with the locale as a second parameter. In most cases the locale would come from the request but might be overriden if the user chooses to set the locale as an account preference. But the currency would always come from the database/server layer |
+1 here. Would love to see this resolved especially with the PR already there: #715. |
Maybe you didn't see it, but I created a PR some time ago: #715. I just updated it to be merged into 3.1. I hope it helps (this issue has the label "help wanted") |
I tried to solve this for hours and went with your solution too, the numbers.formatCurrency is still not able to update the culture region in 3.0.1. |
I agree 100% with @gemma1987 and @jonhkr
We have a multi-tenant platform for sporting events where the currency for
a particular event is in the local currency but participants come from
multiple countries. For example, the currency for the entry fee may be USD
but the participant is registering from France or London. So their browser
Locale will be EUR or GBP. But it is critical the currency show as USD.
…On Tue, Mar 28, 2023 at 7:05 AM gemma1987 ***@***.***> wrote:
I personally think about the same lines as @jonhkr
<https://github.com/jonhkr> . The locale represents the language that you
want to show an amount in. If you have an amount in euro with an English
locale, you should show € 1,000.00. If you shown an amount in euro with a
Dutch locale, you should show € 1.000,00. I already find it weird that
the number is just assumed to be in the correct currency of the current
locale. I am now just using formatDecimal for now (All my prices in my
app are in euro, regardless of the locale of the current usr):
th:text="${'€ ' + #numbers.formatDecimal(finishedRide.ridePrice, 1, 'DEFAULT', 2, 'DEFAULT')}
I tried to solve this for hours and went with your solution too, the
numbers.formatCurrency is still not able to update the culture region in
3.0.1.
—
Reply to this email directly, view it on GitHub
<#604 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAJDHB3ZZ644QJTGRPQZMRDW6LAXDANCNFSM4DI2GADA>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Hello,
It would be good to have a way to set the currency when using #numbers.formatCurrency()
So we can format the numbers correctly in a multi currency application.
The text was updated successfully, but these errors were encountered: