Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Standard way to create a Locale.LanguageRange from a Locale in Java

In Java is there a way to create a Locale.LanguageRange from a Locale?

At the moment I do this:

List<LanguageRange> ranges = 
        Locale.LanguageRange.parse(
                locale.toString()  // locale.toString() gives en_GB
                .replace('_', '-') // parse() needs en-GB
                + ";q=1.0");       // weight

It feels dirty and very inelegant.

Is there a better or even standard way to do so? I wasn't able to find one.

Minimal working example:

import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Locale.LanguageRange;

public class LanguageUtil {
        public static Locale getClosestMatch(Locale locale, Locale defaultLocale, Collection<Locale> allowedLanguages) {
            List<LanguageRange> ranges = Locale.LanguageRange.parse(
                    locale.toString().replace('_', '-') + ";q=1.0," +           //exact match e.g. en-GB -> en-GB
                    locale.getLanguage() + ";q=0.5," +                          //close match e.g. en-US -> en-GB
                    defaultLocale.toString().replace('_', '-') + ";q=0.0"));    //default match e.g. fr-FR -> en-GB
            return Locale.filter(ranges, allowedLanguages).get(0);
        }
    }
like image 917
timbernasley Avatar asked Oct 18 '22 18:10

timbernasley


1 Answers

I use new LanguageRange(locale.toLanguageTag()) to derive a LanguageRange from a Locale which takes care of the syntax.

However by feeding this to Locale.lookup() the matching is to restrictive (it would not return en_GB for en).

I therefore ended up with a two-step mechanism:

  1. filter all system locales by the requested locales
  2. lookup the best match from result list of step 1 against the supported locales

Source code:

List<Locale> allAvailableLocales = Arrays.asList(Locale.getAvailableLocales());

private Locale findBestMatch(final List<Locale> requested, final List<Locale> supported) {
    final List<LanguageRange> languageRanges = toLanguageRanges(requested);

    final List<Locale> allMatches = Locale.filter(languageRanges, allAvailableLocales);
    final Locale bestMatch = Locale.lookup(toLanguageRanges(allMatches), supported);

    return bestMatch;
}

private static List<LanguageRange> toLanguageRanges(final List<Locale> locales) {
    final ArrayList<LanguageRange> languageRanges = new ArrayList<>();
    for (final Locale locale : locales) {
        languageRanges.add(toLanguageRange(locale));
    }
    return languageRanges;
}

private static LanguageRange toLanguageRange(final Locale locale) {
    return new LanguageRange(locale.toLanguageTag());
}

Note: consider a default in case findBestMatch returns null.

like image 185
Jens Piegsa Avatar answered Oct 21 '22 08:10

Jens Piegsa