Internationalization
The bot you are developing is likely to be used by people which primary language is not English. To support these users, Botrino encourages the externalization of strings so they can be translated more conveniently.
The Translator
interface
The Translator
interface has one abstract method Locale getLocale()
which defines what is the target locale of the
translator, and a default method String translate(String, String, Object...)
which effectively does the translation.
By default, the translate method does the following:
default String translate(String bundle, String key, Object... args) {
return MessageFormat.format(ResourceBundle.getBundle(bundle, getLocale()).getString(key), args);
}
- Strings are located in a
ResourceBundle
which name is given. Typically, that's the name of a.properties
file located at the root of the resources folder. - Strings are parameterized using
MessageFormat
, which aims at being a language-independent way to put variables in a string, unlikeString.format()
.
Externalizing strings
If let's say you have a file named AppStrings.properties
in src/main/resources
with the following contents:
hello=Hello {0}!
You can use a translator like this:
var tr = Translator.to(Locale.ENGLISH);
System.out.println(tr.translate("AppStrings", "hello", "Alex"));
Which gives the output:
Hello Alex!
What happened here?
- The first argument of
tr.translate
isAppStrings
, so it will look for aResourceBundle
namedAppStrings
. It will find theAppStrings.properties
and will load its content. - The second argument says to find the string with key
hello
, which is what we defined earlier. - The third argument will substitute the
{0}
of our string with the value at runtime, hereAlex
.
To learn more about resource bundles and string argument formatting, check out the Javadoc
for ResourceBundle
and MessageFormat
. Note
that since Translator.translate
is a default interface method and thus can be overriden, you may customize the way
translations are retrieved, but this section will only document the default behavior.
Using translated strings
Once a string is properly externalized, it is possible to add a translation for it by duplicating the resource file and
naming it with the locale suffix. For example, if you have src/main/resources/AppStrings.properties
and want to
translate it in French, you will duplicate the file and name the copy src/main/resources/AppStrings_fr.properties
. The
way to name the translated files is documented in
the ResourceBundle
javadoc.
In your AppStrings_fr.properties
, you will translate the value of the hello
string:
hello=Bonjour {0} !
In your Java code, you can now specify either English or French locale and the string will adapt automatically:
var tr1 = Translator.to(Locale.ENGLISH);
var tr2 = Translator.to(Locale.FRENCH);
System.out.println(tr1.translate("AppStrings", "hello", "Alex"));
System.out.println(tr2.translate("AppStrings", "hello", "Alex")); // notice we use exact same arguments
Which gives the output you want:
Hello Alex!
Bonjour Alex !