据我所知,验证给定的 BCP-47 语言标签是否有效的唯一方法是使用以下惯用法:
private static boolean isValid(String tag) {
try {
new Locale.Builder().setLanguageTag(tag).build();
return true;
} catch (IllformedLocaleException e) {
return false;
}
}
但是,这种方法的缺点是
setLanguageTag
会引发异常,该异常在经常检查区域设置的工作负载中会产生明显的性能开销(在配置文件中)。
setLanguageTag
函数是使用 sun.util.locale
API 实现的,据我所知,这是唯一检查 sun.util.locale.ParseStatus
的地方。
我希望能够做的是使用具有以下语义的方法:
import sun.util.locale.LanguageTag;
import sun.util.locale.ParseStatus;
private static boolean isValid(String tag) {
ParseStatus sts = new ParseStatus();
LanguageTag.parse(tag, sts);
return !sts.isError();
}
但是,无法以上述方式检查语言环境,因为它直接使用
sun.*
类,因为它需要额外的 JDK 选项才能从 sun.util.locale
模块导出 java.base
。
有没有一种方法可以在不使用私有
sun.*
API 的情况下验证语言标签,同时与 sun.util.locale.LanguageTag#parse
的实现保持一致?
最简单的解决方案应该是:
boolean isValidBCP47 = "und".equals(Locale.forLanguageTag(tag))
最好的解决方案是利用
java.util.Locale
的过滤来为您处理这个问题。
我们通常需要回退到语言环境。例如;
en-JP
是说英语的人参观日本主题公园时想要的。然而;当 en-JP 不存在时,您可能只想回退到 en
。此外,您的平台可能不支持所有区域设置,需要检查支持的区域设置列表。
使用
com.glide.Locale
您可以执行以下操作:
ArrayList<Locale.LanguageRange> priorityList = new ArrayList<>();
priorityList.add(new Locale.LanguageRange("en-JP"));
priorityList.add(new Locale.LanguageRange("joking")); // invalid tag
priorityList.add(new Locale.LanguageRange("fr")); // unsupported tag
priorityList.add(new Locale.LanguageRange("en"));
ArrayList<String> supportedTags = new ArrayList<>();
supportedTags.add("ja");
supportedTags.add("en-JP");
supportedTags.add("en");
Locale.filterTags(priorityList, supportedTags, Locale.FilteringMode.AUTOSELECT_FILTERING);
// returns ArrayList ["en-JP", "en"]
这个问题来晚了,但现在您可以使用BCP47J,一个Java库,它提供了与BCP47语言标签相关的多个功能。