2009-04-28

plugins and translation

localizing an application is important if one wants to take over the world with it. this is why we try to localize padre (the perl ide) and translate it in as many languages as possible. (if padre isn't translated in your language, your help would be more than welcome!)

we are using the standard wx localization framework, which is similar to & compatible with gettext. then, using standard xgettext, msgmerge and msgfmt commands, the translators can do their magic and voilà! padre is translated.

this is working quite well.

but now, enter plugins. indeed, to keep padre as lean as possible, non-core features are deported in plugins. and even if padre is still a young project, there are already quite a lot of plugins for padre.

but how to translate plugins?

first (and stupid) solution would be to extract the strings to be translated and add them to padre's messages file. definitely not a good idea, since padre and the plugins do not share the same release planning, and we would end up with strings mismatch between what padre ships and what the plugin uses.

therefore, the plugin must provide its own translation. but that's a bit difficult, since they are not an application of their own: they are running inside padre, an application that already has its translated messages thank you very much.

so we need a way to have more than one strings catalog open at the same time. i had some troubles finding the correct method within wx documentation, but finally came up with:
$locale->AddCatalog($catalog);


$catalog being the catalog containing the new translated strings. and in order not to clash with main catalog (named after the locale, eg "fr-fr" for my current locale), the plugin catalog should be named $plugin-$locale.

but of course, it doesn't work as is. indeed, wx doesn't know where to find this new catalog. so we need to add a new search path to find the locales:
$locale->AddCatalogLookupPathPrefix($directory);


of course, we want padre plugins to be as easy to write as possible, so we don't want plugin authors to have to do this kind of non-sexy things.

therefore, plugin authors just need to define a plugin_locale_directory() method that will tell padre where to look for translated string catalogs. and since the plugins inherit from the base class padre::plugin, they have such a default method which points to the share directory as defined by file::sharedir. therefore, plugin authors don't even need to redefine this method if they're using the install_share instruction of module::install. (i don't like module::install, but that's not the point here)

ok, so plugin authors have one method to add. now they need to extract the strings and translate them (or ask other people to translate them). that's using standard gettext tools, so nothing really gets in the way.

and that's all. because padre handles the loading of new catalogs automatically, as long as they're named $plugin-$locale. that is, if the german translation of Padre::Plugin::SpellCheck is called SpellCheck-de.mo, then padre will find it and make sure that wx translates your plugin.

this is a good thing, because wx is a bitch to program with. that is, you can add a catalog or a catalog path, but you cannot remove them. and you don't want to load all your catalogs at once, to reduce memory load. and padre also takes care of locale switching, unloading previous locales and loading new ones. (unloading as in destroy locale object and create a new one since wx does not know how to remove a loaded locale).

therefore, even for localization, padre plugins are easy to write. why don't you join us and write your own, to have padre behave just how you expect? (using a real programming language that you know and love)

1 comment:

  1. Please consider using File::ShareDir::PAR instead of plain File::ShareDir in the context of Padre (and its plugins) because that'll make using PAR for packaging feasible.

    ReplyDelete