【译】使用Java Locale进行国际化
前言
在开发软件应用程序时,我们经常强调尊重用户语言和地理区域的重要性和价值。允许用户用他们自己的语言与软件交流可能会大大促进软件的销售。在Java
语言环境中, Locale
则用来阐明国际化过程。
什么是Locale
java.util.Locale
是Java Locale
的实现类。要为应用程序定义区域设置(语言、国家和变体),您将使用 Locale 对象,它只是一个标识符。真正的本地化是由区域敏感类完成的。您从对区域设置敏感的类创建的对象可以自定义如何格式化和向用户呈现数据。这些类通过 Locale
对象来感知应用程序中使用的语言环境.NumberFormat
类就是一个很好的例子。比如,对于法国,NumberFormat
表示为 302 400
,德国为 302 .400
, 美国则是302,400
。
在Java
标准API
中, 常见的区域敏感类有:
NumberFormat
DateFormat
DecimalFormat
创建Java Locale对象
现在让我们深入研究代码。有四种方法可以创建 Locale
对象。
Locale
构造函数Locale.Builder
类Locale.forLanguageTag
工厂方法Locale
常量
使用Locale构造函数
有三个可用于创建 Locale 对象的构造函数。
Locale(String language)
: 仅用语言来创建语言环境对象:Locale locale = new Locale("en");
Locale(String language, String country)
: 使用语言和国家来创建语言环境对象:Locale locale = new Locale("en", "US");
Locale(String language, String country, String variant)
: 使用所有三个组件——语言、国家和变体——来创建语言环境对象:Locale locale = new Locale("en", "US", "SiliconValley");
这是使用Locale
构造函数的完整示例:
Locale deLocale = new Locale("de", "De");
Locale usLocale = new Locale("en", "US");
Locale zhLocale = new Locale("zh", "CN");
long number = 123456789L;
NumberFormat denf = NumberFormat.getInstance(deLocale);
NumberFormat usnf = NumberFormat.getInstance(usLocale);
NumberFormat zhnf = NumberFormat.getInstance(zhLocale);
System.out.println(denf.format(number));
System.out.println(usnf.format(number));
System.out.println(zhnf.format(number));
Date now = new Date();
DateFormat usdf = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, usLocale);
DateFormat dedf = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, deLocale);
DateFormat zhdf = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, zhLocale);
System.out.println(usdf.format(now));
System.out.println(dedf.format(now));
System.out.println(zhdf.format(now));
在输出中,可以看到德语,美国英语和中国如何显示数字和日期:
123.456.789
123,456,789
123,456,789
December 12, 2021 1:02:53 PM CST
12. Dezember 2021 13:02:53 CST
2021年12月12日 下午01时02分53秒
使用Locale.Builder类
您还可以使用 Locale.Builder
类来创建 Locale
对象。这个类只有一个构造函数,不带任何参数。您必须使用一系列 setter
方法来指定language
、country
和variant
。
Locale locale = new Locale.Builder().setLanguage("de").setRegion("CA").build();
使用Locale.forLanguageTag工厂方法
IETF BCP 47
是定义语言标签以识别区域设置的标准,Java SE 7
包符合它。您可以使用 IETF BCP 47
标准语言标签通过 Locale.forLanguageTag
工厂方法创建区域设置对象
Locale aLocale = Locale.forLanguageTag("en-US");
Locale bLocale = Locale.forLanguageTag("de-Germany");
稍后我们将介绍语言标签;下面的代码向您展示了如何使用 Locale.forLanguageTag
工厂方法来创建Locale
对象。
Locale usLocale = Locale.forLanguageTag("en-US");
Locale deLocale = Locale.forLanguageTag("de-Germany");
Locale zhLocale = Locale.forLanguageTag("zh-CN");
long number = 123456789L;
NumberFormat denf = NumberFormat.getInstance(deLocale);
NumberFormat usnf = NumberFormat.getInstance(usLocale);
NumberFormat zhnf = NumberFormat.getInstance(zhLocale);
System.out.println(denf.format(number));
System.out.println(usnf.format(number));
System.out.println(zhnf.format(number));
输出将是:
123.456.789
123,456,789
123,456,789
使用Locale常量
这可能是创建 Locale 对象的最简单方法。为方便起见,Java
为某些语言和国家/地区预定义了常量。例如:Japan
是日本的国家表示,而 Japanese
是日语的表示。您只需要使用一个常量来创建这种类型的语言环境。以下代码是如何使用区域设置常量的示例。
Locale deLocale = Locale.GERMANY;
Locale usLocale = Locale.US;
Locale zhLocale = Locale.CHINA;
long number = 123456789L;
NumberFormat denf = NumberFormat.getInstance(deLocale);
NumberFormat usnf = NumberFormat.getInstance(usLocale);
NumberFormat zhnf = NumberFormat.getInstance(zhLocale);
System.out.println( denf.format(number) );
System.out.println( usnf.format(number) );
System.out.println( zhnf.format(number) );
这段代码基本上和前面的例子做了同样的事情,唯一的区别是它如何创建 Locale 对象。输出是:
123.456.789
123,456,789
123,456,789
Java Locale代码小结
您可能已经注意到,我们在使用 Locale
构造函数和 Locale.Builder
方法创建对象时使用了代码。有一个可用的 Java
语言代码和国家/地区代码列表。可用代码的完整列表将使本文不必要地冗长。
您在这里看到的是对更常见的概述:
语言代码:
English – en
German – de
French – fr
Russian –ru
Japanese – ja
Chinese – zh
Arabic – ar
同一种语言可以在多个国家使用。语言的使用方式可能因国家/地区而异。例如,在美国使用的英语与在英国使用的英语不同。这就是为什么在您的 Locale
对象中指定国家/地区很重要的原因。该国家/地区使用唯一的国家/地区代码指定......
国家代码:
United States – US
Germany – DE
France – FR
United Kingdom – UK
Canada – CA
Java Locale语言标签
语言标签是具有特殊格式的字符串,用于提供有关特定语言环境的信息。它可以像英语使用en
表示一样简单,也可以像使用zh-cmn-Hans-CN
表示中国一样复杂,分别用于中文、普通话、简体文字。
Locale.forLanguageTag(LanguageTag)
使用语言标签来创建 Locale
对象。
Locale locale = Locale.forLanguageTag("en-US");
此代码仅使用en-US
语言标签创建 Locale
对象。
语言范围
语言范围是一组共享某些属性的语言标签。例如,es-*
可用于识别任何地区的西班牙语。
Locale locale = Locale.forLanguageTag("en-GB");
Locale.LanguageRange r1= new Locale.LanguageRange("es-*",1);
Locale.LanguageRange r2= new Locale.LanguageRange("de-DE",0.5);
Locale.LanguageRange r3= new Locale.LanguageRange("en-GB*",0);
上例中使用的Locale.LanguageRange
构造函数有两个参数。
第一个参数是语言范围,第二个参数是权重。通常,这个权重用于表达用户的偏好。在此示例中,我们创建了从最高用户偏好到最低用户偏好的三个范围。
创建优先级列表
您可以使用一组语言范围创建优先级列表。
Locale locale = Locale.forLanguageTag("en-GB");
String rangeString = "en-US;q=1.0,en-GB;q=0.5,de-DE;q=0.0";
List<Locale.LanguageRange> rangeList = Locale.LanguageRange.parse(rangeString);
rangeString
是具有一组语言环境及其权重的有效字符串。然后我们使用Locale.LanguageRange
类中的 parse()
方法解析它以创建语言优先级列表。
使用优先级列表过滤标签
在前面的示例中,我们创建了一个语言优先级列表。在语言标签过滤过程中,我们将一组语言标签与优先级列表进行匹配。
String ranges = "en-US;q=1.0,en-GB;q=0.5,de-DE;q=0.0";
List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);
Collection<Locale> localesList = new ArrayList<>();
localesList.add(Locale.forLanguageTag("en-GB"));
localesList.add(Locale.forLanguageTag("en-US"));
localesList.add(Locale.forLanguageTag("ja-*"));
localesList.add(Locale.forLanguageTag("fe-FE"));
List<Locale> filteredSet = Locale.filter(languageRanges,localesList);
for(Locale locale : filteredSet){
System.out.println(locale.toString());
}
输出为:
en_US
en_GB
Locale范围
在 Java
中使用语言环境最重要的方面之一是它的范围。您不必在一个程序中使用相同的语言环境。实际上,您可以为应用程序中使用的每个区域设置敏感对象指定不同的区域设置。
一个有趣的案例是分布式应用程序的开发。假设您的应用程序收到来自不同国家/地区的请求。您如何决定应用程序的语言环境?您在这里可以做的是使用单独的线程来处理请求并为每个线程分配一个语言环境。
检索Locale信息
Locale
对象提供了许多方法来获取有关正在使用的语言环境的信息。让我们来了解其中的一些。
获取语言环境
getLanguage()
和getISO3Language()
方法可用于检索区域设置的语言。这里, getLanguage()
返回一个 ISO2
字母,而 getISO3Language()
返回一个 ISO3
字母。
Locale locale = Locale.GERMAN;
System.out.println("Locale:" + locale);
System.out.println("ISO 2: " + locale.getLanguage());
System.out.println("ISO 3: " + locale.getISO3Language());
输出为:
Locale: de
ISO 2: de
ISO 3: deu
首先,我使用 Locale
常量创建了一个 locale
对象。然后,我对该对象调用了 getLanguage()
方法。它返回德语的 ISO2
代码 de
。接下来,我调用 locale.getISO3Language()
。它返回了德语的 ISO3
代码 deu
。
获取国家信息
getCountry()
和 getISO3Country()
可用于检索区域设置的语言。这里, getCountry()
返回 ISO2
字母,而 getISO3Country()
返回 ISO3
字母。
Locale locale = Locale.GERMANY;
System.out.println("Locale: " + locale);
System.out.println("ISO 2 letter: " + locale.getCountry());
System.out.println("ISO 3 letter: " + locale.getISO3Country());
输出:
Locale: de_DE
ISO 2 letter: DE
ISO 3 letter: DEU
如果您检查上述示例中的输出,则这些短格式标签不适合用户。 Java Local
对象提供了以更具可读性的方式返回上述详细信息的方法。
获取显示语言
getDisplayLanguage
方法用于以更常见的方式获取语言。有两个覆盖的 getDisplayLanguage
方法。
如果您使用空参数方法,它将返回默认语言环境中的值。如果您将目标语言环境作为参数传递,则此方法将从目标语言环境返回值。
Locale locale = Locale.GERMANY;
String defaultLanguage = locale.getDisplayLanguage();
String targetLanguage = locale.getDisplayLanguage(locale);
System.out.println(defaultLanguage);
System.out.println(targetLanguage);
输出:
German
Deutsch
在第一种情况下,您没有向 getDisplayLanguage
方法传递任何参数。因此,区域设置值(德语)显示在默认区域设置中,即 en_US
。接下来,我将目标语言环境归因于 getDisplayLanguage
方法。因此显示 Deutsch
。
获取显示国家
getDisplayCountry
方法将返回以可读形式调用的语言环境。 getDisplayCountry
方法的工作方式与 getDisplayLanguage
方法类似。
Locale locale = Locale.GERMANY;
String defaultCountry = locale.getDisplayCountry();
String targetCountry = locale.getDisplayCountry(locale);
System.out.println(defaultCountry);
System.out.println(targetCountry);
输出将与前面的示例非常相似,只是这次将显示国家/地区。
获取显示名称
getDisplayName
方法可用于获取调用它的完整区域设置名称。它的工作原理类似于前两种方法:
Locale locale = Locale.GERMANY;
String defaultCountry = locale.getDisplayName();
String targetCountry = locale.getDisplayName(locale);
System.out.println(defaultCountry);
System.out.println(targetCountry);
输出:
German (Germany)
Deutsch (Deutschland)
总结
如果您对本文感到满意,您可能还想要更进一步了解如何国际化 JSP 应用程序或如何国际化 Spring 启动应用程序。
由斯蒂芬撰写。最后更新于 2020 年 8 月 27 日。