Resource Bundle
L10nMessages uses java.util.ResourceBundle to load localized messages and specifically focuses
on improving the experience when working with resource bundles that are backed by properties
files.
In plain Java, there is are no safeguard to ensure properties files are present, nor that the
messages are present and valid which can lead to hard failure at runtime.
The Annotation Processor can be used to validate the existence of the
properties files at build time and to check the messages' validity. It will also generate an
enum that can be then used to initialize the fluent API and to provide strong typing of message
keys insuring the existence of messages at runtime.
The Fluent API can simply be initialized from the enum and will seamlessly load
messages from the resource bundle. It can also be used without the annotation processor, in which
case the resource bundle baseName needs to be provided manually and message key will be untyped
strings.
Naming convention
Java uses the notion of baseName to identify a ResourceBundle.
The baseName follows the pattern {package}.{bundleName} where package is a regular Java
package in "dotted" notation. The package and bundleName are defined by the user.
The root properties filename follows the pattern: {bundleName}.properties and the localized
properties filename follows the pattern: {bundleName}_{locale}.properties.
For example, with the bundle name: Messages and package: com.pinterest.l10nmessages.example, the
base name will be: com.pinterest.l10nmessages.example.Messages, the root properties file will be:
Messages.properties and the localized properties for French will be Messages_fr.properties.
With Maven directory layout, the files will be:
welcome=Welcome!
welcome=Bienvenue!
Content and encoding
properties files are simple plain text files. They contain a list of messages that are identified
by keys. Use a comment before the key to provide translator instruction.
# Translator instruction for message1
key1=message1
# Translator instruction for message2
key2=message2
UTF-8 is recommended for the file content. For legacy purpose, ISO-8859-1 is also supported.
With Java 8, the library uses a similar logic as what became standard with Java 9. It tries to load
the properties as UTF-8 and fallbacks to ISO-8859-1 in case of errors. With Java 9+, the JDK
code is directly used.
Legacy language codes
Hebrew, Indonesian and Yiddish have obsolet forms: iw, in and ji which respectively
map to the new language codes: he, id and yi.
L10nMessages will load data from either forms and that regardless of the tag used when the locale
is created.
More concretely, properties files can be named
Message_iw.properties or Messages_he.properties, and the locale created with either
new Locale("iw") or new Locale("he"), L10nMessages will adapt accordingly.
This is similar to the behavior introduced by Java 17, but addresses issues with previous versions of Java that will only load the data for the old forms.
For more context, before Java 17, Locale's constructor always converted those three language codes
to their earlier, obsoleted forms. The properties files had to be named using the obsolete forms,
and that regardless of the form used when creating the locale. In Java 17, the new forms are used by
default. The properties files can use either form. If the default form is missing it will attempt
to load the alternate form.
Other ResourceBundle types
The fluent API can use any customized ResourceBundle. The annotation processor is only useful for
the ones that are backed by properties files.