Java 8 - 区域设置查找行为

时间:2015-06-10 10:56:56

标签: java java-8 locale

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

这会打印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

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

3 个答案:

答案 0 :(得分:8)

如果您提供具有相同优先级的语言备选方案,则列表顺序将变得非常重要。当您检查已解析的"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”标签的内容。如果没有语言标签匹配      请求,返回“默认”值。

     

...

     

在查找方案中,语言范围逐渐被截断      从最后到匹配的语言标签。 ...

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

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

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

  

3.3。过滤

     

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

     

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

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

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后备)。因此,根据上下文,您可能首先尝试从筛选列表中进行选择,并且只有在筛选列表为空时才使用 lookup

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

答案 1 :(得分:4)

获得此结果的步骤如下:

  1. en-US匹配en-GB吗? →没有
  2. en-US匹配en吗? →没有
  3. en-US截断为en
  4. en匹配en-GB吗? →没有
  5. en匹配en吗? →是,找到匹配的标签,将其返回
  6. 根据RFC 4647

    运作
      

    <强> 3.4。查找

         

    ...

         

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

         

    ...

         

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

    查找算法的核心是在sun.util.locale.LocaleMatcher#lookupTag中实现的。您可以查看source code

答案 2 :(得分:3)

生成SUM(Cast((replace(replace(replace (p.[Total Sales], '$', ''), '(','-'), ')','')) as money)) - SUM(Cast((replace(replace(replace (p.[Total Cost], '$', ''), '(','-'), ')','')) as money)) / SUM(Cast((replace(replace(replace (p.[Total Sales], '$', ''), '(','-'), ')','')) as money)) as new_bal 的给定范围的解析:

    {li>

    Language Priority List优先级列表为"en-US;q=1.0,en-GB;q=1.0"]

    {li>

    [en-us;=1.0,en-gb;=1.0优先级列表为"en-GB;q=1.0,en-US;q=1.0"]

    {li>

    [en-gb;=1.0,en-us;=1.0优先级列表为"en-US;q=0.9,en-GB;q=1.0"]

然后查找方法遵循此优先级列表,直到找到匹配的区域设置(根据RFC 4647 ):

  • 对于[en-gb;=1.0,en-us;=0.9,算法首先使用en-us;=1.0,en-gb;=1.0,其中最匹配的区域设置为en-us;=1.0
  • 对于en,算法首先使用en-gb;=1.0,en-us;=1.0,其中最匹配的区域设置为en-gb;=1.0
  • 对于en-GB,算法首先使用en-gb;=1.0,en-us;=0.9,其中最匹配的区域设置为en-gb;=1.0