简体   繁体   中英

Generate a Properties object from a ResourceBundle?

I've got a "normal" Java PropertyResourceBundle that's based on a stack of .properties files. In a few places, it would be much more convenient to operate on a Properties object based on the correct translated .properties file instead of the ResourceBundle . Is there a convient way to "cast" the ResourceBundle to a Properties ?

What'd I'd like is something like this:

Locale currentLocale = MagicLocaleFactory.getLocale();
ResourceBundle myResources = ResourceBundle.getBundle("MyResources", currentLocale);

Properties myProperties = myResources.magicallyProduceAPropertiesObject();

So afterwords, the myProperties object behaves as if it had been instantiated from the same .properties file that ResourceBundle.getBundle() went and found.

There are a few ways to do this "by hand"; for example, iterating though the set of key-value pairs of the ResourceBundle and installing them in a fresh Properties object, but I was hoping there was a better, or at least shorter, way to do it.

Edit:

To answer the obvious "but, WHY?" question, the case is this: we're retrofitting a long-existing desktop java program for i18n. The program is already pulling strings from a Properties object backed by a single .properties file. We're replacing the single file with multiple files and "promoting" the Properties object to a resource bundle. The problem, such as it is, is that the method to get a key on Properties is getProperty , whereas for ResourceBundle it's getString or getObject . Changing where the Properties object comes from before it gets passed around the program and has strings pulled out is very easy. Changing the actual method call is... less easy. Sure, you can pretty much search and replace for that, but then instead of just changing the one class that loads the properties, we have to touch, essentially, every single source file. (Yeah, there's a lot of text in this thing.) We were hoping we had missed a way to to use the ResourceBundle 's multiple .properties with fallback mechanism without having to rewire the entire app. (Gratuitous Gandalf quote: "There never was much hope. Just a fool's hope.")

There is no built-in way to do what you want, but as you said, it isn't difficult to do it yourself: the basically have the same interface, and copying the keys and values from the bundle to the properties is easy.

There is a caveat, though. Although the interface is similar, the implementation is not: the resource bundle has an inheritance model which allows returning the value in foo.properties if it isn't defined in foo_fr_FR.properties and foo_fr.properties . So copying all the entries won't get you the same properties as it they had been loaded from the properties file. It will get the entries of the properties file and the properties of all its parents. But I guess you knew that since you're talking about a stack of properties files.

You haven't stated why you would prefer a Properties over a ResourceBundle, so it's hard to give you a better answer.

Another solution would be to simply load the properties yourself:

Properties props = new Properties();
properties.load(MyClass.class.getResourceAsStream("MyResources_" + locale + ".properties")

This way, you would get only the entries from the specific properties file.

There in none and for the good reason: ResourceBundle is meant to contain properties in different languages, so that it would load *and fall-back appropriate file – when you ask for let's say messages with de-AT locale (German, Austria), it will fall-back to German if it is able to find one or to your base properties file (messages.properties) in other case.

I don't really know what is your use case here (maybe it is simply achievable in a different way?) but it seems that the only way is to read directly from properties file and unfortunately imitate the mechanism I mentioned above (the tricky part are Portuguese Brazil and Chinese Traditional which should not fall back to their "default" languages ("pt" and "zh" respectively)).

Another solution is iterate on keys and puts all pair in a properties object, You can use convertBundleToProperties :

static Properties convertBundleToProperties(ResourceBundle resource) {
    Properties properties = new Properties();

    Enumeration<String> keys = resource.getKeys();
    while (keys.hasMoreElements()) {
      String key = keys.nextElement();
      properties.put(key, resource.getString(key));
    }

    return properties;
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM