CCK Node Reference is an excellent module that allows creation of complex relationships between content types in Drupal. Combine that with Views2 feature called Relationships and you have one of the most sophisticated information architecture design tools any CMS has ever seen. At least - if you stick to one language. When you are working on a multilingual website, though, things get complicated. In this blog post we will discuss how to properly configure node references on a multilingual Drupal website.

When your website is multilingual the referenced nodes are also in multiple languages. On an English-only website, you set up your Node Reference field by indicating the node type. Try that on a multilingual site and your drop-downs, on node edit pages, will have choices in all languages! That’s just amateur. Any self-respecting client will frown if you deliver a solution like that.

The first step at fixing the problem is to indicate a view in the Node Reference configuration, instead of a node type. That does not get us all the way to the destination, however, since View only has an option of indicating “current user language” as a filter. That is not what we need. We need to filter view by the language of the node being edited. You can only do that in a View if you use Views Arguments. Unfortunately, whilst Node Reference does allow passing arguments, it only allows passing hardcoded arguments and does not allow passing a dynamic property of the current node (e.g. language).

While we believe this is a serious shortcoming of the Node Reference module, and hope that they will add such feature in the future, right now we have to forget about arguements and praise the authors of Views2 for leaving all kinds of hooks to change the default behavior of the Views programmatically.

The solution is to write a Query Alter hook implementation for views, that will filter view for use on node edit pages by the language of the edited node, if present, or the current user language if node does not have a language specified.

An example code, that takes care of Node Reference node types (and corresponding views) called “company” and “location” would look something like the listing below and would be placed in a module called “modulename”.

function modulename_views_query_alter(&$view, &$query) {
  global $language;

  if ( arg(0) == 'node' &&
       ( (is_numeric(arg(1)) && arg(2) == 'edit') ||
         (arg(1) == 'add') )
      && ( $view->name == 'company' || $view->name == 'location') ) {

    $node = node_load(arg(1));
    if (!empty($node->language)) {
      $lang = $node->language;
    } else if (arg(1)=='add' && !empty($_GET['language']))  {
      $lang = $_GET['language'];
    } else {
      $lang = $language->language; //default user lang

      $query->where[0]['clauses'][] = 'node.language = \'%s\'';
      $query->where[0]['args'][] = $lang;

P.S. This implementation has one last, minor flaw: if you are changing the language of a node, you will have to first save the change, before dropdowns of the Node Reference fields will update, but hey - nothing is perfect in this world :)