Unexpected currency symbol in currency NumberFormat - java

While testing on an Android emulator, I came across an inconsistency between the formatted strings produced by a NumberFormat instance and it's reported currency symbol.
I start by setting up a localized currency formatter like so:
// displayLocale is af_NA
DecimalFormat df = (DecimalFormat)
NumberFormat.getCurrencyInstance(displayLocale);
// currency is USD
df.setCurrency(currency); // USD localized for af_NA
Then I use it to format a value. The result of invoking:
df.format(1)
is "$1". This might not seem obviously wrong, but when I check the details of the formatter, things dont add up. Invoking:
df.getDecimalFormatSymbols().getCurrencySymbol()
yields "USD" and not the expected "$"...what!? Even stranger, I've yet to find a physical device that I can replicate the issue on. Tests running under Robolectric don't exhibit this behavior either.
Has anybody else come across this behavior before and if so, any idea what's causing it? And finally, is this behavior that might be encountered on physical devices or is it purely an AVD thing?
UPDATE:
Here's a method you can call from any Activity to check for and print out any offending formatters:
void checkFormatters() {
Currency USD = Currency.getInstance(Locale.US);
Money oneDollar = new Money(BigDecimal.ONE, USD);
for(Locale locale : Locale.getAvailableLocales()) {
DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(locale);
df.setCurrency(USD);
String currencySymbol = df.getDecimalFormatSymbols().getCurrencySymbol();
String localizedDollarString = CurrencyUtils.getPrettyCurrencyString(locale, oneDollar);
if(!localizedDollarString.contains(currencySymbol)) {
Log.w(TAG, locale.getDisplayName() + ": Expected localized dollar string [" + localizedDollarString +
"] to contain currency symbol [" + currencySymbol +
"]");
}
}
}
If the device you're testing on has the issue then you'll see results like these:
Uzbek (LATN): Expected localized dollar string [$ 1] to contain currency symbol: [US$]
Uzbek (Uzbekistan,UZ): Expected localized dollar string [$ 1] to contain currency symbol: [US$]

Related

Formatting number based on the different currency code for different locale where output to be in the currency symbol formatted based on the locale

Language: Java
Problem: I need to set the currency code manually in java. Let's say "USD" and locale can be either "fr-CA" or "en_US" based on the user logged in . I am unable to find the solution where we can do the number format by setting the manual currency and displaying the symbol with number in the output. Please note currency code will not be the same as the locale and vice versa.
For example, if my currency is USD then based on the different locale, the number should be formatted and the output should be as below.
$1,300,000.00 - english
1.300.000,00 $ - Deutch
1 300 000,00 US$ - Potuguese
1 300 000,00 $ US - France canada
Tried below but it does not give the expected output:
Currency currencyInstance1 = Currency.getInstance("USD"); // This can change based on the user input on the UI.
NumberFormat numberFormat4 = NumberFormat.getCurrencyInstance(Locale.CANADA_FRENCH);
numberFormat4.setCurrency(currencyInstance1);
System.out.println(numberFormat4.format(amount4));
Actual output : 123 456,79 USD
**Expected output:**
For french canada: 1 300 000,00 $ US
For Portuguese : 1 300 000,00 US$
For Deutch : 1.300.000,00 $
Any help is appreciated.
Cross currency for cross locale is not supported in Java.
Country codes are an important locale component because of java. text.Format objects for dates, time, numbers, and currency are particularly sensitive to this element. Country codes add precision to the language component of a locale. For example, French is used in both France and Canada. However, precise usage and idiomatic expressions vary in the two countries.
These differences can be captured with different locale designators in which only the country code is different. For example, the code fr_CA (French-speaking Canada) is different from fr_FR (French-speaking France).
So if we need to fetch the symbol then we would need to create a map with the locale and currency. Pass the currency to fetch the symbol and then use replace to add it.
public static Map<Currency, Locale> currencyLocaleMap;
static {
currencyLocaleMap = new HashMap<>();
List<Locale> availableLocales =
Arrays.asList(Locale.getAvailableLocales());
List<Locale> supportedLocales = new ArrayList<>();
supportedLocales.add(Locale.forLanguageTag("en-US"));
List<Locale> filteredLocales = supportedLocales.stream().filter
(eachLocale -> availableLocales.contains(eachLocale)).collect(Collectors.toList());
System.out.println("UtilTemp : Locales supported : " + filteredLocales);
for (Locale locale : filteredLocales) {
try {
if(!locale.getCountry().isEmpty()){
Currency currency = Currency.getInstance(locale);
currencyLocaleMap.put(currency, locale);
}
}
catch (Exception e) {
}
}
}
public static String getCurrencySymbol(String currencyCode) {
Currency currency = Currency.getInstance(currencyCode);
System.out.println("UtilTemp :" + currencyLocaleMap);
return currency.getSymbol(currencyLocaleMap.get("USD"));
}

How to format currency with number format classes

I am new in Android development and i am stuck at a place. I want to format my currency, I am setting to show without decimal places and with commas.
Example: right now it's showing like 23000.00. But I want the currency like 23,000; how can I do that?
I tried the formatter classes but that doesn't help me.
This is how it's set now.
public class CurrencyFormatter {
public static String setsymbol(BigDecimal data, String currency_symbol)
{
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.ENGLISH);
format.setCurrency(Currency.getInstance(currency_symbol));
String result=data+" "+" دينار";
return result;
}
}
I expect output to be (arabic text)23,000 instead of (arabic test)23000.00
Basically, you need a currency formatter object.
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);
After that you can format an amount of money:
Double currencyAmount = new Double(23000.00);
String formattedOutput = currencyFormatter.format(currencyAmount);
There are more options and explanations available here on Oracle's reference document: https://docs.oracle.com/javase/tutorial/i18n/format/numberFormat.html
check this
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.getDefault());
format.setCurrency(Currency.getInstance("USA"));
String result = format.format(1234567.89);
This is the format set of usa you can change with your country code
reference check description here
Try this, it will show in this format 23,000 without decimal points, It will show thousand separator in the number.
String result = null;
try {
// The comma in the format specifier does the trick
result = String.format("%,d", Long.parseLong(data)); // use this result variable where you want to use.
result = result + " " + " دينار"; // to append arabic text, do as you were doing before.
} catch (NumberFormatException e) {
}

What is the correct way to get Currency Symbol in Android? [duplicate]

This question already has answers here:
How to get currency symbol by currency name?
(6 answers)
Closed 6 years ago.
This code is working fine but if I change my device langauge this is also show Rs so what the correct way to get currency symbol ?
public void displayTotlaPrice() {
TextView totalPriceTextView = (TextView) findViewById(R.id.total_Price);
totalPriceTextView.setText("Rs" + displayCalculatePrice());
}
Locale locale = Locale.getDefault();
Currency currency = Currency.getInstance(locale);
String symbol = currency.getSymbol().replaceAll("\\w", "");
try this, Hope it works.
yourString= NumberFormat.getCurrencyInstance().format(yourNumber);
or
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
String cur = currencyFormatter.format(yourValue);
for specific
yourString= NumberFormat.getCurrencyInstance(new Locale("en", "AU")).format(yourNumber);
number will format based on device language.
Detail:
How to get currency symbol by currency name?
Currency
Store below variable in string.xml
<string name="Rs">\u20B9</string>
Now call it as below wherever you want to display Rs symbol,
textView.setText(getResources().getString(R.string.Rs) + "500");
you can use,
Locale swedishLocale = new Locale("sv", "SE");
Currency currency = Currency.getInstance(swedishLocale);
System.out.println("Symbol: " + currency.getSymbol());
for more details, visit display the currency for a locale

Formatting currency in Android using wrong decimal separator

I got a bug report from a Swedish user saying that our Swedish currency was using the wrong decimal separator.
NumberFormat enUS = NumberFormat.getCurrencyInstance(Locale.US);
NumberFormat enGB = NumberFormat.getCurrencyInstance(Locale.UK);
NumberFormat svSE = NumberFormat.getCurrencyInstance(new Locale("sv", "SE"));
double cost = 1020d;
String fmt = "en_US: %s en_GB %s sv_SE %s";
String text = String.format(fmt, enUS.format(cost), enGB.format(cost), svSE.format(cost));
Log.e("Format", text);
> Format﹕ en_US: $1,020.00 en_GB £1,020.00 sv_SE 1 020:00 kr
They say that the format should be "1 020,00 kr". When I inspect the format object, it looks like it has decimalSeparator of "," in the symbols table, but a "monetarySeparator" of ":".
Does anyone know if : is actually correct, whether this is a bug in Android/java, or any sort of workaround?
It's like your user says: In Swedish thousand separator is white space " " and decimal separator is comma "," and currency symbol "kr" (Krona). So colon ":" is definitely wrong.
You can check it here too: http://www.localeplanet.com/java/sv-SE/
What Java version are you using? It works well on my desktop 1.6.0_13
-- update --
It seems that on Android there's a bug, but you can go around the bug by using the DecimalFormatSymbols like this:
DecimalFormat svSE = new DecimalFormat("#,###.00");
DecimalFormatSymbols symbols = new DecimalFormatSymbols(new Locale("sv", "SE"));
symbols.setDecimalSeparator(',');
symbols.setGroupingSeparator(' ');
svSE.setDecimalFormatSymbols(symbols);
This prints the correct separators in Android as well.

Changing the pattern for CHF currency in Java using icu package?

I wrote a java function that shows the locale pattern for each currency. See the function below. What I am interested to know is that why when the currency is CHF, the 2nd decimal is hardcoded to 5?
Note that I am using icu package and this issue doesn't exist with java.util.Currency package. I am using the default locale of en_US.
Here is the output of the function which is related to USD and CHF currencies:
Analyzing currency: [USD] localePattern: [¤#,##0.00;(¤#,##0.00)] Currency symbol [$]
Analyzing currency: [CHF] localePattern: [¤#,##0.05;(¤#,##0.05)] Currency symbol [SwF]
Here is the java function I wrote:
import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.util.Currency;
public static void main(String[] args)
{
Currency configuredCurrency = null;
NumberFormat formatter = NumberFormat.getCurrencyInstance();
DecimalFormat localeCurrencyFormatter = (DecimalFormat)formatter;
String localePattern = "";
String symbol = "";
String currencies = "AED,AFN,ALL,AMD,ARS,AUD,BGN,BHD,BND,BOB,BRL,BWP,BYR,CAD,CHF,CLP,CNY,COP,CRC,CZK,DJF,DKK,DOP,DZD,EEK,EGP,ERN,ETB,EUR,GBP,GTQ,HKD,HNL,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JOD,JPY,KES,KPW,KRW,KWD,KZT,LBP,LTL,LVL,LYD,MAD,MKD,MTL,MXN,MYR,NIO,NOK,NZD,OMR,PAB,PEN,PHP,PKR,PLN,PYG,QAR,RON,RUB,SAR,SDD,SEK,SGD,SKK,SOS,SVC,SYP,SwF,THB,TND,TRY,TZS,UAH,USD,UYU,VEB,VND,YER,ZAR,ZWD";
String[] currenciesArray = currencies.split(",");
for (int i = 0; i < currenciesArray.length; i++)
{
String currency = currenciesArray[i];
configuredCurrency = Currency.getInstance(currency);
localeCurrencyFormatter.setCurrency(configuredCurrency);
localePattern = localeCurrencyFormatter.toPattern();
symbol = localeCurrencyFormatter.getCurrency().getSymbol();
System.out.println("Analyzing currency: [" + currency + "] localePattern: [" + localePattern + "] Currency symbol [" + symbol + "]");
}
}
The 5 there is the rounding increment (there is no 0.01 of Swiss franc, 0.05 is the least valuable coin (Swiss franc wikipedia)).
Also from the icu4j DecimalFormat javadoc:
"In place of '0', the digits '1' through '9' may be used to indicate a rounding increment."
The '5' tells the ICU package that there are special rules about how to round the number to the nearest 5/100ths when converting to a string form.
"In Switzerland, five centimes are the smallest currency unit for payment transactions. For Swiss company codes and the currency Swiss franc, you therefore enter 5 ."
SAP help web site
Thank you all for the help. I was finally able to find an answer. I wrote this piece of code and did the trick:
localeCurrencyFormatter.setRoundingIncrement(new BigDecimal("0"));

Categories

Resources