In this post I’m going to show you how to make your extension localizable via Common Pool and how it can be localized.
early adopter warning: It’s the first attempt, it’s a new concept, things may brake, things may be a little rough, stay calm. It’s not a replacement for a well known solutions yet, but it may be one day. Play with it, hack the service and the library, suggest improvements, report the issues, but stay calm whatever happens – there may be dragons.
Using the library
Since Common Pool is currently implemented in Addon SDK, I assume you’re using it for writing your extension. First thing is to add my localization module to your extension. It’s available at http://builder.addons.mozilla.org.
Once you have it in your dependencies, you can just include it into your code.
Let’s take an example Hello World code:
var notifications = require("notifications"); var menuItem = contextMenu.Item({ label: "Hello World", contentScript: 'on("click", function (node, data) {' + ' postMessage(node.src);' + '});', onMessage: function (imgSrc) { notifications.notify({ title: "Hello World", text: "Welcome to the new, wonderful world!", }); } }
Now, in order to make it localizable, all we need to do is to add one require, and change the string initialization:
var notifications = require("notifications"); var _ = require("localization").get; var menuItem = contextMenu.Item({ label: _("Hello World"), contentScript: 'on("click", function (node, data) {' + ' postMessage(node.src);' + '});', onMessage: function (imgSrc) { notifications.notify({ title: _("Hello World"), text: _("Welcome to the new, wonderful world!"), }); } }
Done! That’s what I meant when I wrote that Common Pool is asking as little attention from the developer as possible. If it reminds you of common patterns used by GetText, you’re right on spot. We like this notation, we reuse it.
With such code, you’re ready to go 🙂 As a developer, you can move along, do your work, deploy your extension on AMO and never ever bother about this again, while we will make sure that the localizers can localize, and users will receive the localized version dynamically. 🙂
Early adopter warning: For the time of the field testing of this library, we do not actually have any integration with AMO, so when you want your addon to be localized, you need to “cfx xpi” it, or if you’re using the builder just click on “Download” and upload the result xpi here: https://l10n.mozillalabs.com/projects/p/mozilla-jetpacks/upload/. This is a temporary step
Using the web service
Once a developer uploaded his addon and his job is done, the camera shifts onto another hero – a localizer. This brave soul, can just go to https://l10n.mozillalabs.com, log in and start localizing. As a localizer, you can just select your locale and start localizing. You can filter by an extension and you can view how other locales localized it.
You can also select overrides and add one for a given jetpack or occurrence. When you finish localizing your jetpack, you’re done. We will spread your translation to all users of the jetpack who use your locale. If you later update your translation, all users will receive an update on the next day. Isn’t that awesome? 🙂
Early adopter warning: Until we fix bug 10, we refer to jetpacks by their unique ID, instead of the human readable name. It should be fixed soon 🙂
The beauty of early adopting
Well, that being said, you know you would not be happy to receive a complete, ready to use, bug free solution. That’s not what hackers life is about. In fact, we decided to blow quite a big hole through the middle of the road that’s called “First Run Experience“.
As we were working on the library, and the webservice, and how nicely they’re tied, and we enjoyed the experience of a user staying up to date with localization of his extensions, and being able to download an extension in en-US and then see it localized on the day when a localizer finishes localizing it… we actually did not solve a pretty important case. Here’s the issue:
When a user installs an extension it contains no translation resources bundled with it. On the first run, we asynchronously ask the localization web service for the entities used by the extension. So far so good.
The server asynchronously sends the user all the entities and they’re cached. From that moment every request for a string will work by providing a translation of the string. But what happens before we cache?
Well, for now, nothing. Bummer 🙁 Basically, until we cache the strings, all we have is an empty cache and the localization library will just return the english strings which is the default fall back.
The bug for that is reported, bug 619807, and we’re working on a solution for that. We may decide to bundle entities that we have available for the extension together with it at the time of download, but that will be just a workaround. An ideal solution would be to pull the localizations together with the addon (as a part of addon installation experience) and then check if there are any localization updates on a normal daily routine.
If you have any ideas, suggestions or code snippets that solves it – feel free to jump in and help! 🙂
Real Life Example
Take a look at this example extension, Translate Selection with l10n. Now, go to l10n.mozillalabs.com to see its localization and localize it live.
Next time you run this extension you should be able to see it working with localization (assuming your browser is using your locale and minus the First Run Experience bug).
That’s all. 🙂
Summary
Common Pool is a simple, yet very powerful solution. It solves a lot of issues that we’ve been struggling with since the beginning of times. It makes internationalization easier than ever, localization easier than ever and synchronization easier than ever. Bare in mind, it’s intended as a solution for simple strings, for developers who don’t have much time to think through their UI’s and plan it for localization, and for massive localization of tons of thousands of extensions.
We believe it nails it perfectly (with the few early adopters hiccups that we’re working on right now, and an unlimited number of issues that are awaiting to be discovered by you!), and we want to improve it until we feel it to be the right one.
At the same time, please, remember that for a more complex and sophisticated UI’s, the ones where a developer has to think about entities, and the localizer wants to fine tune each and every sentence – we’re going to work on a complementary, L20n based solution.
Now, it’s your turn to play with it, hack on it, give us feedback and help us evaluate the solution. We’re available at irc.mozilla.org #l10n and #jetpack channels, and we use mozilla-labs-jetpack group that you can use. For bugs in the l10n web service, please, use its bitbucket issue reporting system. Thanks! 🙂
3 replies on “Using Common Pool – Tutorial”
I love this, congrats!
Are comments in the extension code also supported? For clarification, please see:
http://en.wikipedia.org/wiki/GNU_gettext#Programming
P.S.: I’ve never worked with Transifex before and it pretty much works exactly as I would like to see Verbatim to work.
Nicely done, congrats 🙂
As a lazy (and code ignorant) tester I ran the proposed ready-made extension https://builder.addons.mozilla.org/addon/1000051/latest/ and yeaaah it worked just as expected, displaying my French strings as previously set on the transifex thing.
(Also made successful tests with some other available languages).
Of course to me the huge number of kind of “lib” files inside the extension looks a bit frightening, I hope they are not required as standard (?) but hey this is developer’s business anyway 😛
So it seems to be working for strings embedded in .js, great for jetpacks.
my ruminations here
1. Will it be possible to use the same process for entities for “classical” extensions? I suppose an extension cannot “call” remote online entities (?), and I have no idea whether a smart hack can convert cloud-pooled strings into entities for local use (?)
2. In case transifex is temp. unavailable, user has no strings at all or is there a requirement to have en-US strings as fallback inside the jetpack/extension? Or is there some process to “import” locally needed strings from common pool at first start of teh extension, so that online call is no longer necessary each time the extension is used? (well on second thoughts, updates of online strings can be necessary sometimes too)
3. In case you did not notice, Christopher Finkle http://www.chrisfinke.com/ has launched an online translation tool for Chrome extensions and mentioned it could be adapted for mozilla extensions. I don’t know if technically it would be more/less usable than transifex. My point is: there should be coordinate efforts regarding extension translations. We have set BabelZilla (which is far from perfect but improving) as a “one meeting point” precisely to avoid the scattering of “volunteer task force”, Though good tools like yours and Christopher’s are welcome, they tend to divide volunteers works between different projects.
trivial bug report:
When I register to l10n.mozillalabs.com, I recieved mail titled “[Transifex] Email validation for example.com” and it contains validation url starting with http://example.com/ …
I can register replacing example.com with l10n.mozillalabs.com but you should fix server setting.