Localizing your Drupal site just got a whole lot easier

Whenever you spot an untranslated string on your Drupal site, you need to:

  1. Remember the string or at least some unique identifier from the text.
  2. In Drupal 6 go to Administration - Site building - Translate interface - Search tab; in Drupal 5 go to Administration - Site configuration - Localization - Manage strings tab.
  3. Enter what you remembered in step 1 and hit submit.
  4. Identify the string in the result list or if it is not found, go back to step 1 and find an actually unique part of the string to search for.
  5. Hit Edit on the item in the result list if found.
  6. A form with all languages are displayed, fill in the translations you want to provide.
  7. Go back and check whether the translation was used properly.

This is quite time consuming and error prone. Of course a lot of people suggested that we should have a solution which gets closer to the user, but it was not implemented before. So here I am to tell you that there is a solution for you which just works and eliminates nearly all of the steps above.

Let me introduce Localization client module. This is a Drupal 6 only module for now (but read on), because it utilizes new features in how Drupal 6 supports interface translation. What it does is actually very simple: collects all strings used on any given page for you and presents it in a nice widget which allows you to translate anything displayed on the page to the language the page should have been displayed with.

This is not a breaking new module, actually the backend was done as part of my Google Summer of Code 2007 involvement. Although, it did have a very clunky interface which was not too friendly on the user. That was when Development Seed sponsored Young Hahn to step in, and actually implement an enjoyable interface for this functionality. I am sure you will love how it behaves and makes your life easier.

Once you have l10n_client module enabled, you have access permission to use it and you are on a page which is not displayed with the built-in English language, a little bar is shown on the bottom of the page which pops up when clicked and displays the editing widget. The standard Drupal locale module database is used as a backend, so whatever you enter is saved right away to the database.

Due to how this ties into Drupal core, and how the core t() function needs to be modified (patch), this module is not possible to backport to Drupal 5 without core patching. Nonetheless people at Development Seed put resources into backporting it to Drupal 5, so your hope is not lost, if you are not into Drupal 6 functionality yet.


elv's picture

Great improvement over the localization module. The interface is not very drupalish I guess, but seems very practical.

Gábor Hojtsy's picture

If you have ideas on a more Drupalish user interface which is at least equally usable (or more :), then please step up with mockups or whatever you have. I am pretty satisfied with how the current state looks but it is definitely not untouchable.

greggles's picture

Perhaps the interface is too easy and too useful to be possible in Drupal ;)

That is great work, Gábor - I know this will make the lives of our translators much easier. Thanks to you and the other folks involved in this.

yched's picture

The UI could come in a JS popup ?

Not that we have js popups in drupal core right now, but I long for that day (confirm forms, batch progressbars...). And with with Panels 2 (and maybe Views 2 ?) using their own popups, they could become 'drupalish' in the next few months...

Anyway, this looks terrific !

Gábor Hojtsy's picture

We discussed using thickbox or something along these lines, but hiding the page away completely was not acceptable, because that way you cannot see where the string is used to recheck how you should fit your translation.

Also this bottom widget allows keeping the translation pane open from page to page, while a popup window staying somewhere above the page would be harder to manage I guess.

If your idea evolves more around the "look, untranslated content, let's click on it and get some translation popup for that exact string" (as compared to a widget for all strings on the page) then additonally to the visibility issue (the popup can easily overlap some important context), it is far from trivial to do string matching. For strings like the one demonstrated in the video, the string we know about is "Post new @node_type", while the actual string in the HTML is "Post new Fórum téma", which makes it complex to match the two together. Some strings create DOM nodes with their inline HTML, so that complicates the issue. So on the fly string matching for this kind of translation did not seem to work.

Then it is trivial that I needed to look into how can I tag translated strings in the HTML output, so we don't need to identify them ourselfs. There was an idea that we should just return strings wrapped with span elements from Drupal when this module is turned on. But using a special wrapper would break the mails you send, the form items (eg. select box options) you have, etc. When we return a translation in locale(), we don't know where will that be used: in HTML, as part of a select box, in email, etc. So we would break quite a few things.

This compromise with a usable UI seemed to be the most we can get from here, but if I did not understand your suggestion properly, then please clarify.

yched's picture

Right... I guess JS popups are probably not the right tool here :-)

elv's picture

I mean, your interface looks great! But as any module developer can create his own, sometimes the whle user interface is not very consistent when your site uses a lot of contrib modules.

Ideally modules would share common styles and markup, but I've talked about this with some Drupal ninjas and it seems it's a complex problem. And I guess Javascript widgets need a separate stylesheet, so that a theme won't override it by default.

Gábor Hojtsy's picture

Indeed, it is also hard to cater to different themes, which in this case would also be a possible requirement, given that we are translating user pages, which are displayed with whatever theme the site uses.

Dries's picture

Wow, this interface looks vastly superior to what we have in core. There is something to be said for swapping out the old interface, and replacing it with the one in this module.

Gábor Hojtsy's picture

While I carefully avoided some negative points about this interface (there is a set of modules in development for that purpose :), this module is rather a value add then a replacement for the built-in locale translation UI. These are two different approaches.

If you know you need to translate something but you don't know where is it displayed, you can find it easier with the locale module interface. Also there are obviously strings which are rarely or actually never displayed. Watchdog messages, email text and so on gets into the "strings used on the page" list sometimes, but error messages, which are critical to be properly worded and translated to quickly solve problems will not pop up in normal browsing, so l10n_client will not be able to translate them.

So while this is useful to translate stuff which you see on normal page views as you browse around, stuff which is only visible under some different circumstances (eg. for users with more or less permissions, for example the "register and login to post comments" note) still need some other method to be translatable.

So both approaches have their merits. Having solutions for both helps translators to pick the tool which fits their needs for the exact task they have at hand.

Granted, the built-in locale module interface needs improvement, and as my time allows, I am working on modules to help in that. But these are not yet at the "wow" stage unfortunately.

pp's picture

Amikor beszéltél erről már akkor is ígéretesnek tűnt, de a videót látva le vagyok nyűgözve! Ez űbertuti! Le a kalappal!

When We talked about this it seemed to be promising, but after seeing the video I'm spellbound!


Benjamin Melançon's picture

This would be fantastic for the translators for the World Social Forum 2008 site. And just for the great internationalization improvements, I wanted to use Drupal 6.. but sadly there were all those other modules people wanted.

Gábor Hojtsy's picture

Some bugs might still need to be worked out, but the Development Seed guys who work on the backport might have an announcement soon. For now feel free to try the 5.x-dev snapshot (sorry, no release until we don't know that the code is reasonably bugfree). Please also report if you see everything works well (or not :).

Ian Ward's picture

Hey all, the backport is now here in CVS and we've got it running for a UN project which is discussed over here on our blog. You just need to apply a simple patch to the locale module. It's working pretty well as you can see in the short little video. Gabor - thanks for your awesome vision in making translators' and site administrators' lives easier through the implementation of tools like these. It's simply awesome!

Wim Leers's picture

Wow. This is one of the most innovative modules I've seen in some time. Thank you so much! Multi-lingual sites in Drupal 6 will be a breeze :)

thamas's picture

... just repeat others: It's great! Thanks!

Alex's picture

I'm missing the way how i could get the newly translated strings back to d.o in CVS. I thought "Localization client" have a sync logic inside... it won't help much if i have this translated and after the next upgrade all is lost and no one else can benefit from this translation.

Gábor Hojtsy's picture

You can export the translations as a Gettext file using the built-in locale module. Translators can merge your Gettext file with their version and decide on which version to use for each string individually.

Although it takes some time for us to implement, there is logic behind the Localization Server and Localization Client having these names. The idea is that you will be able to contribute back each of your translations to the community (automatically or by hand). This is planned for a future version. For now, the above method works.

Add new comment