From a230a6099e2ec1b2f8f35515964c8ccb7c1523ec Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 9 Jul 2026 16:28:56 +0000 Subject: [PATCH] 8387795: Remove hard coded set of locales in LocaleData Reviewed-by: jlu --- .../ResourceBundleGenerator.java | 40 +++++++++++++++++-- .../util/cldr/CLDRLocaleProviderAdapter.java | 6 ++- .../provider/JRELocaleProviderAdapter.java | 4 ++ .../provider/ResourceBundleBasedAdapter.java | 12 +++++- .../sun/util/resources/LocaleData.java | 21 +++++----- 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 84657ae94f0..8e9635ab519 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -29,6 +29,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Comparator; import java.util.Formatter; import java.util.HashSet; import java.util.HashMap; @@ -39,6 +40,7 @@ import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.stream.Collectors; +import static java.util.ResourceBundle.Control; class ResourceBundleGenerator implements BundleGenerator { // preferred timezones - keeping compatibility with JDK1.1 3 letter abbreviations @@ -69,6 +71,9 @@ class ResourceBundleGenerator implements BundleGenerator { // For duplicated values private static final String META_VALUE_PREFIX = "metaValue_"; + // locales in the base module + private final Set baseModuleLocales = new HashSet<>(); + @Override public void generateBundle(String packageName, String baseName, String localeID, Map map, BundleType type) throws IOException { @@ -80,8 +85,15 @@ class ResourceBundleGenerator implements BundleGenerator { return; } - // Assume that non-base resources go into jdk.localedata - if (!CLDRConverter.isBaseModule) { + if (CLDRConverter.isBaseModule) { + if (!localeID.equals("root")) { + baseModuleLocales.addAll( + Control.getControl(Control.FORMAT_DEFAULT) + .getCandidateLocales("", + Locale.forLanguageTag(CLDRConverter.toLanguageTag(localeID)))); + } + } else { + // Assume that non-base resources go into jdk.localedata dirName = dirName + File.separator + "ext"; packageName = packageName + ".ext"; } @@ -284,6 +296,7 @@ class ResourceBundleGenerator implements BundleGenerator { import java.util.HashMap; import java.util.Locale; import java.util.Map; + import java.util.Set; import sun.util.locale.provider.LocaleDataMetaInfo; import sun.util.locale.provider.LocaleProviderAdapter; @@ -296,6 +309,7 @@ class ResourceBundleGenerator implements BundleGenerator { out.printf(""" private static final Map parentLocalesMap = HashMap.newHashMap(%d); private static final Map languageAliasMap = HashMap.newHashMap(%d); + private static final Set baseModuleLocales; static final boolean nonlikelyScript = %s; // package access from CLDRLocaleProviderAdapter static { @@ -322,7 +336,23 @@ class ResourceBundleGenerator implements BundleGenerator { CLDRConverter.handlerSupplMeta.getLanguageAliasData().forEach((key, value) -> { out.printf(" languageAliasMap.put(\"%s\", \"%s\");\n", CLDRConverter.escape(key), CLDRConverter.escape(value)); }); - out.printf(" }\n\n"); + out.println(); + + // for baseModuleLocales + out.printf(" baseModuleLocales = Set.of(\n"); + out.printf(" %s", + baseModuleLocales.stream() + .map(Locale::toLanguageTag) + .sorted(Comparator.comparing(l -> l.equals("und") ? "" : l)) + .map(l -> switch(l) { + case "und" -> "Locale.ROOT"; + case "en" -> "Locale.ENGLISH"; + case "en-US" -> "Locale.US"; + default -> "Locale.forLanguageTag(\"" + l + "\")"; + }) + .collect(Collectors.joining(",\n "))); + out.printf("\n );"); + out.println("\n }\n"); // end of static initializer block. @@ -391,6 +421,10 @@ class ResourceBundleGenerator implements BundleGenerator { return parentLocalesMap; } + public Set baseModuleLocales() { + return baseModuleLocales; + } + // package access from CLDRLocaleProviderAdapter Map likelyScriptMap() { return CLDRMapHolder.likelyScriptMap; diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 573187ba3d0..1e80bce3839 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -288,6 +288,10 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { || langtags.contains(getEquivalentLoc(locale).toLanguageTag()); } + public Set baseModuleLocales() { + return baseMetaInfo.baseModuleLocales(); + } + /** * Returns the canonical ID for the given ID */ diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 7b8b3b06eb3..2d6d95b509f 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -488,4 +488,8 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R "th-TH-TH".equals(oldname) || "no-NO-NY".equals(oldname); } + + public Set baseModuleLocales() { + return Set.of(Locale.ROOT); + } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java index 613b1ee5158..48d9b832b13 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ package sun.util.locale.provider; import java.util.List; import java.util.Locale; +import java.util.Set; + import sun.util.resources.LocaleData; /** @@ -40,5 +42,11 @@ public interface ResourceBundleBasedAdapter { /** * candidate locales customization */ - public List getCandidateLocales(String baseName, Locale locale); + List getCandidateLocales(String baseName, Locale locale); + + /** + * Returns the locales whose resource bundles are resolved from + * the java.base module for this adapter. + */ + Set baseModuleLocales(); } diff --git a/src/java.base/share/classes/sun/util/resources/LocaleData.java b/src/java.base/share/classes/sun/util/resources/LocaleData.java index 20e8e0f8fe9..884f9610ca7 100644 --- a/src/java.base/share/classes/sun/util/resources/LocaleData.java +++ b/src/java.base/share/classes/sun/util/resources/LocaleData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.ResourceBundleProvider; import sun.util.locale.provider.JRELocaleProviderAdapter; @@ -180,9 +179,6 @@ public class LocaleData { private static class LocaleDataStrategy implements Bundles.Strategy { private static final LocaleDataStrategy INSTANCE = new LocaleDataStrategy(); - // TODO: avoid hard-coded Locales - private static final Set JAVA_BASE_LOCALES - = Set.of(Locale.ROOT, Locale.ENGLISH, Locale.US, Locale.of("en", "US", "POSIX")); private LocaleDataStrategy() { } @@ -202,11 +198,8 @@ public class LocaleData { String key = baseName + '-' + locale.toLanguageTag(); List candidates = CANDIDATES_MAP.get(key); if (candidates == null) { - LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE; - LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - candidates = adapter instanceof ResourceBundleBasedAdapter rbba ? - rbba.getCandidateLocales(baseName, locale) : - defaultControl.getCandidateLocales(baseName, locale); + var adapter = getAdapter(baseName); + candidates = adapter.getCandidateLocales(baseName, locale); // Weed out Locales which are known to have no resource bundles int lastDot = baseName.lastIndexOf('.'); @@ -227,7 +220,13 @@ public class LocaleData { } boolean inJavaBaseModule(String baseName, Locale locale) { - return JAVA_BASE_LOCALES.contains(locale); + return getAdapter(baseName).baseModuleLocales().contains(locale); + } + + private static ResourceBundleBasedAdapter getAdapter(String baseName) { + return (ResourceBundleBasedAdapter)(baseName.contains(DOTCLDR) ? + LocaleProviderAdapter.forType(CLDR) : + LocaleProviderAdapter.forType(JRE)); } @Override