mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-13 12:02:20 +00:00
[JENKINS-72449] Specify that no fallback to the default locale should be used when looking up a resource bundle via I18n action. (#8776)
[JENKINS-72449] Specify that no fallback to the default locale should be used when looking up a resource bundle When running the JVM with a default locale that is not english, the resource bundle lookup for english would return a bundle with that default locale, instead of using the "default" that is english. Also changed bundle resolution to use uberClassloader rather than iterating on all plugin classloaders
This commit is contained in:
1 parent
302e6ac2d1
commit
259ccc06fb
2 files changed
+40
-60
No files matched your search
@@ -24,15 +24,12 @@
|
||||
|
||||
package jenkins.util;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.CheckForNull;
|
||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import hudson.PluginWrapper;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
import jenkins.model.Jenkins;
|
||||
import net.sf.json.JSONObject;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
@@ -44,9 +41,8 @@ import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
* @since 2.0
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
public class ResourceBundleUtil {
|
||||
|
||||
private static final Logger logger = Logger.getLogger("jenkins.util.ResourceBundle");
|
||||
public final class ResourceBundleUtil {
|
||||
// TODO proper cache eviction
|
||||
private static final Map<String, JSONObject> bundles = new ConcurrentHashMap<>();
|
||||
|
||||
private ResourceBundleUtil() {
|
||||
@@ -70,55 +66,20 @@ public class ResourceBundleUtil {
|
||||
* @throws MissingResourceException Missing resource bundle.
|
||||
*/
|
||||
public static @NonNull JSONObject getBundle(@NonNull String baseName, @NonNull Locale locale) throws MissingResourceException {
|
||||
String bundleKey = baseName + ":" + locale;
|
||||
JSONObject bundleJSON = bundles.get(bundleKey);
|
||||
var bundleKey = baseName + ":" + locale;
|
||||
var bundleJSON = bundles.get(bundleKey);
|
||||
|
||||
if (bundleJSON != null) {
|
||||
return bundleJSON;
|
||||
}
|
||||
|
||||
ResourceBundle bundle = getBundle(baseName, locale, Jenkins.class.getClassLoader());
|
||||
if (bundle == null) {
|
||||
// Not in Jenkins core. Check the plugins.
|
||||
Jenkins jenkins = Jenkins.getInstanceOrNull();
|
||||
if (jenkins != null) {
|
||||
for (PluginWrapper plugin : jenkins.getPluginManager().getPlugins()) {
|
||||
bundle = getBundle(baseName, locale, plugin.classLoader);
|
||||
if (bundle != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bundle == null) {
|
||||
throw new MissingResourceException("Can't find bundle for base name "
|
||||
+ baseName + ", locale " + locale, baseName + "_" + locale, "");
|
||||
}
|
||||
|
||||
bundleJSON = toJSONObject(bundle);
|
||||
var noFallbackControl = ResourceBundle.Control.getNoFallbackControl(ResourceBundle.Control.FORMAT_DEFAULT);
|
||||
var uberClassLoader = Jenkins.get().getPluginManager().uberClassLoader;
|
||||
bundleJSON = toJSONObject(ResourceBundle.getBundle(baseName, locale, uberClassLoader, noFallbackControl));
|
||||
bundles.put(bundleKey, bundleJSON);
|
||||
|
||||
return bundleJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plugin bundle using the supplied Locale and classLoader
|
||||
*
|
||||
* @param baseName The bundle base name.
|
||||
* @param locale The Locale.
|
||||
* @param classLoader The classLoader
|
||||
* @return The bundle JSON.
|
||||
*/
|
||||
private static @CheckForNull ResourceBundle getBundle(@NonNull String baseName, @NonNull Locale locale, @NonNull ClassLoader classLoader) {
|
||||
try {
|
||||
return ResourceBundle.getBundle(baseName, locale, classLoader);
|
||||
} catch (MissingResourceException e) {
|
||||
// fall through and return null.
|
||||
logger.finer(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JSON representation of a resource bundle
|
||||
*
|
||||
|
||||
+33
-14
@@ -24,18 +24,23 @@
|
||||
|
||||
package jenkins.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import net.sf.json.JSONObject;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.jvnet.hudson.test.JenkinsRule;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
|
||||
*/
|
||||
public class ResourceBundleUtilTest {
|
||||
@Rule
|
||||
public JenkinsRule j = new JenkinsRule();
|
||||
|
||||
/**
|
||||
* Test resource bundle loading for a defined locale.
|
||||
@@ -43,12 +48,20 @@ public class ResourceBundleUtilTest {
|
||||
@Test
|
||||
public void test_known_locale() {
|
||||
JSONObject bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", Locale.GERMAN);
|
||||
Assert.assertEquals("Initialisiere Log-Rekorder", bundle.getString("LogRecorderManager.init"));
|
||||
assertEquals("Initialisiere Log-Rekorder", bundle.getString("LogRecorderManager.init"));
|
||||
bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("de"));
|
||||
Assert.assertEquals("Initialisiere Log-Rekorder", bundle.getString("LogRecorderManager.init"));
|
||||
assertEquals("Initialisiere Log-Rekorder", bundle.getString("LogRecorderManager.init"));
|
||||
|
||||
// Test caching - should get the same bundle instance back...
|
||||
Assert.assertSame(ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("de")), bundle);
|
||||
assertSame(ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("de")), bundle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noFallbackLocale() {
|
||||
try (var ignored = new DefaultLocale(new Locale("fr"))) {
|
||||
var bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("en"));
|
||||
assertEquals("System Log", bundle.getString("LogRecorderManager.DisplayName"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,16 +69,8 @@ public class ResourceBundleUtilTest {
|
||||
*/
|
||||
@Test
|
||||
public void test_unknown_locale() {
|
||||
Locale defaultOSLocale = Locale.getDefault();
|
||||
try {
|
||||
//Set Default-Locale to english
|
||||
Locale.setDefault(new Locale("en", "US"));
|
||||
|
||||
JSONObject bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("kok")); // konkani
|
||||
Assert.assertEquals("Initializing log recorders", bundle.getString("LogRecorderManager.init"));
|
||||
} finally {
|
||||
Locale.setDefault(defaultOSLocale);
|
||||
}
|
||||
JSONObject bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("kok")); // konkani
|
||||
assertEquals("Initializing log recorders", bundle.getString("LogRecorderManager.init"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,4 +80,18 @@ public class ResourceBundleUtilTest {
|
||||
public void test_unknown_bundle() {
|
||||
assertThrows(MissingResourceException.class, () -> ResourceBundleUtil.getBundle("hudson.blah.Whatever"));
|
||||
}
|
||||
|
||||
private static class DefaultLocale implements AutoCloseable {
|
||||
private Locale previous;
|
||||
|
||||
DefaultLocale(Locale locale) {
|
||||
previous = Locale.getDefault();
|
||||
Locale.setDefault(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
Locale.setDefault(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user