Introduced in Java 8, Locale.lookup()
, based on RFC 4647, allows the user to find the best match for a list of Locale
according a priority list of LocaleRange
. Now I don't understand every corner case for this method. The following exposes one particular case I would like to have an explanation for:
// Create a collection of Locale objects to search
Collection<Locale> locales = new ArrayList<>();
locales.add(Locale.forLanguageTag("en-GB"));
locales.add(Locale.forLanguageTag("en"));
// Express the user's preferences with a Language Priority List
String ranges = "en-US;q=1.0,en-GB;q=1.0";
List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);
// Find the BEST match, and return just one result
Locale result = Locale.lookup(languageRanges,locales);
System.out.println(result.toString());
This prints en
, where I would have intuitively expected en-GB
.
Note that:
- if you have a range of
"en-GB;q=1.0,en-US;q=1.0"
(GB and US reversed), this will printen-GB
, - and if you have a range of
"en-US;q=0.9,en-GB;q=1.0"
(GB has a higher priority than US), this will printen-GB
.
Could someone explain the rationale behind this behavior?
If you provide language alternatives with the same priority, the list order becomes significant. This becomes apparent when you inspect the parsed list of
"en-US;q=1.0,en-GB;q=1.0"
. It contains two entries, representing"en-US;q=1.0"
, followed by"en-GB;q=1.0"
See https://www.ietf.org/rfc/rfc4647.txt
The last sentence describes what has already said by example in the first paragraph, i.e. a language range of
de-CH
might match eitherde-CH
orde
. This lookup with fallback is performed for each item of the list, stopping at the first one for which a match is found.In other words, specifying
"en-US;q=1.0,en-GB;q=1.0"
is like specifying"en-US,en,en-GB,en"
.Maybe what you want is filtering, see
Thus, given your original list of selectable locales
produces
[en_GB]
.whereas
produces
[en_US, en_GB]
(note the prioritized order and the absence of anen
fallback). So depending on the context you may attempt to select from a filtered list first and only resort to lookup when the filtered list is empty.At least, the behavior of Java’s implementation is in line with the specification. As you already noted, changing the priority or changing the order (when the priority is equal), changes the result according to the specification.