如何理解Java教程国际化定制资源捆绑加载示例



我在Oracle Java教程中看到了这段代码,我对它的实际工作方式感到困惑。我正在寻求几个问题的答案:

1) 我看不到public List<Locale> getCandidateLocales(String baseName, Locale locale)是从任何地方调用的,那么它实际上是如何执行的呢?

2) 作为参数传递给public List<Locale> getCandidateLocales(String baseName, Locale locale) 的内容

3) public List<Locale> getCandidateLocales(String baseName, Locale locale)返回List<Locale>,返回List<Locale> 的目的是什么

4) 如果if语句都不满足,则public List<Locale> getCandidateLocales(String baseName, Locale locale)返回super.getCandidateLocales(baseName, locale);,关键字super指的是哪个类?

public class RBControl {
    public static void main(String[] args) {
    test(Locale.CHINA);
    test(new Locale("zh", "HK"));
    test(Locale.TAIWAN);
    test(Locale.CANADA);
    }
    private static void test(Locale locale) {
    ResourceBundle rb = ResourceBundle.getBundle("Internationalisation/RBControl", locale,
         new ResourceBundle.Control() {
         @Override
         public List<Locale> getCandidateLocales(String baseName, Locale locale) {
             if (baseName == null)
             throw new NullPointerException();
             if (locale.equals(new Locale("zh", "HK"))) {
             return Arrays.asList(
                 locale,
                 Locale.TAIWAN,
                 // no Locale.CHINESE here
                 Locale.ROOT);
             } else if (locale.equals(Locale.TAIWAN)) {
             return Arrays.asList(
                 locale,
                 // no Locale.CHINESE here
                 Locale.ROOT);
             }
             return super.getCandidateLocales(baseName, locale);
         }
         });
    System.out.println("locale: " + locale);
    System.out.println("tregion: " + rb.getString("region"));
    System.out.println("tlanguage: " + rb.getString("language"));
    }
}

老实说,可能很难回答你的问题,因为你的代码风格早于Java7(你是考古学家吗?),但我会尝试的。

  1. 我只能向您保证,当代码搜索要从中加载文本资源的有效文件名或类名时,实际上会调用getCandidateLocales(String, String)。例如:

    // ResourceBundle.java line 1314
    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
                                                ClassLoader loader, Control control) {
        // (...) many lines removed
        // line 1352 - loop through files to find the best one
        ResourceBundle baseBundle = null;
        for (Locale targetLocale = locale;
             targetLocale != null;
             targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
            // line 1356, there you are
            List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
            if (!isKnownControl && !checkList(candidateLocales)) {
                throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
            }
            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
            // lengthy comment removed for clarity
            if (isValidBundle(bundle)) {
               // checking if it is the right one, removed
            }
        }
        // logic to deal with missing file, removed    
        return bundle;
    }
    
  2. 我认为现在应该是显而易见的,但让我详细谈谈。假设您的消息以属性文件的形式存在:messages.properties基础、默认语言资源、messages_fr.properties基础法语资源、messages_fr_CA.properties基础法语加拿大资源,最后是messages_de.proprties基础德语资源。基本名称是您可能猜到的基本文件名,即messages。候选区域设置是用户界面区域设置
    如果您正在使用桌面应用程序(极不可能)或移动应用程序,则只需调用Locale.getDetault(Locale.Category.DISPLAY)即可获得UI Locale。在旧版本的Java中,它只是Locale.getDefault()。在web应用程序中,解决方案实际上取决于技术(即Spring、JSF、Thymelaf、Play…)和您的区域设置检测方法。不管怎样,你应该先尝试最专业的,而不是退缩。例如,法裔加拿大用户(语言标签fr-CA)应该已经看到messages_fr_CA.properties的内容,而法语的其他用户应该收到messages_fr.properties的内容。同样,任何其他语言环境都应遵守messages.properties中的翻译
    该方法的作用是,它将为用户生成后备区域设置(即,对于输入Locale.forLanguageTag("fr-CA"),它将返回输入本身、法语区域设置("fr")和未定义的区域设置标记("und")。最后一个命令告诉ResourceBundle使用默认文件。

  3. 它返回后备区域设置的列表,正如我上面解释的那样。

  4. 它调用父类ResourceBundle.Control中的方法。在附加的代码列表中定义的匿名内部类实际上是从ResourceBundle.Control.派生的

最新更新