Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Locale.getDefault() returns unsuported / invalid Locale for Currency.getInstance

my app uses the following code to get the local currency:

Locale locale = Locale.getDefault()
java.util.Currency localCurrency = java.util.Currency.getInstance(locale);

This workes fine in all my tests and was never a problem before. Today I saw a CrashLog in the Google Play Developer Console: The app crashes with:

java.lang.IllegalArgumentException: Unsupported ISO 3166 country: es

I can easy reproduce this error when using new Locale("es") instead of Locale.getDefault():

Locale locale = new Locale("es");
java.util.Currency localCurrency = java.util.Currency.getInstance(locale);

Actually the same exception is thrown no matter was language code I use, e.g. "en", "de", "fr", etc. Only when also the country code is specified everthing workes fine, e.g. new Locale("es", "ES")

I have two problems with Exception:

1. Why is "es" not a valid locale? As fas as I understand Locale names are formed by a language code (lowercase), and an optional country code. Thus es-ESwould be a valid locale but "es" should be as well, shouldn't it?

2. What can I do to avoid this problem? I use Locale.getDefault() all over the app to give the user locale currency, locale numberformat, etc. I would assume that the system always returns a valid Locale but this is obviously not the case. How can I make sure, that a valid locale is used?

like image 939
Andrei Herford Avatar asked Oct 15 '14 07:10

Andrei Herford


1 Answers

I have also had this issue and I feel the current answer is incomplete. This issue pops up when you run on Firebase virtual machines (you can do it as well on your emulator by selecting the respective language locales i.e. en, de,es, etc.).

I resolved this by creating a custom class which does the retrieval of the currency accounting for failure using a try:

public static Locale getLocalCurrency() {
    try {
        return Currency.getInstance(Locale.getDefault());
    } catch (NullPointerException | IllegalArgumentException ex) {
        return Currency.getInstance(new Locale("en", "US"));
    }
}

This basically assumes that if it fails it will return the locale for the US. This could easily be extended to detect the language, i.e. es, and return the relevant default.

I have extended this to all points where I use Locale for safety.

Hope that helps anyone else who looks here.

like image 134
Ben Everest Avatar answered Oct 03 '22 05:10

Ben Everest