src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java

Print this page

        

@@ -28,16 +28,22 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.text.spi.BreakIteratorProvider;
 import java.text.spi.CollatorProvider;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
 import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import sun.util.locale.provider.JRELocaleProviderAdapter;
 import sun.util.locale.provider.LocaleProviderAdapter;
 import sun.util.locale.provider.LocaleDataMetaInfo;
 
 /**

@@ -46,15 +52,20 @@
  * @author Masayoshi Okutsu
  * @author Naoto Sato
  */
 public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
 
-    private final LocaleDataMetaInfo metaInfo;
+    private static final CLDRBaseLocaleDataMetaInfo baseMetaInfo = new CLDRBaseLocaleDataMetaInfo();
+    // Assumption: CLDR has only one non-Base module.
+    private final LocaleDataMetaInfo nonBaseMetaInfo;
+
+    // parent locales map
+    private static ConcurrentMap<Locale, Locale> parentLocalesMap = null;
 
     public CLDRLocaleProviderAdapter() {
         try {
-            metaInfo = AccessController.doPrivileged(new PrivilegedExceptionAction<LocaleDataMetaInfo>() {
+            nonBaseMetaInfo = AccessController.doPrivileged(new PrivilegedExceptionAction<LocaleDataMetaInfo>() {
                     @Override
                 public LocaleDataMetaInfo run() {
                     for (LocaleDataMetaInfo ldmi : ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
                         if (ldmi.getType() == LocaleProviderAdapter.Type.CLDR) {
                             return ldmi;

@@ -68,11 +79,11 @@
             // It's ok ignore it if something wrong happens because there always is the
             // JRE or FALLBACK LocaleProviderAdapter that will do the right thing.
             throw new UnsupportedOperationException(e);
         }
 
-        if (metaInfo == null) {
+        if (nonBaseMetaInfo == null) {
             throw new UnsupportedOperationException("CLDR locale data could not be found.");
         }
     }
 
     /**

@@ -105,17 +116,67 @@
         return locs;
     }
 
     @Override
     protected Set<String> createLanguageTagSet(String category) {
-        String supportedLocaleString = metaInfo.availableLanguageTags(category);
+        // Directly call Base tags, as we know it's in the base module.
+        String supportedLocaleString = baseMetaInfo.availableLanguageTags(category);
+        String nonBaseTags = nonBaseMetaInfo.availableLanguageTags(category);
+        if (nonBaseTags != null) {
+            if (supportedLocaleString != null) {
+                supportedLocaleString += " " + nonBaseTags;
+            } else {
+                supportedLocaleString = nonBaseTags;
+            }
+        }
         if (supportedLocaleString == null) {
             return Collections.emptySet();
         }
         Set<String> tagset = new HashSet<>();
         StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
         while (tokens.hasMoreTokens()) {
             tagset.add(tokens.nextToken());
         }
         return tagset;
     }
+
+    // Implementation of ResourceBundleBasedAdapter
+    @Override
+    public List<Locale> getCandidateLocales(String baseName, Locale locale) {
+        List<Locale> candidates = super.getCandidateLocales(baseName, locale);
+        return applyParentLocales(baseName, candidates);
+    }
+
+    private List<Locale> applyParentLocales(String baseName, List<Locale> candidates) {
+        if (Objects.isNull(parentLocalesMap)) {
+            parentLocalesMap = new ConcurrentHashMap<>();
+            Map<String, String> parentLocales = baseMetaInfo.parentLocales();
+            parentLocales.keySet().forEach(parent -> {
+                Arrays.asList(parentLocales.get(parent).split(" ")).stream().forEach(child -> {
+                    parentLocalesMap.put(Locale.forLanguageTag(child),
+                        "root".equals(parent) ? Locale.ROOT : Locale.forLanguageTag(parent));
+                });
+            });
+        }
+
+        // check irregular parents
+        for (int i = 0; i < candidates.size(); i++) {
+            Locale l = candidates.get(i);
+            Locale p = parentLocalesMap.get(l);
+            if (!l.equals(Locale.ROOT) &&
+                Objects.nonNull(p) &&
+                !candidates.get(i+1).equals(p)) {
+                List<Locale> applied = candidates.subList(0, i+1);
+                applied.addAll(applyParentLocales(baseName, super.getCandidateLocales(baseName, p)));
+                return applied;
+            }
+        }
+
+        return candidates;
+    }
+
+    @Override
+    public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) {
+        return Locale.ROOT.equals(locale) ||
+            langtags.contains(locale.stripExtensions().toLanguageTag());
+    }
 }