diff --git a/platform/core-api/src/com/intellij/DynamicBundle.java b/platform/core-api/src/com/intellij/DynamicBundle.java index 81a93e55033d..37158c987c62 100644 --- a/platform/core-api/src/com/intellij/DynamicBundle.java +++ b/platform/core-api/src/com/intellij/DynamicBundle.java @@ -27,7 +27,7 @@ import java.lang.reflect.Method; import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.*; -import java.util.function.Function; +import java.util.function.BiFunction; public class DynamicBundle extends AbstractBundle { private static final Logger LOG = Logger.getInstance(DynamicBundle.class); @@ -64,29 +64,29 @@ public class DynamicBundle extends AbstractBundle { return resolveResourceBundle( getBundleClassLoader(), baseLoader, - loader -> { - return super.findBundle(pathToBundle, loader, control, getLocale()); - }, pathToBundle + (loader, locale) -> { + return super.findBundle(pathToBundle, loader, control, locale); + }, pathToBundle, getLocale() ); } private static @NotNull ResourceBundle resolveResourceBundle( @NotNull ClassLoader bundleClassLoader, @NotNull ClassLoader baseLoader, - @NotNull Function bundleResolver, - @NotNull String defaultPath + @NotNull BiFunction bundleResolver, + @NotNull String defaultPath, + @NotNull Locale locale ) { Path bundlePath = FileSystems.getDefault().getPath(defaultPath.replaceAll("\\.", "/")); - ClassLoader pluginClassLoader = languagePluginClassLoader(bundleClassLoader); - List paths = LocalizationUtil.Companion.getLocalizedPaths(bundlePath); + ClassLoader pluginClassLoader = languagePluginClassLoader(bundleClassLoader, locale); + List paths = LocalizationUtil.Companion.getLocalizedPaths(bundlePath, locale); Map bundleOrderMap = new HashMap<>(); if (pluginClassLoader != null) { - resolveBundleOrder(pluginClassLoader, true, bundlePath, paths, bundleOrderMap, bundleResolver); + resolveBundleOrder(pluginClassLoader, true, bundlePath, paths, bundleOrderMap, bundleResolver, locale); } - resolveBundleOrder(baseLoader, false, bundlePath, paths, bundleOrderMap, bundleResolver); + resolveBundleOrder(baseLoader, false, bundlePath, paths, bundleOrderMap, bundleResolver, locale); reorderParents(bundleOrderMap); - Optional> resourceBundleEntry = - bundleOrderMap.entrySet().stream().min(Map.Entry.comparingByKey()); + Optional> resourceBundleEntry = bundleOrderMap.entrySet().stream().min(Map.Entry.comparingByKey()); if (!resourceBundleEntry.isPresent()) { throw new RuntimeException("No such resource bundle: " + bundlePath); } @@ -96,12 +96,12 @@ public class DynamicBundle extends AbstractBundle { } @ApiStatus.Internal - private static List getBundlesFromLocalizationFolder(Path pathToBundle, ClassLoader loader) { - List paths = LocalizationUtil.Companion.getFolderLocalizedPaths(pathToBundle); + private static List getBundlesFromLocalizationFolder(Path pathToBundle, ClassLoader loader, Locale locale) { + List paths = LocalizationUtil.Companion.getFolderLocalizedPaths(pathToBundle, locale); List resourceBundles = new ArrayList<>(); for (Path path : paths) { try { - ResourceBundle resourceBundle = bundleResolver(path.toString().replace('\\', '/')).apply(loader); + ResourceBundle resourceBundle = bundleResolver(path.toString().replace('\\', '/')).apply(loader, locale); resourceBundles.add(resourceBundle); } catch (MissingResourceException e) { @@ -111,7 +111,7 @@ public class DynamicBundle extends AbstractBundle { return resourceBundles; } - private static @Nullable ClassLoader languagePluginClassLoader(@NotNull ClassLoader bundleClassLoader) { + private static @Nullable ClassLoader languagePluginClassLoader(@NotNull ClassLoader bundleClassLoader, @NotNull Locale locale) { if (DefaultBundleService.isDefaultBundle()) { return null; } @@ -119,6 +119,10 @@ public class DynamicBundle extends AbstractBundle { if (langBundle == null) { return null; } + if (!Objects.equals(locale.getLanguage(), getLocale().getLanguage()) || + (locale.getCountry() != null && !Objects.equals(locale.getCountry(), getLocale().getCountry()))) { + return null; + } PluginDescriptor pluginDescriptor = langBundle.pluginDescriptor; return pluginDescriptor == null ? bundleClassLoader : pluginDescriptor.getClassLoader(); @@ -136,8 +140,9 @@ public class DynamicBundle extends AbstractBundle { Path pathToBundle, List orderedPaths, Map bundleOrderMap, - @NotNull Function bundleResolver) { - ResourceBundle bundle = bundleResolver.apply(loader); + @NotNull BiFunction bundleResolver, + @NotNull Locale locale) { + ResourceBundle bundle = bundleResolver.apply(loader, locale); try { while (bundle != null) { putBundleOrder(bundle, bundleOrderMap, orderedPaths, isPluginClassLoader); @@ -147,7 +152,7 @@ public class DynamicBundle extends AbstractBundle { catch (Throwable throwable) { LOG.info(throwable); } - for (ResourceBundle localizedBundle : getBundlesFromLocalizationFolder(pathToBundle, loader)) { + for (ResourceBundle localizedBundle : getBundlesFromLocalizationFolder(pathToBundle, loader, locale)) { putBundleOrder(localizedBundle, bundleOrderMap, orderedPaths, isPluginClassLoader); } } @@ -279,6 +284,12 @@ public class DynamicBundle extends AbstractBundle { .computeIfAbsent(pathToBundle, __ -> resolveResourceBundle(loader, pathToBundle)); } + public static @NotNull ResourceBundle getResourceBundle(@NotNull ClassLoader loader, @NotNull @NonNls String pathToBundle, @NotNull Locale locale) { + return (DefaultBundleService.isDefaultBundle() ? ourDefaultCache : ourCache) + .computeIfAbsent(loader, __ -> CollectionFactory.createConcurrentSoftValueMap()) + .computeIfAbsent(pathToBundle, __ -> resolveResourceBundle(loader, pathToBundle, locale)); + } + public static @Nullable ResourceBundle getPluginBundle(@NotNull PluginDescriptor pluginDescriptor) { ClassLoader classLoader = pluginDescriptor.getPluginClassLoader(); String baseName = pluginDescriptor.getResourceBundleBaseName(); @@ -289,14 +300,24 @@ public class DynamicBundle extends AbstractBundle { return resolveResourceBundleWithFallback( () -> resolveResourceBundle( DynamicBundle.class.getClassLoader(), - loader, bundleResolver(pathToBundle), pathToBundle + loader, bundleResolver(pathToBundle), pathToBundle, getLocale() ), loader, pathToBundle ); } - private static @NotNull Function<@NotNull ClassLoader, @NotNull ResourceBundle> bundleResolver(@NonNls @NotNull String pathToBundle) { - return l -> AbstractBundle.resolveBundle(l, getLocale(), pathToBundle); + private static @NotNull ResourceBundle resolveResourceBundle(@NotNull ClassLoader loader, @NonNls @NotNull String pathToBundle, @NotNull Locale locale) { + return resolveResourceBundleWithFallback( + () -> resolveResourceBundle( + DynamicBundle.class.getClassLoader(), + loader, bundleResolver(pathToBundle), pathToBundle, locale + ), + loader, pathToBundle + ); + } + + private static @NotNull BiFunction<@NotNull ClassLoader, @NotNull Locale, @NotNull ResourceBundle> bundleResolver(@NonNls @NotNull String pathToBundle) { + return (loader, locale) -> resolveBundle(loader, locale, pathToBundle); } /** diff --git a/platform/core-api/src/com/intellij/util/LocalizationUtil.kt b/platform/core-api/src/com/intellij/util/LocalizationUtil.kt index 565379421329..0dc0c2d21ab4 100644 --- a/platform/core-api/src/com/intellij/util/LocalizationUtil.kt +++ b/platform/core-api/src/com/intellij/util/LocalizationUtil.kt @@ -46,8 +46,10 @@ class LocalizationUtil { return result } - fun getResourceAsStream(defaultLoader: ClassLoader?, path: Path): InputStream? { - val localizedPaths = getLocalizedPaths(path) + @JvmOverloads + fun getResourceAsStream(defaultLoader: ClassLoader?, path: Path, specialLocale: Locale? = null): InputStream? { + val locale = specialLocale ?: getLocale() + val localizedPaths = getLocalizedPaths(path, locale) for (localizedPath in localizedPaths) { val pathString = localizedPath.pathString.replace('\\', '/') getPluginClassLoader()?.getResourceAsStream(pathString)?.let { return it } @@ -56,31 +58,35 @@ class LocalizationUtil { return null } - fun getLocalizedPaths(path: Path): List { + @JvmOverloads + fun getLocalizedPaths(path: Path, specialLocale: Locale? = null): List { + val locale = specialLocale ?: getLocale() val result = mutableListOf() //localizations/zh/CN/inspectionDescriptions/name.html - result.add(convertPathToLocalizationFolderUsage(path, getLocale(), true)) + result.add(convertPathToLocalizationFolderUsage(path, locale, true)) //inspectionDescriptions/name_zh_CN.html - result.add(convertPathToLocaleSuffixUsage(path, getLocale(), true)) + result.add(convertPathToLocaleSuffixUsage(path, locale, true)) //localizations/zh/inspectionDescriptions/name.html - result.add(convertPathToLocalizationFolderUsage(path, getLocale(), false)) + result.add(convertPathToLocalizationFolderUsage(path, locale, false)) //inspectionDescriptions/name_zh.html - result.add(convertPathToLocaleSuffixUsage(path, getLocale(), false)) + result.add(convertPathToLocaleSuffixUsage(path, locale, false)) //inspectionDescriptions/name.html result.add(path) return result } - fun getFolderLocalizedPaths(path: Path): List { + @JvmOverloads + fun getFolderLocalizedPaths(path: Path, specialLocale: Locale? = null): List { + val locale = specialLocale ?: getLocale() val result = mutableListOf() //localizations/zh/CN/inspectionDescriptions/name.html - result.add(convertPathToLocalizationFolderUsage(path, getLocale(), true)) + result.add(convertPathToLocalizationFolderUsage(path, locale, true)) //localizations/zh/inspectionDescriptions/name.html - result.add(convertPathToLocalizationFolderUsage(path, getLocale(), false)) + result.add(convertPathToLocalizationFolderUsage(path, locale, false)) return result } }