简体   繁体   中英

How to validate a locale in java?

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?

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

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

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;
}

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

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

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() ) );

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);
}

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.

@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());
        }
    }    

}

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.

Now I just do:

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

which works fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM