31

I read a file in an application that specifies a language code:

public void setResources(String locale) {

    // validate locale
    // ULocale lo = new ULocale(locale);
    // System.out.println(lo.getDisplayCountry());

}

that must be in the format: <ISO 639 language code>_<ISO 3166 region code> eg. en_UK, en_US etc. Is it possible to validate that the locale string is valid before continuing?

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
u123
  • 15,603
  • 58
  • 186
  • 303

10 Answers10

27

I do not know ULocale, but if you mean java.util.Locale, the following code may do:

public void setResources(String locale) {
  // validate locale
  Locale lo = parseLocale(locale);
  if (isValid(lo)) {
    System.out.println(lo.getDisplayCountry());
  } else {
    System.out.println("invalid: " + locale);
  }
}

private Locale parseLocale(String locale) {
  String[] parts = locale.split("_");
  switch (parts.length) {
    case 3: return new Locale(parts[0], parts[1], parts[2]);
    case 2: return new Locale(parts[0], parts[1]);
    case 1: return new Locale(parts[0]);
    default: throw new IllegalArgumentException("Invalid locale: " + locale);
  }
}

private boolean isValid(Locale locale) {
  try {
    return locale.getISO3Language() != null && locale.getISO3Country() != null;
  } catch (MissingResourceException e) {
    return false;
  }
}

EDIT: added validation

AlexVogel
  • 10,601
  • 10
  • 61
  • 71
Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94
23
isAvailableLocale(Locale locale) 

Is answer to your question.

Example:

String key= "ms-MY";
Locale locale = new Locale.Builder().setLanguageTag(key).build();
 if (LocaleUtils.isAvailableLocale(locale))
 {
  System.out.println("Locale present");
 }

Avoid using getAvailableLocales() it will return you 155 locales Its time consuming.

If possible please explore more at LocaleUtils class and Locale

VedantK
  • 9,728
  • 7
  • 66
  • 71
  • 1
    +1 for this one is more simple than that 5 y.o. aswer above. Thank you so much. I think you can use this whenever you like without concern about high ammount of loop – poring91 Jun 14 '16 at 06:04
  • 7
    but it is org.apache.commons, I dont want to include more libs – Kamil Nękanowicz Nov 07 '16 at 09:26
  • 1
    This is the best answer if you already have org.apache.commons included in your project. Also this should be the accepted answer – Srinivas Valekar Feb 22 '19 at 14:05
  • 1
    Note that the implementation of LocaleUtils.isAvailableLocale() simply iterates through a cached list of locales. The performance is slightly better due to the caching, but it doesn't avoid the linear time search (aka high amount of loop mentioned by @poring91 ). https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/LocaleUtils.java – Adam Burke Apr 03 '19 at 02:54
13

You can get the available locales like so and enumerate them to see if the locale is valid

boolean isValidLocale(String value) {
  Locale[] locales = Locale.getAvailableLocales();
  for (Locale locale : locales) {
    if (value.equals(locale.toString())) {
      return true;
    }
  }
  return false;
}
Antony Denyer
  • 1,541
  • 1
  • 15
  • 31
locka
  • 5,809
  • 3
  • 33
  • 38
  • This is very inperformant because of the large number of available locales! – Arne Burmeister Sep 10 '10 at 13:11
  • 4
    You only need to do it once and put it into a set – Rich Sep 10 '10 at 13:15
  • You could introduce a sorted list with the most used locales, which is checked first and adds new locals if confirmed, this should reduce the checks of the whole available locales! – Christopher Klewes Sep 10 '10 at 13:40
  • +1. If the resources are part of the actual application itself (and not integrated into the system from an external source or interface), I'd integrate the above code snippet into a unit test of sorts that checks all the resources filenames with the list found in `Locale.getAvailableLocales()`. – cthulhu Sep 10 '10 at 13:54
  • 1
    What about mixed locales with a language, which is not commonly spoken in selected country, like "en_RU"? It is a valid locale, but one cannot find it in the list of available locales. – 30thh Dec 06 '11 at 11:45
  • If the system doesn't know about it then you're out of luck I guess. You could I suppose decide to "special case" "en_XX" to default to en_US or something in that case. – locka Dec 12 '11 at 15:14
8

use org.apache.commons.lang.LocaleUtils.toLocale(localeString).

one-liner, other than catching java.lang.IllegalArgumentException.

Aleksander Blomskøld
  • 18,374
  • 9
  • 76
  • 82
user1876251
  • 81
  • 1
  • 1
5

commons lang has a utility method to parse and validate locale strings: LocaleUtils.toLocale(String)

After that, you just have to check whether the variant is empty:

Validate.isTrue( StringUtils.isBlank( locale.getVariant() ) );
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
3

There are plenty of answers already but for a fast one-liner:

Arrays.asList(Locale.getAvailableLocales()).contains(Locale.US)

In a method:

boolean isLocaleAvailable(Locale locale) {
   return Arrays.asList(Locale.getAvailableLocales()).contains(locale);
}
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
2

You could check if the String is contained in the Arrays returned by the getISOCountries() or getISOLanguages() methods of Locale. Its kinda crude but may actually work. You could also extract all available Locales with getAvailableLocales() and search them for display names.

kostja
  • 60,521
  • 48
  • 179
  • 224
0

I had this problem recently. With the help from Common-lang I came up with this

 public static Locale getValidLocale(final Locale locale) {

    Set<Locale> locales = LocaleUtils.availableLocaleSet();
    List<Locale> givenLocales = LocaleUtils.localeLookupList(locale, Locale.ENGLISH);
    for (Locale loc : givenLocales) {
        if (locales.contains(loc)) {
            return loc;
        }
    }
    return Locale.ENGLISH;

}

LocaleUtils.availableLocaleSet() returns all available locales, but it stores the list in a static variable, so it is iterated only once

LocaleUtils.localeLookupList() takes a locale and creates a list with different granularities.

The code basically validates your locale using a more general version until english is used as fallback.

santiagozky
  • 2,519
  • 22
  • 31
0

Now I just do:

ULocale uLocale = new ULocale(locale);
if (uLocale.getCountry() != null && !uLocale.getCountry().isEmpty()) {
  ...
}

which works fine.

u123
  • 15,603
  • 58
  • 186
  • 303
0
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidLocaleValidator.class)
@Documented
public @interface ValidLocale {
    String message() default "{constraints.validlocale}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}   

public class ValidLocaleValidator implements ConstraintValidator<ValidLocale, String> {
    private Set<String> validLocales = new HashSet<String>();

    @Override
    public void initialize(ValidLocale constraintAnnotation) {
        Locale []locales = Locale.getAvailableLocales();
        for (java.util.Locale l : locales) {
            validLocales.add(l.toString());
        }
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {        
        return validLocales.contains(value);
    }
}

public class ValidLocaleTest {    
public static class MyBeanWithLocale {
    public static final String MSG = "not a locale";

    private String l;
    public MyBeanWithLocale(String l) {
        this.l = l;
    }
    @ValidLocale(message=MSG)
    public String getL() {
        return l;
    }
    public void setL(String l) {
        this.l = l;;
    }
}

    @Test
    public void testLocale() {
        //success
        MyBeanWithLocale b1 = new MyBeanWithLocale("fr_FR");
        Jsr303.validate(b1); //equivalent to Validation.buildDefaultValidatorFactory().getValidator().validate
        //failure
        try {
        MyBeanWithLocale b2 = new MyBeanWithLocale("FRANCE");
        Jsr303.validate(b2);//equivalent to Validation.buildDefaultValidatorFactory().getValidator().validate
        Assert.fail();
        } catch (Exception e) {
        Assert.assertEquals("[" + MyBeanWithLocale.MSG + "]", e.getCause().getMessage());
        }
    }    

}