Java 8 - 区域设置查找行为

2022-09-02 13:30:36

Java 8中引入的,基于RFC 4647,允许用户根据优先级列表找到最匹配的列表。现在我不明白这种方法的每个角落案例。下面揭示了一个我想解释的特殊情况:Locale.lookup()LocaleLocaleRange

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

这打印了我直觉所期望的。enen-GB

请注意:

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

有人能解释一下这种行为背后的原因吗?


答案 1

如果提供具有相同优先级的语言替代语言,则列表顺序将变得很重要。当您检查 解析的 列表中时,这一点变得很明显。它包含两个条目,表示 后跟"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-CHde-CHde

换句话说,指定就像指定 一样。"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);

生产。[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);

产生(注意优先顺序和缺少回退)。因此,根据上下文,您可以首先尝试从筛选列表中进行选择,并且仅在筛选列表为空时才诉诸于查找[en_US, en_GB]en

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


答案 2

获取此结果的步骤如下:

  1. 匹配吗?→ 否en-USen-GB
  2. 匹配吗?→ 否en-USen
  3. 截断为en-USen
  4. 匹配吗?→ 否enen-GB
  5. 匹配吗?→是的,找到匹配的标签,将其返回enen

它根据RFC 4647工作:

3.4. 查找

...

根据用户的优先级,找到的第一个匹配标记被视为最接近的匹配项,并且是返回的项目。

...

在查找方案中,语言范围从末尾逐渐截断,直到找到匹配的语言标记。

查找算法的核心在 中实现。您可以查看源代码sun.util.locale.LocaleMatcher#lookupTag


推荐