AgentKnopf
AgentKnopf

Reputation: 4345

Java NumberFormat: Missing Currency Symbols for Portugal, Luxembourg and others

Within the scope of an Android application (language used is Java), I want to display a list of countries and their respective currencies. However there are a few oddities:

  1. For some locales the value returned by getDisplayCountry() is empty (so I filter those countries out)
  2. Some countries appear multiple times when listing them via NumberFormat.getAvailableLocales(), any idea why?
  3. Some countries have one entry which has a currency symbol and a currency code as well as one or more further entries with a currency code but no currency symbol (indicated by an "¤")
  4. Some countries have no entry with a currency symbol at all, such as Portugal and Luxembourg, both of which have the Euro. However it can't be for a lack of that Symbol being present, as Germany has the Euro Symbol.

Here is the piece of code that creates the list I later display:

List<String> countries = new ArrayList<String>();
List<Locale> locales = new ArrayList<Locale>();

// Explicitly check for Locales needed to create currencies
Locale[] locales = NumberFormat.getAvailableLocales();
for (Locale locale : locales) {
  if (!locale.getDisplayCountry().isEmpty()) {
    String country = locale.getDisplayCountry();
    String currencySymbol = CurrencyAmount.getCurrencySymbol(locale);

    String formatted = String.format("%s,  %s", country, currencySymbol);
    Log.i(TAG, formatted);
        countries.add(formatted);
    locales.add(locale);
  }
}

The above code produces the following log statements (excerpt):

01-27 15:50:25.742: I/de.zainodis.SelectCurrency(13281): Deutschland, €

01-27 15:50:25.882: I/de.zainodis.SelectCurrency(13281): Portugal, ¤

01-27 15:50:25.742: I/de.zainodis.SelectCurrency(13281): Schweiz, CHF

01-27 15:50:25.742: I/de.zainodis.SelectCurrency(13281): Luxemburg, ¤
01-27 15:50:25.820: I/de.zainodis.SelectCurrency(13281): Luxemburg, ¤

01-27 15:50:25.906: I/de.zainodis.SelectCurrency(13281): Taiwan, ¤
01-27 15:50:25.914: I/de.zainodis.SelectCurrency(13281): Taiwan, NT$

I slightly modified the above code, to only display entries, where getInstance(locale) does not throws an IllegalArgumentException. That is the case if the locale's country is not a supported ISO 3166 country. The modified code...

List<String> countries = new ArrayList<String>();
List<Locale> locales = new ArrayList<Locale>();

Locale[] locales = NumberFormat.getAvailableLocales();
for (Locale locale : locales) {
  if (!locale.getDisplayCountry().isEmpty()) {
    String country = locale.getDisplayCountry();
    String currencySymbol = CurrencyAmount.getCurrencySymbol(locale);

    try {
       Currency currency = Currency.getInstance(locale);
       String formatted = String.format("%s,  %s, %s", country, currencySymbol,
            currency.getCurrencyCode());
       Log.i(TAG, String.format("%s, %s", country, currencySymbol));
       SelectCurrency.countries.add(formatted);
       SelectCurrency.locales.add(locale);

    } catch (IllegalArgumentException e) {
       // Skip these countries
    }
  }
}

...and the output (excerpt):

01-27 15:55:01.453: I/de.zainodis.SelectCurrency(13725): Deutschland,  €, EUR

01-27 15:55:01.632: I/de.zainodis.SelectCurrency(13725): Portugal,  ¤, EUR

01-27 15:55:01.453: I/de.zainodis.SelectCurrency(13725): Schweiz,  CHF, CHF

01-27 15:55:01.468: I/de.zainodis.SelectCurrency(13725): Luxemburg,  ¤, EUR
01-27 15:55:01.578: I/de.zainodis.SelectCurrency(13725): Luxemburg,  ¤, EUR

01-27 15:55:01.664: I/de.zainodis.SelectCurrency(13725): Taiwan,  NT$, TWD

Since I want to display a list of countries, each with their respective currencies (as a Symbol) what would I do in case of countries such as Portugal or Luxembourg, that have no currency symbol attached? I know I could alternatively show the currency code, however since I'll render amounts with their respective currencies into the UI, I'd rather go for those symbols... I guess I could filter countries out where the currency symbol is "¤" but I wonder: is it guaranteed to be that symbol on each Android device across the world? And what if someone happens to live in Portugal or Luxembourg... ?

This is how it, what it looks like right now:

enter image description here

In this example screenshot, Belgium's entry has no currency symbol (should be the € symbol), however later in the list, there is another Belgium entry (several actually...) which looks like this:

enter image description here

So in case of Belgium, I could simply kick out the one that has "¤" as it's currency symbol, but what about countries such as Portugal, which have no entry with a proper currency symbol?

Upvotes: 2

Views: 2105

Answers (2)

Anatolii Shuba
Anatolii Shuba

Reputation: 6185

Yes, it is a Google issue that has been fixed in Android v.4.3 only. I am using workaround below to fix this issue for devices with pt_PT locale.

if (Locale.getDefault().toString().equals("pt_PT")) {
       mCurrencyNumberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault());
       DecimalFormatSymbols dfs = ((DecimalFormat)mCurrencyNumberFormat).getDecimalFormatSymbols();
       dfs.setCurrencySymbol("\u20AC");
       ((DecimalFormat)mCurrencyNumberFormat).setDecimalFormatSymbols(dfs);
}

So € symbol now shown instead of buggy ¤ symbol. Enjoy )))

Upvotes: 1

StarsSky
StarsSky

Reputation: 6711

Ther's an issue in google code issue

// http://code.google.com/p/android/issues/detail?id=38622
    public void test_getSymbol_38622() throws Exception {
        // The CLDR data had the Portuguese symbol for "EUR" in pt, not in pt_PT.
        // We weren't falling back from pt_PT to pt, so we didn't find it and would
        // default to U+00A4 CURRENCY SIGN (¤) rather than €.
        Locale pt_BR = new Locale("pt", "BR");
        Locale pt_PT = new Locale("pt", "PT");
        assertEquals("R$", Currency.getInstance(pt_BR).getSymbol(pt_BR));
        assertEquals("BR$", Currency.getInstance(pt_BR).getSymbol(pt_PT));
        assertEquals("€", Currency.getInstance(pt_PT).getSymbol(pt_BR));
        assertEquals("€", Currency.getInstance(pt_PT).getSymbol(pt_PT));
    }

Upvotes: 1

Related Questions