The Answer by Rupesh is correct and should be accepted. His comment prompted this Answer.
Enum
Regarding how to track the locales currently supported by your app, define an enum. An enum is a good way to handle a list of items known at compile-time and unchanging during execution. See tutorial by Oracle.
public enum L10n
{
fr_CA , es_ES ; // Names of reference variables automatically set to point to objects automatically instantiated when this class loads.
}
Use a constructor to pass the Locale
object represented by each enum element. We use L10n
as the class name for our enum, with “L10N” being a common abbreviation of the word “localization”.
public enum L10n
{
// Enum elements.
fr_CA( Locale.CANADA_FRENCH ) ,
es_ES( new Locale("es", "ES") ) ;
final private Locale locale ;
// Constructor
L10n( Locale localeArg )
{
this.locale = Objects.requireNonNull( localeArg ) ;
}
}
Enum elements are constants. So in Java naming conventions, each element name should be in all uppercase, such as FR_CA
& ES_ES
. I consider our case here to be an exception to that convention, as the upper/lowercase is important for the programmer to recognize the meaning of each name (language & culture codes).
You can use the Locale
objects contained in this enum to access your resource bundle. We add a getResourceBundle
method to provide this facility.
public enum L10n
{
// Enum elements.
fr_CA( Locale.CANADA_FRENCH ) ,
es_ES( new Locale("es", "ES") ) ;
final private Locale locale ; // Remember the `Locale` object behind each element in this enum.
// Constructor
L10n( Locale localeArg )
{
this.locale = Objects.requireNonNull( localeArg ) ;
}
// Access the ResourceBundle for a particular locale.
public ResourceBundle getResourceBundle()
{
…
}
}
Caution: Think about thread-safety. There is only one instance per enum object across your app. So that getResourceBundle
method must be thread-safe if you might invoke across threads. If only called from within the single UI-related thread, then thread-safety is not an issue. But remember to consider test suites, logging, or other places that might call from threads other than the main UI thread.
Example using that getResourceBundle
method.
L10n preferredLocalization = L10n.es_ES ; // Perhaps taken from a dialog interaction with user.
ResourceBundle resourceBundle = preferredLocalization.getResourceBundle() ;
This enum now acts as a façade in front of your resource bundle handling. You can refactor that handling code without affecting the places throughout your app where you call L10n::getResourceBundle
.
To present a list of the localizations supported by your app, add a method to get a display name. This method delegates to the contained Locale
object’s Locale::getDisplayName
method. You might want to localize that display name to the language and cultural norms of each locale itself.
public enum L10n
{
// Enum elements.
fr_CA( Locale.CANADA_FRENCH ) ,
es_ES( new Locale("es", "ES") ) ;
final private Locale locale ; // Remember the `Locale` object behind each element in this enum.
// Constructor
L10n( Locale localeArg )
{
this.locale = Objects.requireNonNull( localeArg ) ;
}
// Access the ResourceBundle for a particular locale.
public ResourceBundle getResourceBundle()
{
…
}
// For presentation to the user.
public String getDisplayName()
{
String name = this.locale.getDisplayName( this.locale ) ; // Pass a `Locale` to `Locale::getDisplayName` to have that locale's name automatically localized.
return name ;
}
}
Get a list of display names.
You can get a collection of the enum’s elements. The Enum.values
method is a special “implicit” method defined in the Java specs returning an array of all the objects defined as elements on that enum. Unfortunately this method is nearly omitted from the Enum
Javadoc, with a mention buried in the valueOf
method’s description.
for ( L10n localization : L10n.values() )
{
System.out.println( localization.getDisplayName() );
}
français (Canada)
español (España)
You could get even fancier with this by adding another member field to the enum class for an icon of the country flag representing that language & culture. The flag could then appear in the user-interface to identify the current localization. Pass an icon image for each enum element as a second argument on the constructor. Or write code on the enum class to do a lookup for the icon image. And of course add a getFlag
method to our enum class to return said flag image.