Google+ Badge

Wednesday, September 29, 2010

Internationalization in Java - when is a number not a number?

The Java product I work on is internationalized and localized - well it turns out for the most part. I updated the code some time back to allow the user to type in numbers in their locale so a German speaking user can type 600,25 (notice the comma instead of a decimal point) and we should consider that to be 600.25 in English.

Two problems arose, the masked entry field I wrote handled this just fine allowing user to type in numbers using their locale settings but the code in others areas converted the typed text to a Double using Double.valueOf(text) and it would fail by tossing and exception. I switched the code to NumberFormat.getInstance().parse(text), adjusted to catch the proper exception and everything now works. This code area allows users to enter custom property values.

One thing I found out, NumberFormat returns a Number. That might be a Double or a Long. If you parse 85 you get a Long. If you parse 85.43 you get a Double. You can ask the Number for its doubleValue if you always want the double. I was getting a typecast error on occasion until I figured this out. If you send in an empty string you get a parse error. You may want to check for that before you parse to assign a default value of Double.MAX_VALUE to indicate empty or 0 if you want empty strings to equal a zero value.

Second problem came from the advanced search area where we allow users to search for previously entered data. We used the same masked entry control but never converted the output to a number. The server takes the search statement as a string so there seemed to be no need. Of course there is a need. The code looks a bit silly but I take the text, convert to a number and convert back to text so it will be in English format to send to the server.
String numOne = numberFieldOne.getText();

// We convert to a number then back to text for i18n reasons
// All numbers set to server in English format, this forces that rule
   numOne = NumberFormat.getInstance().parse(numOne).toString();
catch (ParseException e)
   numOne = numberFieldOne.getText();

Everything is up and running again. The company has a big push toward international expansion so it was critical that we solved these issues. I must say Eclipse pop-up help on methods is very handy. I viewed the pop-up for Integer.valueOf and it suggested using NumberFormat instead. I love it when you are handed the answer without needing to do a web search right from the IDE.

Converting existing code to i18n can be painful, making it i18n from the start and keeping it that way can be a big help. I will add this discovery to my i18n toolbox. Seems pretty rare for users to type in floating point values but it does happen and you need to account for it.