This module provides support for multilingual blocks

These are not real blocks, but metablocks that group together a number of normal blocks and display the right one depending on language

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.

'); case 'admin/build/block/i18n': return t('

These are not real blocks, but metablocks that group together a number of normal blocks and display the right one depending on language

'); } } /** * Implementation of hook_db_rewrite_sql() */ function i18nblocks_db_rewrite_sql($query, $primary_table, $primary_key) { if ($primary_table == 'b' && $primary_key == 'bid') { $return['join'] = 'LEFT JOIN {i18n_blocks_language} i18n ON b.module = i18n.module AND b.delta = i18n.delta'; $return['where'] = i18n_db_rewrite_where('i18n', 'block', 'simple'); return $return; } } /** * Implementation of hook_menu() */ /* function i18nblocks_menu() { $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->i18ndelta]['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 hook_locale(). */ function i18nblocks_locale($op = 'groups') { switch ($op) { case 'groups': return array('blocks' => t('Blocks')); } } /** * Implementation of block form_alter(). * * Remove block title for multilingual blocks. */ function i18nblocks_form_alter(&$form, $form_state, $form_id) { if ($form_id == 'block_admin_configure') { $form['i18n'] = array( '#type' => 'fieldset', '#title' => t('Multilingual settings'), '#collapsible' => TRUE, ); // For i18nblocks, just a help text if (($module = $form['module']['#value']) == 'i18nblocks') { $form['i18n']['text'] = array('#value' => t('This is a translatable block.')); // Unset block title unset($form['block_settings']['title']); $form['block_settings']['title'] = array('#type' => 'value', '#value' => ''); } else { $block = i18nblocks_get_language($module, $form['delta']['#value']); $form['i18n'] = array( '#type' => 'fieldset', '#title' => t('Multilingual settings'), '#collapsible' => TRUE, ); // Language options will depend on block type $options = array('' => t('All languages')) + locale_language_list('name'); if ($module == 'block') { $options[I18N_BLOCK_LOCALIZE] = t('Translatable block'); } $form['i18n']['language'] = array( '#type' => 'radios', '#title' => t('Language'), '#default_value' => $block->language, '#options' => $options, ); // Pass i18ndelta value $form['i18n']['i18ndelta'] = array('#type' => 'value', '#value' => $block->i18ndelta); $form['#submit'][] = 'i18nblocks_block_admin_configure_submit'; } } // Content type setting: Optional nodeasblock synchronization /** 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.'), ); } // Node form with nodeasblock settings 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); } */ } /** * Forms api callback. Submit function */ function i18nblocks_block_admin_configure_submit($form, &$form_state) { $values = $form_state['values']; i18nblocks_set_language($values['module'], $values['delta'], $values['language']); i18nblocks_save($values); } /** * Get block language data */ function i18nblocks_get_language($module, $delta) { $block = db_fetch_object(db_query("SELECT l.*, b.i18ndelta FROM {i18n_blocks_language} l LEFT JOIN {i18n_blocks} b ON l.module = b.module AND l.delta = b.delta WHERE l.module = '%s' AND l.delta = %d", $module, $delta)); // If no result, return default settings return $block ? $block : (object)array('language' => '', 'i18ndelta' => 0); } /** * Set block language data */ function i18nblocks_set_language($module, $delta, $language) { db_query("DELETE FROM {i18n_blocks_language} WHERE module = '%s' AND delta = %d", $module, $delta); if ($language) { db_query("INSERT INTO {i18n_blocks_language} (module, delta, language) VALUES('%s', %d, '%s')", $module, $delta, $language); } } /** * Update i18n block data. Only for localizable blocks */ function i18nblocks_save($values) { dargs(); if ($values['language'] == I18N_BLOCK_LOCALIZE) { $values['info'] = t('[Translatable]'.' '.$values['info']); if ($values['i18ndelta']) { drupal_write_record('i18n_blocks', $values, 'i18ndelta'); } else { drupal_write_record('i18n_blocks', $values); } } else { db_query("DELETE FROM {i18n_blocks} WHERE module = '%s' AND delta = %d", $values['module'], $values['delta']); } } /** * Load and translate block data */ function i18nblocks_get_block($delta, $language){ // Get block metadata $meta = db_fetch_object(db_query("SELECT i.*, b.title FROM {i18n_blocks} i INNER JOIN {blocks} b ON i.delta = b.delta AND i.module = b.module WHERE i.i18ndelta = '%d'", $delta)); // Get block data from module $block = module_invoke($meta->module, 'block', 'view', $meta->delta); if ($block) { // Override the default title if ($meta->title) { // Check plain here to allow module generated titles to keep any markup. $block['subject'] = $meta->title == '' ? '' : check_plain(tt("blocks:block:$delta:title", $meta->title, $language)); } elseif (!empty($block['subject'])) { $block['subject'] = tt("blocks:block:$delta:title", $block['subject'], $language); } $block['content'] = tt("blocks:block:$delta:content", $block['content'], $language); return $block; } } /** * 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; } 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); }