views:

923

answers:

6

Hello,

I'm working on an international project and have observed that, in Java, the choice of the decimal separator is based on the Locale's language, not its country. For example:

DecimalFormat currencyFormatter = (DecimalFormat) NumberFormat.getInstance(new Locale("it","IT"));
System.out.println(currencyFormatter.format(-123456.78));

currencyFormatter = (DecimalFormat) NumberFormat.getInstance(new Locale("en","IT"));
System.out.println(currencyFormatter.format(-123456.78));

produces the following output:

-123.456,78
-123,456.78

I would have expected it to follow the country, since if I'm in the country, whether I speak English or Italian the numbers in that country are written with the decimal separator as comma.

My question is two-fold:

  1. Does anyone know why this behaviour follows the language?
  2. More importantly, can anyone offer details as to how to modify the default behaviour in Java to follow the language instead?

Thanks.

+2  A: 

But if you are an Englishman living in Italy, chances are you still write your numbers the English way and count your money in pounds inside your head - and vice versa ;-)

So to me this behaviour looks perfectly logical. And I am afraid there may not be a way to get what you want :-(

Update based on the comment of Oscar Reyes: In Java 6, NumberFormatProvider enables you to achieve your goal.

Péter Török
+1. Formatting numbers is a matter of language, not of where you are.
OregonGhost
But for a software system wouldn't you want to format the currency always according to the country's currency?
chenson42
@chenson42 Well I can only speak for myself with certainty. Having been living in Spain, Finland and India apart from my native Hungary, still I always preferred to see numbers, date and time on my computer screen the Hungarian style, not the local way. An OS or a personal app is quite different in this respect of course, than e.g. an ERP or financial application. But guess which one is used by more people...
Péter Török
-1 There is since Java 1.6 you have NumberFormatProvider
OscarRyz
A: 

I think you might be able to override the NumberFormat behavior per Locale using LocaleServiceProvider. This would require Java 6 though ...

chenson42
+1  A: 

Modifying all of Java is a big order; as far as I know, there's no way to do this at the JVM level. However, you can manually set the number format for your particular classes/projects to pretty much any locale (or even imaginary system) with the DecimalFormatSymbols class. See "Altering the Formatting Symbols" at the Java Tutorials page on format customization for examples and more information.

Granted, this is not an optimal approach if your program might be used in more than three or four different locations, but it could work if you're only supporting a few.

Lord Torgamus
+3  A: 

It is very, very likely that there is no known "en_IT" locale on your system and that Java knows of no such locale.

Therefore you'll get the resources for the closest matching Locale, as per this note in the JavaDoc of Locale:

When you ask for a resource for a particular locale, you get back the best available match, not necessarily precisely what you asked for. For more information, look at ResourceBundle.

The relevant documentation in ResourceBundle shows that the country alone is never attempted as the identifier to find a given resource. Only the language, the language + the country and the language + the country + the variant are used.

Joachim Sauer
-1 : Unfortunately this doesn't help to the second part of the question: *can anyone offer details as to how to modify the default behavior in Java to follow the country instead?*
OscarRyz
-1 for a good answer that answers one part of a two-part question? Re-read the tooltip of the down-arrow and ask yourself if that applies here ...
Joachim Sauer
+1  A: 

Your assumption "I would have expected it to follow the country, since if I'm in the country, whether I speak English or Italian the numbers in that country are written with the decimal separator as comma." is wrong. Several bilingual countries have language specific formatting rules for numbers. Among the countries with formatting rules in Sun's JDK, this applies to Canada, India and Luxembourg.

jarnbjo
+1  A: 

1.- Does anyone know why this behaviour follows the language?

One of the first aspects that change in an application according to its locale is the language. Think of Switzerland, where they have both French and German as official languages. Using the country in this scenario makes no sense because, besides currency there are other aspect ( such as display messages, to take into consideration )

Same goes for a number of countries ( Canada is other that comes to my mind).

The country is an option to specialize that language.

Since there is no "Italian English" en_IT doesn't make much sense. So it takes "english" and that's why the returned instance is the one with "en" English.

2.- More importantly, can anyone offer details as to how to modify the default behavior in Java to follow the language instead?

You mean, the country right?

The answer is in the method: NumberFormat.getAvailableLocales() which in turn leads you to: NumberFormatProvider which is an abstract class you can extend to return the correct NumberFormat for "en_IT" ( which pretty much will return it_IT )

How to install that new class goes beyond my knowledge, but I think you'll have to hack it somewhere in the jre directory.

EDIT

As I suspect the class should be installed under jre/ext folder and that's it.

There is a project somewhere else which did something similar to support "gl_ES" ( Galician )

Here's instructions on how to install it and what it is all about:

http://www.javagalician.org/install.html

So, basically, if you want to provide a bunch of instances for Italy ( or even better a single one ) , you just have to create one instance of the NumberFormatProvider and have it responding all the languages available.

OscarRyz