-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
With native-image RC10, -H:IncludeResourceBundles includes only the bundle for the default locale at image build-time. This is useful only if just a single locale is needed for an application, and that locale is known at build-time - and that seems insufficient for most internationalization/localization use cases.
As an example, take the following Java program:
import java.util.Locale;
import java.util.ResourceBundle;
public class Main {
private static String getMessage(final Locale locale) {
return ResourceBundle.getBundle("message", locale).getString("msg");
}
public static void main(final String[] args) {
System.out.println("user.language=" + System.getProperty("user.language"));
System.out.println("Locale.getDefault() = " + Locale.getDefault());
System.out.println("message in default locale = " + getMessage(Locale.getDefault()));
System.out.println("message in English = " + getMessage(Locale.ENGLISH));
System.out.println("message in Japanese = " + getMessage(Locale.JAPANESE));
}
}
And let messages be a property file backed resource bundle with two files: messages_en.properties (msg=English message), and messages_ja.properties (msg=Japanese message). The example program is also available as a Gist.
Running the code under the JVM produces the expected results - ResourceBundle.getBundle(String, Locale) returns the appropriate bundle for the given locale, and the default locale is determined from the host OS or properties at run-time.
$ java -Duser.language=ja Main
user.language=ja
Locale.getDefault() = ja_US
message in default locale = Japanese message
message in English = English message
message in Japanese = Japanese message
On the other hand, when using native-image, -H:IncludeResourceBundles only includes the bundle for the locale that is the default at image build-time, and the default locale is baked into the image. The replacement of ResourceBundle.getBundle(String, Locale) ignores the locale argument, so the bundle corresponding to the default locale at build-time is returned for every getBundle() call.
For this example, the locale for native-image was en_US:
$ ./main -Duser.language=ja
user.language=ja
Locale.getDefault() = en_US
message in default locale = English message
message in English = English message
message in Japanese = English message
The default locale being baked into the image is irritating, but that could be worked around by writing application code that determines the correct locale at startup and calls Locale.setDefault(). But the current behavior of -H:IncludeResourceBundles defeats the purpose of using resource bundles in most cases - it's no better than hardcoding messages for a single locale.
At a minimum, I feel this should be clearly documented as a limitation where resource bundles are discussed (e.g. https://github.com/oracle/graal/blob/master/substratevm/RESOURCES.md).
But ideally, the example program would behave identically on the JVM and when compiled with native-image. I think that would mean that com.oracle.svm.core.jdk.LocalizationSupport would be enhanced to capture resource bundles for all locales (or at least, for a list of locales provided via an option at build-time - that would be sufficient for my needs). And SVM would ship a replacement for Locale.getDefault() that determines the correct locale at image run-time rather than image build-time.