You are here

i18nblocks.module in Internationalization 5

File

i18nblocks/i18nblocks.module
View source
<?php

/**
 * Internationalization (i18n) submodule: Multilingual meta-blocks
 * 
 * @author Jose A. Reyero, 2005
 */

/**
 * Implementation of hook_help()
 */
function i18nblocks_help($section = 'admin/help#i18nblocks') {
  switch ($section) {
    case 'admin/help#i18nblocks':
      return t('<h2>This module provides support for multilingual blocks</h2>
        <p>These are not real blocks, but metablocks that group together a number of normal blocks and display the right one depending on language</p>
        <p>In the block administration pages you will find a new tab for creating "Multilingual blocks". Set them up as usual and define which one of the other blocks will be shown for each language.</p>
        ');
    case 'admin/build/block/i18n':
      return t('<p>These are not real blocks, but metablocks that group together a number of normal blocks and display the right one depending on language</p>');
  }
}

/**
 * Implementation of hook_menu()
 */
function i18nblocks_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/build/block/i18n',
      'title' => t('Add multilingual block'),
      'access' => user_access('administer blocks'),
      'callback' => 'i18nblocks_admin',
      'type' => MENU_LOCAL_TASK,
    );
  }
  return $items;
}

/**
 * Implementation of hook_block()
 */
function i18nblocks_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks = array();
      $result = db_query("SELECT * FROM {i18n_blocks}");
      while ($data = db_fetch_object($result)) {
        $blocks[$data->delta]['info'] = $data->info;
      }
      return $blocks;
    case 'view':
      return i18nblocks_get_block($delta, i18n_get_lang());
      break;
    case 'configure':
      return i18nblocks_form(i18nblocks_get_metablock($delta, TRUE), $delta);
    case 'save':
      i18nblocks_save($edit, $delta);
      break;
  }
}

/**
 * Implementation of block form_alter().
 * 
 * Remove block title for multilingual blocks.
 */
function i18nblocks_form_alter($form_id, &$form) {
  if ($form_id == 'block_admin_configure' && isset($form['block_settings']['i18nblocks'])) {
    unset($form['block_settings']['title']);
    $form['block_settings']['title'] = array(
      '#type' => 'value',
      '#value' => '',
    );
  }
  elseif (module_exists('nodeasblock') && $form_id == 'node_type_form' && isset($form['identity']['type'])) {
    $form['workflow']['nodeasblockset']['i18n_nodeasblock'] = array(
      '#type' => 'radios',
      '#title' => t('Create translation blocks automatically'),
      '#default_value' => variable_get('i18n_nodeasblock_' . $form['#node_type']->type, 0),
      '#options' => array(
        0 => t('Disabled'),
        1 => t('Enabled'),
      ),
      '#description' => t('Automatic synchronization with blocks generated by nodeasblock module.'),
    );
  }
  elseif (isset($form['type']) && ($node = $form['#node']) && $form['type']['#value'] . '_node_form' == $form_id && variable_get("i18n_nodeasblock_{$node->type}", 0) && isset($form['nodeasblockset'])) {
    if ($i18nblock = _i18nblocks_nodeasblock($node)) {
      $block = i18nblocks_get_metablock($i18nblock['delta']);

      // Override form default values, but not block title
      foreach (array(
        'block_settings',
        'user_vis_settings',
        'role_vis_settings',
        'page_vis_settings',
      ) as $category) {
        if (isset($form['nodeasblockset'][$category])) {
          foreach (element_children($form['nodeasblockset'][$category]) as $field) {
            if (isset($block->{$field}) && $field != 'title') {
              $form['nodeasblockset'][$category][$field]['#default_value'] = $block->{$field};
            }
          }
        }
      }

      // Override first level value
      foreach (array(
        'status',
        'region',
        'weight',
        'visibility',
        'pages',
        'custom',
      ) as $field) {
        if ($form['nodeasblockset'][$field]['#type'] == 'value') {
          $form['nodeasblockset'][$field]['#value'] = $block->{$field};
        }
        elseif (isset($form['nodeasblockset'][$field]['#default_value'])) {
          $form['nodeasblockset'][$field]['#default_value'] = $block->{$field};
        }
      }
      $form['nodeasblockset']['i18ntxt'] = array(
        '#value' => t('Some block settings have been overridden by the translation block'),
      );
    }
    else {

      // Prepare a new block
      $i18nblock = array(
        'type' => 'nodeasblock',
        'info' => '',
        'i18nblocks' => array(),
        'delta' => '',
        'new' => TRUE,
      );
    }
    $form['i18nblock'] = array(
      '#type' => 'value',
      '#value' => $i18nblock,
    );
  }
}

/**
 * Implementation of hook_nodeapi
 */
function i18nblocks_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if (variable_get("nodeasblock_{$node->type}", 1) && variable_get("i18n_nodeasblock_{$node->type}", 0)) {
    switch ($op) {
      case 'submit':
        if ($node->i18nblock) {

          // Copy values from the form before changing any
          foreach (array(
            'status',
            'region',
            'weight',
            'visibility',
            'pages',
            'custom',
            'info',
          ) as $field) {
            $node->i18nblock['block'][$field] = $node->nodeasblockset[$field];
          }

          // If the block is new, disable the block changing status before it is saved
          if (!$node->nodeasblock) {
            $node->nodeasblockset['status'] = 0;
            $node->nodeasblockset['region'] = BLOCK_REGION_NONE;
          }
        }
        break;
      case 'update':
      case 'insert':

        // Regenerate all translations for this block
        // This will run after i18n, translations and nodeasblock
        if (isset($node->i18nblock) && ($metablock = $node->i18nblock)) {
          $metablock['nids'][$node->nid] = $node->nid;

          // Recreate the translation block. Or delete if no blocks.
          $metablock['i18nblocks'] = array();
          $result = db_query("SELECT * FROM {i18n_node} i INNER JOIN {nodeasblock} n ON i.nid = n.nid WHERE i.nid IN (%s) ", implode(',', $metablock['nids']));
          while ($trn = db_fetch_object($result)) {
            $metablock['i18nblocks'][$trn->language] = "nodeasblock:{$trn->nid}";
          }
          if ($metablock['i18nblocks']) {

            // Set values if new block
            if (!$metablock['info']) {
              $metablock['info'] = t('Translation: !title', array(
                '!title' => $node->title,
              ));
            }
            $metablock = i18nblocks_save($metablock);

            // Only if the block is new, rehash block table
            if (isset($metablock['new'])) {
              _block_rehash();
            }
            if ($block = $metablock['block']) {
              $block['status'] = 1;
              $block['delta'] = $metablock['delta'];
              db_query("UPDATE {blocks} SET status = %d, region = '%s', weight = %d, visibility = %d, pages = '%s', custom = %d WHERE module = 'i18nblocks' AND delta = '%s'", $block['status'], $block['region'], $block['weight'], $block['visibility'], trim($block['pages']), $block['custom'], $block['delta']);
            }
          }
          elseif ($metablock['delta']) {
            i18nblocks_delete($metablock['delta']);
          }
        }
        break;
    }
  }
}

/**
 * Helper function: collect translation nids and get related nodeasblock block
 */
function _i18nblocks_nodeasblock($node) {
  $nids = $translations = array();
  if ($node->trid) {

    // It is a translation
    $translations = translation_node_get_translations(array(
      'trid' => $node->trid,
    ));
  }
  elseif ($node->translation_nid) {

    // Translation is just being created
    $translations = translation_node_get_translations(array(
      'nid' => $node->translation_nid,
    ), TRUE);
    $nids[$node->translation_nid] = $node->translation_nid;
  }
  foreach ($translations as $lang => $trn) {
    $nids[$trn->nid] = $trn->nid;
  }
  if ($node->nid) {

    // Updating existing node, no translations yet
    $nids[$node->nid] = $node->nid;
  }

  // Check for existing block
  if (!empty($nids) && ($i18nblock = db_fetch_array(db_query_range("SELECT m.* FROM {i18n_blocks} m INNER JOIN {i18n_blocks_i18n} b ON m.delta = b.bid WHERE m.type = 'nodeasblock' AND b.delta IN (%s)", implode(',', $nids), 0, 1)))) {
    $i18nblock['nids'] = $nids;
    return $i18nblock;
  }
}

/**
 * Form for multilingual blocks
 */
function i18nblocks_form($metablock, $delta = NULL) {
  $languages = i18n_supported_languages();
  $modules = array_intersect(module_list(), module_implements('block'));

  // Compile list of available blocks
  $blocklist = array(
    '' => t(' -- '),
  );
  foreach (module_implements('block') as $module) {
    if ($module != 'i18nblocks') {

      // Avoid this module's blocks, could be funny :-)
      if (is_array($module_blocks = module_invoke($module, 'block', 'list'))) {
        foreach ($module_blocks as $number => $block) {
          $blocklist[$module . ':' . $number] = $block['info'] . "({$module})";
        }
      }
    }
  }
  $form['info'] = array(
    '#type' => 'textfield',
    '#title' => t('Block description'),
    '#default_value' => $metablock->info ? $metablock->info : t('Multilingual block !number', array(
      '!number' => $delta,
    )),
    '#size' => 40,
    '#maxlength' => 40,
  );
  $form['type'] = array(
    '#type' => 'value',
    '#value' => $metablock->type ? $metablock->type : '',
  );
  $form['i18nblocks'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Select the block to be displayed for each language'),
  );
  foreach ($languages as $lang => $langname) {
    $block = isset($metablock->blocks[$lang]) ? $metablock->blocks[$lang] : NULL;
    $form['i18nblocks'][$lang] = array(
      '#type' => 'select',
      '#title' => $langname,
      '#default_value' => $block ? $block->module . ':' . $block->delta : '',
      '#options' => $blocklist,
    );
  }

  // Submit button only for new blocks
  if ($delta) {
    $form['delete'] = array(
      '#value' => l(t('Delete this block'), 'admin/build/block/i18n/delete/' . $delta),
    );
    $form['type'] = array(
      '#type' => 'radios',
      '#default_value' => $metablock->type,
      '#options' => array(
        '' => t('Normal translation block'),
      ),
      '#disabled' => TRUE,
    );
    if (module_exists('nodeasblock')) {
      $form['type']['#options']['nodeasblock'] = t('Node as block with automatic synchronization');
      $form['type']['#disabled'] = FALSE;
    }
  }
  else {
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Create block'),
    );
  }
  return $form;
}

/**
 * Add a new metablock and go to settings page
 */
function i18nblocks_admin($op = 'add', $delta = NULL, $confirm = FALSE) {
  if ($op == 'add') {
    $metablock = new StdClass();
    $metablock->info = t('New multilingual block');
    return drupal_get_form('i18nblocks_form', $metablock);
  }
  elseif ($op == 'delete' && $delta && ($block = i18nblocks_get_metablock($delta))) {
    i18nblocks_delete($delta);
    drupal_set_message("The block has been deleted");
    drupal_goto('admin/build/block');
  }
}
function i18nblocks_form_submit($form_id, $form_values) {
  i18nblocks_save($form_values, NULL);
  return 'admin/build/block';
}

/**
 * Db layer: for now it stores each block as a variable
 */
function i18nblocks_get_metablock($delta, $getblocks = FALSE) {
  $metablock = db_fetch_object(db_query("SELECT b.*, i.* FROM {blocks} b INNER JOIN {i18n_blocks} i ON b.delta = i.delta WHERE b.module = 'i18nblocks' AND b.delta = '%s'", $delta));
  if ($getblocks) {
    $result = db_query("SELECT * FROM {i18n_blocks_i18n} WHERE bid = '%s'", $delta);
    $metablock->blocks = array();
    while ($block = db_fetch_object($result)) {
      $metablock->blocks[$block->language] = $block;
    }
  }
  return $metablock;
}

// Load and process block data
function i18nblocks_get_block($delta, $language) {
  $meta = db_fetch_object(db_query("SELECT i.*, b.title FROM {i18n_blocks_i18n} i INNER JOIN {blocks} b ON i.delta = b.delta AND i.module = b.module WHERE i.bid = '%d' AND i.language = '%s'", $delta, $language));
  if ($block = module_invoke($meta->module, 'block', 'view', $meta->delta)) {
    if ($meta->title) {

      // Check plain here to allow module generated titles to keep any markup.
      $block['subject'] = $meta->title == '<none>' ? '' : check_plain($meta->title);
    }
    return $block;
  }
}
function i18nblocks_save($edit, $delta = NULL) {
  $delta = isset($edit['delta']) && $edit['delta'] ? $edit['delta'] : $delta;
  if ($delta) {
    db_query("UPDATE {i18n_blocks} SET info = '%s', type = '%s' WHERE delta = '%s'", $edit['info'], $edit['type'], $delta);
    db_query("DELETE FROM {i18n_blocks_i18n} WHERE bid = %d", $delta);
  }
  else {

    // New block, return delta value
    $edit['delta'] = $delta = db_next_id('{i18n_blocks}_delta');
    if ($edit['info'] == t('New multilingual block') || !$edit['info']) {
      $edit['info'] = t('Multilingual block !number', array(
        '!number' => $delta,
      ));
    }
    db_query("INSERT INTO {i18n_blocks}(delta, info, type) VALUES('%d', '%s', '%s')", $delta, $edit['info'], $edit['type']);
    drupal_set_message(t("Created new block '%name'", array(
      '%name' => $edit['info'],
    )));
  }

  // Save language blocks
  foreach ($edit['i18nblocks'] as $lang => $path) {
    if ($path) {
      list($module, $gamma) = explode(':', $path);
      db_query("INSERT INTO {i18n_blocks_i18n}(bid, language, module, delta) VALUES(%d, '%s', '%s', '%s')", $delta, $lang, $module, $gamma);
    }
  }
  return $edit;
}
function i18nblocks_delete($delta) {
  db_query("DELETE FROM {i18n_blocks} WHERE delta = '%s'", $delta);
  db_query("DELETE FROM {i18n_blocks_i18n} WHERE bid = '%s'", $delta);
}

Functions

Namesort descending Description
i18nblocks_admin Add a new metablock and go to settings page
i18nblocks_block Implementation of hook_block()
i18nblocks_delete
i18nblocks_form Form for multilingual blocks
i18nblocks_form_alter Implementation of block form_alter().
i18nblocks_form_submit
i18nblocks_get_block
i18nblocks_get_metablock Db layer: for now it stores each block as a variable
i18nblocks_help Implementation of hook_help()
i18nblocks_menu Implementation of hook_menu()
i18nblocks_nodeapi Implementation of hook_nodeapi
i18nblocks_save
_i18nblocks_nodeasblock Helper function: collect translation nids and get related nodeasblock block