Adding a localization menu to WordPress

You may have noticed a small drop-down menu labelled ‘Localisation’ in the sidebar of this blog. It’s something I’ve been playing about with since localising the Giraffe theme and, while it doesn’t magically translate the entire blog, it does provide a viewer with a simple method to change the locale.

But what is a locale? In WordPress terms it refers to the framework around which your posts are displayed. That is, the words, phrases, dates, and times, that surround your posts. For example:

ItalianSpanishChinese

Try the live version now, if you want. You’ll need a Chinese font to display the Chinese localisation, but the others should work fine.

Providing the viewer with this functionality is actually a very simple process. Unfortunately, because of the way WordPress works, it is not possible to put it into a plugin. Although the locale function is hooked into the plugin framework, the plugins are loaded after the localisation takes place, and by then it is too late to change it.

Instead, a bit of technical jiggery-pokery is required. In other words, you need to hack a little. The change is small though, and in a file that does not vary much between WordPress versions. It is not a difficult modification and just requires a text editor.

First an explanation of how localisation works. WordPress provides a localisation in the form of .mo files. These are like mini dictionaries, and allow WordPress to reference a translation by an English phrase. These files are downloaded from the WordPress localisation repository and are then installed into the /wp-includes/languages directory (you may need to create this as it does not exist by default). Finally, the WPLANG setting in the wp-config.php file is changed to reflect the chosen localisation.

For example, to get a Spanish localisation:

define(WPLANG, 'es_ES');

These changes will affect most of the administration interface, as well as several other parts of the blog (such as dates and times). However, to be fully localised, the theme also needs to support localisation.

Providing the viewer with the ability to choose a localisation does not give them the ability to understand your posts. However, it does make the site more navigable, and it gives it that additional personal touch.

So, edit wp-config.php and replace

define ('WPLANG','');

With:

if (isset ($_GET['lang']))
{
  setcookie ('language', $_GET['lang'], time () + 60 * 60 * 24 * 2, '/');
  define ('WPLANG', $_GET['lang']);
}
else if (isset ($_COOKIE['language']))
  define ('WPLANG', $_COOKIE['language']);
else
  define ('WPLANG', '');

You can modify the default language by changing the last definition of WPLANG. You can also change the cookie’s expiry time by modifying the 60 * 60 * 24 * 2 – this is two days worth of seconds.

Now you can add a little bit of HTML to provide the options to the user:

<form method="get" action="/" style="padding: 1em">
  <select name="lang" style="width: 50%">
    <option value="">English</option>
    <option value="it_IT">Italiano</option>
    <option value="zh_CN">Chinese</option>
  </select>
  <input type="submit" style="border: 1px solid #999;" value="<?php _e('Go')?>"/>
</form>

This can be placed in any appropriate place in your blog. On this website I have added it to the sidebar (through the use of the sidebar-extra.php file in the Giraffe theme).

Naturally you will also need to install the .mo file for each language you want to provide.

13 comments

  1. first thank you for this very handy and helpful explanation!
    1) well there seems to be an error (or my misunderstanding?), i think it should say “setcookie(‘language’ … right?
    2) i propose to check the contents of ‘lang’ before handling them.
    3) by adding another hidden input field, one doesn’t get redirected to your blogs’ frontpage: <input type=”hidden” name=”redirect” value=”<?php echo $_SERVER[‘REQUEST_URI’]; ?>”> after the first 2 calls of define() one can then send a header back to where someone switched the language.

    this gives a nicer user-feel πŸ™‚
    this is what i ended up with & what works fine for me:
    // function to redirect
    function doredirect($location) {
    global $is_IIS;
    $location = str_replace( array("\n", "\r"), '', $location);
    if ($is_IIS)
    header("Refresh: 0;url=$location");
    else
    header("Location: $location");
    }
    // end redirect function
    if (isset ($_GET['lang']))
    {
    setcookie ('language', $_GET['lang'], time () 60 * 60 * 24 * 2, '/');
    define ('WPLANG', $_GET['lang']);
    if ( isset ($_GET['redirect']) )
    define('ABSPATH', dirname(__FILE__).'/');
    require_once(ABSPATH.'wp-settings.php');
    doredirect($_GET['redirect']);
    exit;

    }
    else if (isset ($_COOKIE['language'])) {
    define ('WPLANG', $_COOKIE['language']);
    if ( isset ($_GET['redirect']) ) {
    define('ABSPATH', dirname(__FILE__).'/');
    require_once(ABSPATH.'wp-settings.php');
    doredirect($_GET['redirect']);
    exit;
    }
    }
    else {
    define ('WPLANG', '');
    }
    // wp needs this
    define('ABSPATH', dirname(__FILE__).'/');
    require_once(ABSPATH.'wp-settings.php');

    regards, erik

  2. i guess one could still improve this multi-lingual switch with some fancy xmlHttpRequests … if i only knew JS & AJAX better… maybe you have some ideas on this… πŸ˜‰ just to get rid of page requests. or for doing onmouseover-translations πŸ™‚ hehehe.

  3. Hi Erik,

    Thanks for the suggestions. You are indeed correct about the cookie name – I had it right in my code, but typed it wrong here! I’ve corrected the article now. Also, that’s a good idea for the redirection.

    AJAX wouldn’t really be suitable for the locale menu. It would mean having to download every localized string, search through the web page, and replace each value. The amount of work involved in this would be enormous, especially considering that a user is probably only going to switch language once.

  4. you’re right, of course. after commenting i took a closer look at an examplary AJAX library (rico) and understood that this would be a hilarious amount of work… furthermore this would be kind of redoing what the .mo – files are there for. since my webserver copes with pageloads pretty well πŸ˜‰ this is cancelled and i’m just happy you shared this trick.
    [i just didn’t realize that the translated text _is_ written into the html and thus _needs_ the pageload to be switched, rendered…]
    <php _e(‘regrads from bavaria’, ‘myregards’); ?> πŸ™‚

  5. Hi John,

    you might want to read this post on switching from wp’s gettext.php to PHP’s gettext. interesting stuff – i hope babelfish does it’s job… πŸ˜‰
    MarkusW posts in the german wordpress forum, refering to this speed comparison.
    regards, erik

  6. i am playing with wordpress for the last 6 months .

    i am now trying to change the language settings of the wordpress installed .

    i just downloaded the file es_ES.mo, and created a directory in wp-include file .and placed the file in wp-includes/language .

    modified wp-config as u told with this line define(WPLANG, ‘es_ES’);

    the language is not changed ..

    Any valuable suggesions will be appreciated .

  7. In our blog, users shall be able to select the language of the frontend and the backend. They shall select the .mo-file used both in front- and backend. Is this possible in WordPress 2.7 by the code mentioned above?

  8. thanks John for sharing this idea! worked perfectly for me, I just added validation for $_GET[‘lang’]

    such a simple solution – no need for various plugins any more! πŸ™‚

Leave a Reply to links for 2008-01-30 | unblogged|Artikelverzeichnis Cancel reply

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