Skip to main content

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, unlike String.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 is AppStrings, so it will look for a ResourceBundle named AppStrings. It will find the AppStrings.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, here Alex.
info

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 !