OpenFlights Rotating Header Image

Dynamic Javascript localization with Gettext and PHP

Disclaimer: The following is intolerably technical and doesn’t really have anything at all to do with flying.  Non-geeks, please head straight for the emergency exit.

Now, for the few brave people who are actually interested in the intricacies of Javascript localization…

GNU Gettext and its “.po” files are the gold standard for open-source localization, but Javascript has so far eluded any elegant solutions for this: there is no way to optionally load in only the modules you need, so if you wanted to support 100 languages, you need to load in all 100 translated copies, even though your user only wants to use a single one of them.

Until JSGettext, that is.  Not only do they provide a complete implementation of the GNU Gettext spec with a fast, elegant, and stress-tested .po file parser, so you can use the same localization files as you do for the PHP/Ruby/whatever powering your HTML pages and AJAX backend, but — with a sprinkling of server-side pixie dust — the .po files you want (and no more) can be dynamically selected and loaded.  Here’s how it works, assuming you’re using PHP.

First, download the JSGettext package and set it up under your root directory like this:

/js/Gettext.js

Create a /locale/ja_JP.utf8/LC_MESSAGES/messages.po file, which should look something like this:

#: /www/test.php:13
msgid "Hello world"
msgstr "こんにちは世界"

I’m using Japanese as the example here, but you can replace “ja_JP.utf8″ with the locale (language) of your choice, both above and in the next steps.   If you’re using Linux, make sure the locale you want has been loaded into the system so that it shows up in locale -a.  Now create a file called /test.php, which contains the following:

<?php
$locale = "ja_JP.utf8";
if(isSet($_GET["locale"]))$locale = $_GET["locale"];
?>
<html>
<head>
<link rel="gettext" type="application/x-po" href="/locale/<?php echo $locale ?>/LC_MESSAGES/messages.po" />
<script type="text/javascript" src="/js/Gettext.js"></script>
<script type="text/javascript" src="/js/test.js"></script>
</head>
<body>
Test!
</body>
</html>

So in PHP, we figure out the user’s locale from the URL, extracting it from …?locale=FOO if found, defaulting to “ja_JP.utf8″ if not.  (In a real application, you’d probably want to figure it out from the user’s session, but let’s not get too complicated here.)  This locale is then used to generate the path to the correct messages.po file to load.

Last and least, we create our little piece of Javascript in /js/test.js:

window.onload = function init(){
var gt = new Gettext({ 'domain' : 'messages' });
alert(gt.gettext('Hello world'));
}

Note that we don’t need to specify or pass on the locale here, as JSGettext has only one .po file loaded, and it’s smart enough to always pick its strings from there.

We’re done!  Now load up “/test.php” in a browser, and you should get an alert box that says “こんにちは世界” in Japanese.

Now try “/test.php?locale=en_US.utf8″ — and you’ll get an ugly error, because the dynamic loader can’t find that locale.  To prevent this, you need to control the possible locales that PHP will pass through.

But we still need our ‘home’ locale, and it would be a little silly to create a .po file translating English into English, no?  The solution is to create a dummy .po file at /locale/en_US.utf8/LC_MESSAGES/messages.po:

msgid "Foo"
msgstr "Bar"

And that’s it.  As long as there’s at least one msgid in there, JSGettext will be happy, and use the untranslated defaults.  (A completely empty file, alas, makes JSGettext cry.)

How’s that work for you?  Let me know if you like it, and pass on the link.

Opening up to the world,
-jani


Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

9 Comments

  1. [...] my own blog entry about how to localize javascript with jsgettext http://ur1.ca/4wss #i18n [...]

  2. Nguyen Xuan says:

    Thanks for your post. It did help me.

    But maybe you forget something:

    var gt = Gettext({ ‘domain’ : ‘messages’ });

    It should be:

    var gt = new Gettext({ ‘domain’ : ‘messages’ });

  3. It seems interesting. I should test this lib. The method I was thinking to implement is to have JS vars translated/output by php. Example
    var text1 =

    There is also http://plugins.jquery.com/project/gettext – I may check also this one as I am already using JQuery.

  4. script and php code stripped…

  5. David says:

    Hello.

    This work very well, but ¿how parser javascript files to extract .po file?

    I run xgettext but it dont recognize string from js

    ¿Any idea?

  6. Adam Z says:

    Great introduction, thanks for that!

    However, I do not provide a po file for my default language.
    In PHP everything is fine, as _(‘some text’) returns just ‘some text’, if no po file was found.
    Thus I only have 1 po file (for the other language).

    Usign Gettext.js a nasty error is displayed (even cannot be catched in JS…)

    Any ideas?

    Thanks, mao

    1. admin says:

      Providing a default, almost-empty (you need one string in there) .po for your default language should fix that?

  7. prasanth k c says:

    Seems very nice, working well. Is it possible to localize a page mixed up with both static and dynamic(js) strings by using gettext-js only?

  8. Vanessa says:

    I use https://poeditor.com/ when I need to work with gettext. I recommend it to everybody.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>