Skip to main content
Contact us on +32 2 306 02 11 or mail us at info@desk02.be

Analysis of the Drupal language switcher block

The locale module provides a language switcher block. This block, on its own, only prefixes the current link with the appropriate language prefix. Using the language switcher like this only results in seeing the same node with a translated interface. The code producing this block also introduces a new hook called hook_translation_link_alter() which allows other modules to modify the links in the language switcher block.

It is the content translation module that implements this hook to provide a link to the translated node if it is part of a translation set (tnid column in the node table). The implementation of this hook is somewhat particular that it introduces a behaviour that can seem inconsistent.

You only notice this behaviour when you have more than two languages enabled. So for the example presented here we'll assume that the languages English, Dutch and French are enabled. Also, we have enabled the "Enabled, with translation" option for the page content type, the language switcher block is active in one of the regions and the language negotiation is set to one of the "path prefix" options.

When you create your first page node you'll notice that the language switcher block displays a link for each language that points to this exact node prepended with the language prefix. Clicking those links thus keeps showing the current page and only translates the interface. Just like the language switcher works when only the locale module has been activated.

If you click translate and create a new page node as a translation and save the node you'll notice that the language switch now only displays two of the three languages. Because there is no translation of the node in that language translation module removes that link. One could now argue that when we had only one node there also weren't translations of the node so it should have removed the other links and only show one link instead of three.

The reason the block behaves like this is because the content translation module only acts on the links if the node is part of a translation set. A node is only part of a translation set if the tnid value in the node table is set to something other than 0. The tnid value points to the source translation of a translation set.

When you create a first node of a translatable content-type the tnid value for that node will be 0. When you create a translation of that node the tnid value of that new node will be set to the nid of the source node. The tnid of the source node will also be set to that value. When deleting either node the tnid will be reset to 0.

This behaviour catches a lot of people (and customers) by surprise and most of them feel it's not logical. But when you ask how it should behave the answers aren't consistent either. This is a trend with everything related to the internationalization and localization of web sites and applications in general. Specifying how a language switcher should work can even become harder when multiple countries are available.

When you start a project that will have multiple languages you should make sure to describe how the the language switcher will work on the home page, node pages, views and other listings. Because if you start thinking about this at the end of the road you surely will encounter surprises.

So, what are possible solutions to this problem? Well, for one there is the translation 404 module which tells the visitor the translation is not available when he switches the language on a node page instead of just translating the interface like the default block would do.

On this site the language switcher block always sends the visitor to the home page. Although this can be a pain when you want to switch the language on the contact page at least it's consistent and easy to describe.

To be able to determine what the best or least confusing solution would be we should know how much such a language switcher is actually used. Once I started thinking about that my guess is that the switcher isn't used all that much. If this is true then I think that a language switcher that points to the home page in the user's language isn't that bad a solution. Maybe we could also show an extra link on nodes that have a direct translation to maybe catch the rare situations where one would land on a page with the content he's looking for but in the incorrect language.

I'm really wondering about language switcher usage patterns. Please share your opinion below or if you have hard data about this I'd like to know as well.

I'll follow up this post with a post about the language negotiation in Drupal which isn't all that consistent either but, just like language switchers, everybody has an opinion on those as well.

Tags: Drupal, i18n

Comments

google is the best.

Active Translation (http://drupal.org/project/active_translation) resolves the issue that a Language disappears from the language switcher block with three or more languages.
If a node has not been translated into the current language, it displays the original node as a fallback, with the option to display a message about the unavailable translation.

I find it helpful to show both the lge switcher and the translation links in the nodes themselves, but I can't say which is used more often, since the site is not yet online. ;)
I guess user use the lge switcher block more often to translate the interface, instead of content.

Another quick question: how did you manage to display the comments of one node on the translated node and vice versa? I used a View with a relationship, but maybe there's another way.

@Narretz: I hacked core :)
It was the easiest way and that way we could use the standard node view.

Olivier, please, how did you do that? Making language switcher always leading a visitor to the home page in that language?

Yes, how did you do that: having the language switcher always send the visitor to the home page?
Thanks
Alan

This is a custom block:

/**
 * Copy of the locale_block function but altered to point to the front page when no translation of the node is available.
 * When not viewing a specific node we change the language prefix which is the default behaviour.
 */
function mymodule_block($op = 'list', $delta = 0) {
  global $language;
 
  if ($op == 'list') {
    $block[0]['info'] = t('Desk02 language switcher');
    // Not worth caching.
    $block[0]['cache'] = BLOCK_NO_CACHE;
    return $block;
  }
  elseif ($op == 'view') {
    $block['subject'] = t('Languages');
    $languages = language_list('enabled');
    $links = array();
    foreach ($languages[1] as $lang) {
      $links[$lang->language] = array(
        'href'       => $lang->language == $language->language ? $_GET['q'] : '<front>',
        'title'      => $lang->native,
        'language'   => $lang,
        'attributes' => array('class' => 'language-link'),
      );
    }
    $block['content'] = theme('links', $links, array());
    return $block;
  }
}

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby>. The supported tag styles are: <foo>, [foo].
  • Feweb - Federatie van webontwikkelaars
  • Lid van Drupal Association
  • Sugar CRM