In a project I'm working on, I'd like to load different resources depending on the current locale. With strings, this is pretty easy: just create a resource bundle by adding some files, for example Localization.properties
and Localization_de.properties
and then load it via ResourceBundle.getBundle("domain.project.Localization")
.
But how do I load localized resources that are not simple strings?
Specifically, I'd like to load images and HTML files based on locale. It would suffice to get the correct URL to that resource. For example, I'd like to have a Welcome.html
and Welcome_de.html
file and load the later when the current locale is German.
Simply using getClass().getResource("Welcome.html")
doesn't work, it's always returning exactly that file and doesn't do locale handling. I haven't found a convenient way to solve this yet, apart from manually messing with the filename based on the current locale.
One solution I came up with is to add a key to my Localization.properties
file that contains the name of the correct localized HTML file. But this feels hacky and wrong.
Note that this is not an Android application, just a standard Java 8 desktop app.
It actually turned out to pretty easy to get the same behaviour as ResourceBundle.getBundle
. I've looked at the code and found that the most important part for handling of the locales and filenames is ResourceBundle.Control.
So here's a simple method that returns the URL to localized resource (following the same filename scheme as resource bundles) without caching and support for just the current locale:
/** Load localized resource for current locale.
*
* @param baseName Basename of the resource. May include a path.
* @param suffix File extension of the resource.
* @return URL for the localized resource or null if none was found.
*/
public static URL getLocalizedResource(String baseName, String suffix) {
Locale locale = Locale.getDefault();
ResourceBundle.Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
List<Locale> candidateLocales = control.getCandidateLocales(baseName, locale);
for (Locale specificLocale : candidateLocales) {
String bundleName = control.toBundleName(baseName, specificLocale);
String resourceName = control.toResourceName(bundleName, suffix);
// Replace "Utils" with the name of your class!
URL url = Utils.class.getResource(resourceName);
if (url != null) {
return url;
}
}
return null;
}
If someone wants to extend it to support generic locales as an argument: the important part in the ResourceBundle.getBundleImpl
implementation is:
for (Locale targetLocale = locale;
targetLocale != null;
targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
...
}
The last entry of getCandidateLocales
is the empty locale (Locale.ROOT
). It should be ignored when the locales since the default resource would then be found in the first for
iteration, before the fallback locale is tested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With