How to validate & instantiate Java Locale from strings? - java

My app is being fed string from an external process, where each string is either 2- or 5-characters in length, and represents a java.util.Locales. For example:
en-us
ko
The first example is a 5-char string where "en" is the ISO language code, and "us" is the ISO country code. This should correspond to the "en_US" Locale. The second example is only a 2-char string, where "ko" is the ISO language code, and should correspond to the "ko_KR" (Korean) Locale.
I need a way to take these strings (either the 2- or 5-char variety), validate it (as a supported Java 6 Locale), and then create a Locale instance with it.
I would have hoped that Locale came with such validation out of the box, but unfortunately this code runs without exceptions being thrown:
Locale loc = new Locale("waawaaweewah", "greatsuccess");
// Prints: "waawaaweewah"
System.out.println(loc.getDisplayLanguage());
So I ask, given me the 2 forms that these string will be given to me in, how can I:
Validate the string (both forms) and throw an exception for strings corresponding to non-existent or unsupported Java 6 Locales; and
Instantiate a new Locale from the string? This question really applies to the 2-char form, where I might only have "ko" and need it to map to the "ko_KR" Locale, etc.
Thanks in advance!

Locale.getISOCountries() and Locale.getISOLanguages()
return a list of all 2-letter country and language codes defined in ISO 3166 and ISO 639 respectively and can be used to create Locales.
You can use this to validate your inputs.

You have two options,
Use a library for doing this commons-lang has the LocaleUtils class that has a method that can parse a String to a Locale.
While your own method, the validation here is non trivial as there are a number of different sets of country codes that a valid for a Locale - see the javadoc
A starting point would be to split the String and switch on the number of elements:
public static Locale parseLocale(final String locale) {
final String[] localeArr = locale.split("_");
switch (localeArr.length) {
case 1:
return new Locale(localeArr[0]);
case 2:
return new Locale(localeArr[0], localeArr[1]);
case 3:
return new Locale(localeArr[0], localeArr[1], localeArr[2]);
default:
throw new IllegalArgumentException("Invalid locale format;");
}
}
Presumably you would need to get lists of all valid country codes and languages and compare the elements in the String[] to the valid values before calling the constructor.

Related

Why does the NumberFormat returns blank fields?

So a few days ago I encountered a weird problem however, I didn't change any that kind of code. The problem is the format I'm getting from my method which I used for years. All commas are now spaces (blank fields) and I have no idea what is causing this.
public static String toFancyCost(int num) {
return NumberFormat.getInstance().format((Integer) num);
}
Before even this happened the String I received was looking like for example 2,181,273 and not like 2 181 273.
You must have changed your system locale by accident. The implementation of NumberFormat.getInstance() (on 1.8.0_131):
public final static NumberFormat getInstance() {
return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
}
It uses formatting specified by the default locale. and the java docs on Locale.getDefault say:
The Java Virtual Machine sets the default locale during startup based
on the host environment. It is used by many locale-sensitive methods
if no locale is explicitly specified. It can be changed using the
setDefault method.
If you were to use NumberFormat.getInstance(Locale) you can specify which locale the NumberFormat should use.
Your systems default local is using a space as thousands separator, number format retured by getInstance() uses settings from system's default local.
As commented above, somehow the system default may have been modified. Let's stick the code to set the locale when formatting by using below to avoid any issues.
int number = 345678987;
NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.US);// Locale.US or any other locale you required
String numberAsString = numberFormat.format(number);
System.out.println(numberAsString);
response:
345,678,987
when I use the below for example with Locale.CANADA_FRENCH
int number = 345678987;
NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.CANADA_FRENCH);
String numberAsString = numberFormat.format(number);
System.out.println(numberAsString);
response:
345 678 987
So in your case also locale may have been causing issues, so please explictly set locale.

How to get iso2code from a country name by locale

I have a form that user enter a country name, then I have to convert it to iso2 or iso3 code.
How is it possible? I prefer not to use map, as it seems not running on my Android app.
This code is for converthing iso2 to an actual name, I want the other way around:
Locale l = new Locale("", "CH");
System.out.println(l.getDisplayCountry());
Have you tried Locale.getISO3Country() ?
To actually do the conversion, you might need to loop through all the available locales and look for the one whose getDisplayCountry() matches your input country name.
It doesn't sound efficient (but you said to not use maps), but you might try something like:
Locale convertCountryNameToIsoCode(String countryName)
for(Locale l : Locale.getAvailableLocales()) {
if (l.getDisplayCountry().equals(countryName)) {
return l;
}
}
return null;
}
http://docs.oracle.com/javase/7/docs/api/java/util/Locale.html#getISO3Country()
However, if the input comes from a web form, than it would be easier to set the country code directly as the web form input value. If the input comes from an Android native App, then I'm not sure but I'd bet you might a similar thing

Locale appending 'variation' to language and country code

LocaleContext.getLocale() returns the locale object currently as 'en_US_WOL'. I verified the locale object using breakpoint and looks like en- language English, US - country code of US, WOL - variation (a field of Locale object).
How and why is the variation field getting appending and returned for getLocale() method? and how can I stop that? (LocaleContext is of type ThreadLocal)
According to http://docs.oracle.com/javase/6/docs/api/java/util/Locale.html
The variant argument is a vendor or browser-specific code. For example, use WIN for Windows, MAC for Macintosh, and POSIX for POSIX. Where there are two variants, separate them with an underscore, and put the most important one first. For example, a Traditional Spanish collation might construct a locale with parameters for language, country and variant as: "es", "ES", "Traditional_WIN".
If you're after Locale for specific variant, I presume you can use this constructor:
Locale(String language, String country, String variant)
Or adjust your browser's locale settings (if your application involves browser at all)
I had a problem with this too. Unfortunately I haven't found any build-in method to nicely output lang-country code without Variant so I helped myself with such snippet (maybe would be handy to somebody) :
public static String getLanguageCode(Locale locale) {
StringBuilder sb = new StringBuilder();
sb.append(locale.getLanguage());
if (locale.getCountry() != null && locale.getCountry().length() > 0) {
sb.append("-");
sb.append(locale.getCountry());
}
return sb.toString();
}

Setting Turkish and English locale: translate Turkish characters to Latin equivalents

I want to translate my Turkish strings to lowercase in both English and Turkish locale. I'm doing this:
String myString="YAŞAT BAYRI";
Locale trlocale= new Locale("tr-TR");
Locale enLocale = new Locale("en_US");
Log.v("mainlist", "en source: " +myString.toLowerCase(enLocale));
Log.v("mainlist", "tr source: " +myString.toLowerCase(trlocale));
The output is:
en source: yaşar bayri
tr source: yaşar bayri
But I want to have an output like this:
en source: yasar bayri
tr source: yaşar bayrı
Is this possible in Java?
If you are using the Locale constructor, you can and must set the language, country and variant as separate arguments:
new Locale(language)
new Locale(language, country)
new Locale(language, country, variant)
Therefore, your test program creates locales with the language "tr-TR" and "en_US". For your test program, you can use new Locale("tr", "TR") and new Locale("en", "US").
If you are using Java 1.7+, then you can also parse a language tag using Locale.forLanguageTag:
String myString="YASAT BAYRI";
Locale trlocale= Locale.forLanguageTag("tr-TR");
Locale enLocale = Locale.forLanguageTag("en_US");
Creates strings that have the appropriate lower case for the language.
I think this is the problem:
Locale trlocale= new Locale("tr-TR");
Try this instead:
Locale trlocale= new Locale("tr", "TR");
That's the constructor to use to specify country and language.
you can do that:
Locale trlocale= new Locale("tr","TR");
The first parameter is your language, while the other one is your country.
If you just want the string in ASCII, without accents, the following might do.
First an accented character might be split in ASCII char and a combining diacritical mark (zero-width accent). Then only those accents may be removed by regular expression replace.
public static String withoutDiacritics(String s) {
// Decompose any ş into s and combining-,.
String s2 = Normalizer.normalize(s, Normalizer.Form.NFD);
return s2.replaceAll("(?s)\\p{InCombiningDiacriticalMarks}", "");
}
Characters ş and s are different characters. Changing locale cannot help you to translate one to another. You have to create turkish-to-english characters table and do this yourself. I once did this for Vietnamic language that has a lot of such characters. You have to deal with 4 of 5, right? So, good luck!

Temporary displaying text (not dates) in a different language

I'm trying to display some message on the screen in a different language (but keeping the dates in the default language, uk_eng), depending on what user is looking at the screen. Being only a temporary setting I was wondering what's the best way to do it in Java.
You could have message bundles for each Locale. Load these and display them appropriately when you identify the user's Locale.
An example is at http://java.sun.com/developer/onlineTraining/Programming/BasicJava2/int.html
You could load these in a web app too like http://www.devsphere.com/mapping/docs/guide/internat.html
If I see the problem well, you want to display messages with MessageFormat like this:
Object[] arguments = {
new Integer(7),
new Date(System.currentTimeMillis()),
"a disturbance in the Force"
};
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
arguments);
(Example from javadoc)
I checked the source of the MessageFormat and I see that getLocale() is common for the whole message. You cannot make a distinct one for a parameter.
Why don't you make a parameter with the formatted date string itself? Like this:
Object[] arguments = {
new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa", Locale.UK).format(new Date())
};
String result = MessageFormat.format(
"This is the date format which I always want independently of the locale: {1} ",
arguments);
The first parameter of the format methods may come from localized property files.

Categories

Resources