Search code examples
phpdrupalinternationalization

Drupal module_invoke() and i18n


I am tasked with i18n-ing our current CMS setup in Drupal. The problem that I am facing is with use of module_invoke() to place blocks within nodes.

I have managed to string translate blocks, and that is working when a block is placed in a region (block content is successfully translated) using the UI.

However, when a block is injected into a node like such:

$block = module_invoke('block', 'block', 'view', 22); print $block['content'];

It is not getting translated, or even worse, not showing at all.

I have also tried this variation using t(). e.g.:

$block = module_invoke('block', 'block', 'view', 22); print t($block['content']);

to no avail.

Generally speaking I've having a bit of trouble with blocks for i18n. Does anyone have a recommended approach for dealing with blocks in drupal with regards to translating them? I would prefer not to create different blocks for each language.


Solution

  • So .. After digging around in the bowels of Drupal - and much hair pulling .. I've come up with an almost decent solution.

    Basically, with this function, I can extract a translated version of a block:

    function render_i18n_block($block_id, $region = "hidden"){
    
        if ($list = block_list($region)) {
            foreach ($list as $key => $block) {
              // $key == <i>module</i>_<i>delta</i>
              $key_str = "block_".$block_id;
              if ($key_str == $key){
              return theme('block', $block);
              }
            }
        }
    }
    

    Then, in my node, I simple call:

    <?php echo render_i18n_block(<block_id>,<region>); ?>
    

    There can be some issues where your blocks might not be displaying in a region (and therefore you can't pass a region into block_list). For this case, I simply created a region called "hidden" which is not rendered anywhere in my template, but can be used to call block_list.

    Finally (and this is the part that I still need to find a good solution for), I discovered that block_list() in: includes/blocks/block.inc has a bit of an issue.

    It appears that $theme_key is not reliably set unless block_list() is being called from the theme() function (in includes/themes.inc) .. this causes the SQL to return an empty results set. The SQL looks like this:

    $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), array_merge(array($theme_key), $rids));
    

    As you can see, if theme_key is not set, then it will just return an empty result. For now I am bypassing this by simply adding:

    if (!isset($theme_key)){$theme_key="<my_theme_name>";}
    

    in modules/blocks/block.inc::block_list() around line 429 .. I still need to work out a better way to do this.

    • 10 for anyone with suggestions on how I could ensure that $theme_key is set before calling block_list :)