User login

Remixing Drupal the Agaric Way: Multilingual Panels

Step 1: Find a function that does some or most of what you want.
Step 2: Find another function that does the rest of what you want.
Step 3: Mash them together.

The situation this time: we have a Drupal 5 site (World Social Forum 2008) with i18n (internationalization module) and need translated content to show up in panels.

Update: Go straight to the patch.

Here's some code in translation.module of the i18n package that shows one way this translation system for multilingual Drupal 5 figures out what nodes to care about:

<pre>
/**
* Implementation of hook_link().
*/
function translation_link($type, $node = NULL, $teaser = FALSE) {
  $languages = i18n_supported_languages();
  $links = array();
  if ($type == 'node' && variable_get('i18n_translation_node_links', 0) > ($teaser ? 1 : 0) && $node->translation) {
    foreach ($node->translation as $lang => $trnode) {
      // Add node link if published
      if($trnode->status) {
        // If language is not enabled, we'll use current language for the prefix
        $baselang = variable_get('i18n_translation_links', 0) || !isset($languages[$lang]) ? i18n_get_lang() : $lang;
        $links['translation-'.$lang]= theme('translation_node_link', $trnode , $lang, $baselang);
      }
    }
  }
  return $links;
}
</pre>

And here is the code from node.inc of the Panels package, which provides all the basic information for showing nodes:

<pre>/**
* Output function for the 'node' content type. Outputs a node
* based on the nid and settings supplied in the configuration.
*/
function panels_content_node($conf) {
  $node = node_load($conf['nid']);
  if (!node_access('view', $node)) {
    return;
  }

  if ($conf['suppress_title']) {
    $node->title = '';
  }

  $output = node_view($node, $conf['teaser'], FALSE, $conf['links']);
  return $output;
}</pre>

(Note: I've already changed the comment text above this function, which in the original was clearly a copy of the block.inc text.)

So let's mix and match, making the panels node view function multilingual-compatible with the parts Agaric added in bold:

<pre>
function panels_content_node($conf) {
  $node = node_load($conf['nid']);
  if (!node_access('view', $node)) {
    return;
  }
<strong>
  /* this could be optimized to check for translations by nid
   * BEFORE the node is loaded above.  This is a lot easier though.
   * Maybe not a big deal with node caching?
   */
  if ($node->translation) {
    // i18n_get_lang() gets the language the site is being browsed in
    if (array_key_exists(i18n_get_lang(), $node->translation)) {
      $lang = i18n_get_lang();
    } else {
      // use the default language
      $lang = i18n_default_language();
    }
    // avoid redundant node load, even if cached
    if ($node->language != $lang) { 
      $node = node_load($node->translation[$lang]->nid);
    }
  }
</strong>
  if ($conf['suppress_title']) {
    $node->title = '';
  }

  $output = node_view($node, $conf['teaser'], FALSE, $conf['links']);
  return $output;
}
</pre>

Agaric is pretty sure you aren't consigned to hell for hacking Drupal contrib modules. Only a few years in purgatory. This would have been better done with creating another include file to provide a separate interface for translated nodes, but this has very little performance impact if the node doesn't have a translation-- and Views 2 plus Drupal 6 had better just do it!

Resolution

Searched words: 
i18n moddule panels i18n agaric

Comments

In addition to forgetting

In addition to forgetting the obligatory parenthesis for the first if () statement, and a semicolon in the last one, I neglected to put on the final array key [EDIT: not array, but an object '->'] in $node = node_load($node->translation[$lang]) (even though I had mentally noted I had to. ADHD is not for the complacent coder).

This had the entirely irrelevant (but interesting) side effect of showing me what node_load tries to do when handed an array with extra keys:

SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE n.nid = '%s' AND n.title = '%s' AND n.status = '%s' AND n.language = '%s',
Array
(
[0] => 568
[1] => Italian title
[2] => 1
[3] => it
)

What was actually passed in:

[it] => stdClass Object (
[nid] => 568
[title] => Italian title
[status] => 1
[language] => it
)

This gave an error of course since there is no such thing as n.language (Agaric is just ahead of our time, something like it exists in Drupal 6). But still-- pretty interesting, that.

Thanks

Hey mate,

Thanks a lot for this code. I used it in Panels2, except instead of putting it in the Node content type, I put it straight in the context, so that all related panes will see the translated node.

Peace

Pawel

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • 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> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.