Java 8 - 区域设置查找行为

mat*_*eus 16 java locale java-8

在Java 8中引入Locale.lookup(),基于RFC 4647,允许用户Locale根据优先级列表找到最佳匹配列表LocaleRange.现在我不明白这种方法的每个角落情况.以下公开了一个我想要解释的具体案例:

// 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());
Run Code Online (Sandbox Code Playgroud)

这打印en,我会直观地预期en-GB.

注意:

  • 如果你有一个范围"en-GB;q=1.0,en-US;q=1.0"(GB和US反转),这将打印en-GB,
  • 如果你有一个范围"en-US;q=0.9,en-GB;q=1.0"(GB的优先级高于美国),这将打印出来en-GB.

有人可以解释这种行为背后的理由吗?

Hol*_*ger 9

如果您提供具有相同优先级的语言备选项,则列表顺序将变得非常重要.当您检查已解析的列表时,这一点就变得很明显了"en-US;q=1.0,en-GB;q=1.0".它包含两个条目,代表"en-US;q=1.0",后跟"en-GB;q=1.0"

请参阅https://www.ietf.org/rfc/rfc4647.txt

3.4.抬头

查找用于选择与给定请求的语言优先级列表最匹配的单一语言标记.执行查找时,根据优先级依次考虑语言优先级列表中的每个语言范围....根据用户的优先级找到的第一个匹配标签被认为是最接近的匹配,并且是返回的项目.例如,如果语言范围是"de-ch",则查找操作可以产生具有标签"de"或"de-CH"但是从不满足标签"de-CH-1996"的内容.如果没有语言标记与请求匹配,则返回"default"值.

...

在查找方案中,语言范围从结尾逐步截断,直到找到匹配的语言标记....

最后一句描述了第一段中已经通过示例说明的内容,即语言范围de-CH可能匹配de-CH或者de.对列表中的每个项目执行具有回退的查找,在找到匹配的第一个项目处停止.

换句话说,指定"en-US;q=1.0,en-GB;q=1.0"就像指定一样"en-US,en,en-GB,en".


也许你想要的是过滤,请参阅

3.3.过滤

过滤用于选择与给定语言优先级列表匹配的语言标记集....

在过滤中,每个语言范围代表最不具体的语言标记(即,具有最少数量子标记的语言标记),这是可接受的匹配.

因此,给出您可选择的区域设置的原始列表

List<Locale> filtered = Locale.filter(
    Locale.LanguageRange.parse("en-US;q=1.0,en-GB;q=1.0"), locales);
System.out.println("filtered: "+filtered);
Run Code Online (Sandbox Code Playgroud)

生产[en_GB].

Collection<Locale> locales = Arrays.asList(Locale.forLanguageTag("en"),
    Locale.forLanguageTag("en-GB"), Locale.forLanguageTag("en-US"));
List<Locale> filtered = Locale.filter(
    Locale.LanguageRange.parse("en-US;q=1.0,en-GB;q=1.0"), locales);
System.out.println("filtered: "+filtered);
Run Code Online (Sandbox Code Playgroud)

产生[en_US, en_GB](注意优先顺序和没有en后备).因此,根据上下文,您可能首先尝试从筛选列表中进行选择,并且仅在筛选列表为空时才进行查找.

至少,Java实现的行为符合规范.如您所述,更改优先级或更改顺序(当优先级相等时),根据规范更改结果.