PluginDevGuide Internationalisation

From VuzeWiki
Jump to: navigation, search
You can download the code for this tutorial here. The JAR file can be opened in any program which can open up ZIP files, and contains both the compiled code and the source code.
Version: 0.3
Link: Download
Description: Plugin illustrating text localisation and internationalisation.

Plugin Development Guide: Defining plugin text[edit]

Introduction[edit]

Now, we'll tackle the subject of text localisation.

When you want to display some readable message to the user, rather than storing the text directly in the code, you will (in most cases) be passing around message keys, and each message key will map to readable text defined in your message bundle.

Example[edit]

Let's start off with an example - we'll add the following lines to create a menu item (a guide to menu creation is covered in its own section).

plugin_interface.getUIManager().getMenuManager().addMenuItem(MenuManager.MENU_MENUBAR, "Aizen menu item");

If we now run this code with Azureus, we get this:

PluginDevGuide Internationalisation 1.png

As you can see, the text for the menu item does appear, but with exclamation text either side of it. The documentation for the addMenuItem method didn't ask for the actual text to display for the menu item - instead it asked for a resource key instead. Azureus wants to take the key that you provide, translate that to actual text, and then display that. So why does it display !Aizen menu item!?

When you see text which looks like !abcdef!, it means that Azureus has been given the message key abcdef, tried to localise the text, found no definition for it, and just put some placeholder text in.

To actually define the text, you need to add an entry to message file that you defined in plugin.properties. In our case, it will be the file in azplugins/aizen/messages/Messages.properties.

So, if we modify the menu item generation code to be:

plugin_interface.getUIManager().getMenuManager().addMenuItem(MenuManager.MENU_MENUBAR, "aizen.menuitem");

And then add the following line to the Messages.properties file:

aizen.menuitem=Aizen menu item

Then it then displays:

PluginDevGuide Internationalisation 2.png

Multi-language support[edit]

The magic of resource bundles[edit]

Because Azureus uses resource bundles, this means that it also uses the same mechanism for supporting other languages. There's more technical information about resource bundles here.

But as a brief summary, by storing other properties files in the same directory (following a particular naming convention) will allow you to define message strings for other languages.

Resource bundles.gif

  • MyRes.properties is the main message properties file.
  • MyRes_ja_JP.properties contains message strings in Japanese.
  • MyRes_en.properties contains message strings in English.
  • MyRes_en_US.properties contains message strings in English, with text localised for the US.
  • MyRes_en_CA.properties contains message strings in English, with text localised for Canada.

So - if your current language is set to be Canadian English, when Azureus tries to map a message key to some readable text, it will check (in order):

  • MyRes_en_CA.properties
  • MyRes_en.properties
  • MyRes.properties

Bear in mind that MyRes.properties (or Messages.properties in our plugin) needs to contain all message keys that Azureus needs to look for. You can override message strings for specific languages, but you don't need to override all strings - just make sure as they are defined in Messages.properties. Although the default resource bundle properties file defines text in US English, you don't necessarily need to stick to this. You should probably just use that file to define text in whatever is your primary language, and then override the text appropriately.

Example[edit]

OK, so we'll change our plugin to have two menu items.

Definitions[edit]

So the plugin has this code:

plugin_interface.getUIManager().getMenuManager().addMenuItem(MenuManager.MENU_MENUBAR, "aizen.menuitem");
plugin_interface.getUIManager().getMenuManager().addMenuItem(MenuManager.MENU_MENUBAR, "aizen.menuitem.2");

And the Messages.properties file will have this text.

aizen.menuitem=Do something interesting
aizen.menuitem.2=Do something exciting

And we'll define a french language file, Messages_fr.properties. We'll override only one of the message strings.

aizen.menuitem=Faites quelque chose intéressante

Screenshots[edit]

So, if we look at the "Plugins" menu with the plugin running in the default language (US English), we see this: PluginDevGuide Internationalisation 3.png

But if we change the language in Options -> Interface -> Language to French, Azureus will refresh itself - and then going to the Plugins menu now displays this: PluginDevGuide Internationalisation 4.png

As you can see - one of the menu items has changed, but because the other one was not overridden in Messages_fr.properties, it falls back to using the definition in Messages.properties.

Naming schemes[edit]

When you define message strings, it's usually best to try to stick to a particular naming convention for your message keys. Ideally, it should be something like pluginid.somekey. Your message bundle will be integrated with Azureus's own message bundle (as well as the message bundles of other plugins) - it's best to make use of your plugin id to make sure your text doesn't clash with any other definitions.

However, it's not always possible to stick to that naming convention - sometimes, Azureus will look for message text in a particular format. For example, when you define a table column, you need to define an appropriate message key for it. However, you don't explicitly pass what the column name is. Instead, you have to define a message key in the particular format - tableid.column.columnname.

Another example, if you're adding a configuration section - you need to define a message string of the format ConfigView.section.configsectionname.

But where you have the choice, it's suggested that you should be using the pluginid.messagekeyname format.

Accessing localised text[edit]

In some cases, you'll want to access localised text yourself. This can be accessed using methods from the LocaleUtilities class.

As you might notice, some methods allow you pass in strings to substitute into the text. So, you can define a message string like:

aizen.downloadcomplete=The download %1 has just completed.

And then if you want to inform the user, you can get the localised text to display the user like this:

String text = locale_utils.getLocalisedMessageText("aizen.downloadcomplete", new String[] {download_name});

The text definition can contain as many parameters as you want (e.g. %1, %2). Each value refers to a value in the array that you pass in. You can reuse parameters as well - for example, you can define text like:

aizen.downloadcomplete=The download %1 has just completed, the file size was %2 MB. To open %1, go the menu.