文档

Java™ 教程-Java Tutorials 中文版
语言标签过滤和查找
Trail: Internationalization
Lesson: Setting the Locale

语言标签过滤和查找

Java 编程语言包含对语言标签,语言标签过滤和语言标签查找的国际化支持。这些功能由 IETF BCP 47 指定,其中包含 RFC 5646 "Tags for Identifying Languages"RFC 4647 "Matching of Language Tags." 本课程描述了如何在 JDK 中提供此支持。

什么是语言标签?

语言标签是特殊格式的字符串,提供有关特定语言的信息。语言标签可能是简单的(例如英语中的“en”),复杂的(例如“zh-cmn-Hans-CN”表示中文中使用的普通话,简体中文),或介于两者之间的东西(例如“sr-Latn”,塞尔维亚语用拉丁文写成)。语言标签由连字符分隔的“子标签”组成;在整个 API 文档中使用此术语。

java.util.Locale 类提供对语言标签的支持。Locale 包含几个不同的字段:语言(例如英语的“en”或日语的“ja”),脚本(例如拉丁语的“Latn”或西里尔语的“Cyrl”),国家/地区(例如美国的“US”或法国的“FR”),变体(表示某个语言环境的变体)和扩展(它提供单个字符键到 String 值的映射,指示除语言识别之外的扩展)。要从语言标签 String 创建 Locale 对象,请调用 Locale.forLanguageTag(String),传入语言标签作为唯一的参数。这样做会创建并返回一个新的 Locale 对象,以便在你的应用程序中使用。

例子1:

package languagetagdemo;

import java.util.Locale;

public class LanguageTagDemo {
     public static void main(String[] args) {
         Locale l = Locale.forLanguageTag("en-US");
     }
}

请注意,Locale API 仅要求你的语言标签在语法上格式良好。它不执行任何额外验证(例如检查标签是否在 IANA 语言子标签注册表中注册)。

什么是语言范围?

语言范围(由类 java.util.Locale.LanguageRange 表示)标识共享特定属性的语言标签集。语言范围分为基本或扩展,与语言标签类似,它们由连字符分隔的子标签组成。基本语言范围的示例包括“en”(英语),“ja-JP”(日语,日本)和“*”(与任何语言标签匹配的特殊语言范围)。扩展语言范围的示例包括“*-CH”(任何语言,瑞士),“es-*”(西班牙语,任何地区)和“zh-Hant-*”(繁体中文,任何地区)。

此外,语言范围可以存储在语言优先级列表中,这使得用户能够在加权列表中优先考虑他们的语言偏好。语言优先级列表通过将 LanguageRange 对象放入 java.util.List 来表示,然后可以将其传递给 Locale 接受 LanguageRange 对象的 List 的方法。

创建语言范围

Locale.LanguageRange 类提供了两种不同的构造函数来创建语言范围:

它们之间的唯一区别是第二个版本允许指定权重;如果将范围放入语言优先级列表,则将考虑此权重。

Locale.LanguageRange 还指定了一些与这些构造函数一起使用的常量:

MAX_WEIGHT 常量值为 1.0,表示它非常适合用户。MIN_WEIGHT 常量保持值 0.0,表示不适合用户。

例子2:

package languagetagdemo;

import java.util.Locale;

public class LanguageTagDemo {

     public static void main(String[] args) {
         // Create Locale
         Locale l = Locale.forLanguageTag("en-US");

         // Define Some LanguageRange Objects
         Locale.LanguageRange range1 = new Locale.LanguageRange("en-US",Locale.LanguageRange.MAX_WEIGHT);
         Locale.LanguageRange range2 = new Locale.LanguageRange("en-GB*",0.5);
         Locale.LanguageRange range3 = new Locale.LanguageRange("fr-FR",Locale.LanguageRange.MIN_WEIGHT);
     }
}

例子2 创建了三种语言范围:英语(美国),英语(英国)和法语(法国)。按照从最优选到最不优选的顺序对这些范围进行加权以表示用户的偏好。

创建语言优先级列表

你可以使用 LanguageRange.parse(String) 方法从语言范围列表中创建语言优先级列表。此方法接受逗号分隔语言范围列表,对给定范围内的每个语言范围执行语法检查,然后返回新创建的语言优先级列表。

有关“范围”参数所需格式的详细信息,请参阅此方法的 API 规范。

例子3:

package languagetagdemo;

import java.util.Locale;

import java.util.List;

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create Locale

        Locale l = Locale.forLanguageTag("en-US");

        // Create a Language Priority List

        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";

        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges)

    }
}

例子3 创建与例子 2 相同的三种语言范围,但将它们存储在 String 对象中,该对象将传递给 parse(String) 方法。LanguageRange 对象的返回 List 是语言优先级列表。

过滤语言标签

语言标签过滤是将一组语言标签与用户的语言优先级列表进行匹配的过程。过滤结果将是所有匹配结果的完整列表。Locale 类定义了两个返回 Locale 对象列表的过滤器方法。他们的签名如下:

在这两种方法中,第一个参数指定用户的语言优先级列表,如上一节中所述。

第二个参数指定要匹配的 Locale 对象的 Collection。匹配本身将根据 RFC 4647 指定的规则进行。

第三个参数(如果提供)指定要使用的“过滤模式”。Locale.FilteringMode 枚举提供了许多不同的值可供选择,例如 AUTOSELECT_FILTERING(用于基本语言范围过滤)或 EXTENDED_FILTERING(用于扩展语言范围过滤)。

例子4 提供了语言标签过滤的演示。

例子4:

package languagetagdemo;

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

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create a collection of Locale objects to filter
        Collection<Locale> locales = new ArrayList<>();
        locales.add(Locale.forLanguageTag("en-GB"));
        locales.add(Locale.forLanguageTag("ja"));
        locales.add(Locale.forLanguageTag("zh-cmn-Hans-CN"));
        locales.add(Locale.forLanguageTag("en-US"));

        // Express the user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Now filter the Locale objects, returning any matches
        List<Locale> results = Locale.filter(languageRanges,locales);

        // Print out the matches
        for(Locale l : results){
        System.out.println(l.toString());
        }
    }
}

这个程序的输出是:

en_US
en_GB

此返回列表根据用户的语言优先级列表中指定的权重进行排序。

Locale 类还定义了 filterTags 方法,用于将语言标签过滤为 String 对象。

方法签名如下:

例子5 提供与例子 4 相同的搜索,但使用 String 对象而不是 Locale 对象。

例子5:

package languagetagdemo;

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

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create a collection of String objects to match against
        Collection<String> tags = new ArrayList<>();
        tags.add("en-GB");
        tags.add("ja");
        tags.add("zh-cmn-Hans-CN");
        tags.add("en-US");

        // Express user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Now search the locales for the best match
        List<String> results = Locale.filterTags(languageRanges,tags);

        // Print out the matches
        for(String s : results){
            System.out.println(s);
        }
    }
} 


和以前一样,搜索将匹配并返回“en-US”和“en-GB”(按此顺序)。

执行语言标签查找

与语言标签过滤相反,语言标签查找是将语言范围与语言标签集匹配并返回与该范围最匹配的一种语言标签的过程。RFC4647 声明:“查找从可用标签列表中生成最符合用户首选项的单个结果,因此在需要单个项目(并且只能返回单个项目)的情况下,它非常有用。例如,如果一个过程要将人类可读的错误消息插入协议头,则可以根据用户的语言优先级列表选择文本。由于该过程只能返回一个项目,因此它被强制选择一个项目,并且必须返回一些项目,即使内容的语言标签都没有与用户提供的语言优先级列表相匹配。“

例子6:

package languagetagdemo;

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

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create a collection of Locale objects to search
        Collection<Locale> locales = new ArrayList<>();
        locales.add(Locale.forLanguageTag("en-GB"));
        locales.add(Locale.forLanguageTag("ja"));
        locales.add(Locale.forLanguageTag("zh-cmn-Hans-CN"));
        locales.add(Locale.forLanguageTag("en-US"));

        // Express the user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.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());
    }
}

与过滤示例相反,例子 6 中的查找演示返回最匹配的一个对象(在本例中为 en-US)。为了完整起见,示例 7 显示了如何使用 String 对象执行相同的查找。

例子7:

package languagetagdemo;

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

public class LanguageTagDemo {

    public static void main(String[] args) {
        // Create a collection of String objects to match against
        Collection<String> tags = new ArrayList<>();
        tags.add("en-GB");
        tags.add("ja");
        tags.add("zh-cmn-Hans-CN");
        tags.add("en-US");

        // Express user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Find the BEST match, and return just one result
        String result = Locale.lookupTag(languageRanges, tags);
        System.out.println(result);
    }
} 

此示例返回与用户的语言优先级列表最匹配的单个对象。


Previous page: Identifying Available Locales
Next page: The Scope of a Locale