使用 Java API 验证 BCP-47 语言标签

Ser*_*rCe 8 java performance localization

据我所知,验证给定 BCP-47 语言标签是否有效的唯一方法是使用以下习惯用法:

private static boolean isValid(String tag) {
  try {
    new Locale.Builder().setLanguageTag(tag).build();
    return true;
  } catch (IllformedLocaleException e) {
    return false;
  }
}
Run Code Online (Sandbox Code Playgroud)

然而,这种方法的缺点是会setLanguageTag引发异常,该异常在经常检查区域设置的工作负载中具有明显的(在配置文件中)性能开销。

setLanguageTag函数是使用sun.util.localeAPI 实现的,据我所知,这是唯一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();
}
Run Code Online (Sandbox Code Playgroud)

但是,无法以上述方式检查区域设置,因为它直接使用类,因为它需要额外的 JDK 选项才能从模块sun.*导出。sun.util.localejava.base

有没有一种方法可以在不使用私有sun.*API 的情况下验证语言标签,同时与 的实现保持一致sun.util.locale.LanguageTag#parse

Dus*_* E. 0

最简单的解决方案应该是:

boolean isValidBCP47 = "und".equals(Locale.forLanguageTag(tag))
Run Code Online (Sandbox Code Playgroud)

最好的解决方案是利用 的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"]
Run Code Online (Sandbox Code Playgroud)