4f0fa0362e4789a7423197e1f576707677e3b2af
[project/i18n.git] / i18nblocks / i18nblocks.module
1 <?php
2 // $Id$
3
4 /**
5 * Internationalization (i18n) submodule: Multilingual meta-blocks
6 *
7 * @author Jose A. Reyero, 2005
8 *
9 * @ TODO Add strings on block update
10 */
11
12 // Tag for localizable block, cannot be any language
13 define('I18N_BLOCK_LOCALIZE', '__LOCALIZE__');
14
15 /**
16 * Implementation of hook_help()
17 */
18 function i18nblocks_help($section = 'admin/help#i18nblocks' ) {
19 switch ($section) {
20 case 'admin/help#i18nblocks':
21 return t('<h2>This module provides support for multilingual blocks</h2>
22 <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>
23 <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>
24 ');
25 case 'admin/build/block/i18n':
26 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>');
27 }
28 }
29
30 /**
31 * Implementation of hook_db_rewrite_sql()
32 */
33 function i18nblocks_db_rewrite_sql($query, $primary_table, $primary_key) {
34
35 if ($primary_table == 'b' && $primary_key == 'bid') {
36 $return['join'] = 'LEFT JOIN {i18n_blocks_language} i18n ON b.module = i18n.module AND b.delta = i18n.delta';
37 $return['where'] = i18n_db_rewrite_where('i18n', 'block', 'simple');
38 return $return;
39 }
40 }
41 /**
42 * Implementation of hook_menu()
43 */
44 /*
45 function i18nblocks_menu() {
46 $items[] = array('path' => 'admin/build/block/i18n', 'title' => t('Add multilingual block'),
47 'access' => user_access('administer blocks'),
48 'callback' => 'i18nblocks_admin',
49 'type' => MENU_LOCAL_TASK);
50 return $items;
51 }
52
53 /**
54 * Implementation of hook_block()
55 */
56 function i18nblocks_block($op = 'list', $delta = 0, $edit = array()) {
57 switch($op) {
58 case 'list':
59 $blocks = array();
60 $result = db_query("SELECT * FROM {i18n_blocks}");
61 while ($data = db_fetch_object($result)) {
62 $blocks[$data->i18ndelta]['info'] = $data->info;
63 }
64 return $blocks;
65 case 'view':
66 return i18nblocks_get_block($delta, i18n_get_lang());
67 break;
68 case 'configure':
69 //return i18nblocks_form(i18nblocks_get_metablock($delta, TRUE), $delta);
70
71 case 'save':
72 //i18nblocks_save($edit, $delta);
73 break;
74 }
75 }
76
77 /**
78 * Implementation of hook_locale().
79 */
80 function i18nblocks_locale($op = 'groups') {
81 switch ($op) {
82 case 'groups':
83 return array('blocks' => t('Blocks'));
84 }
85 }
86
87 /**
88 * Implementation of block form_alter().
89 *
90 * Remove block title for multilingual blocks.
91 */
92 function i18nblocks_form_alter(&$form, $form_state, $form_id) {
93 if ($form_id == 'block_admin_configure') {
94 $form['i18n'] = array(
95 '#type' => 'fieldset',
96 '#title' => t('Multilingual settings'),
97 '#collapsible' => TRUE,
98 );
99 // For i18nblocks, just a help text
100 if (($module = $form['module']['#value']) == 'i18nblocks') {
101 $form['i18n']['text'] = array('#value' => t('This is a translatable block.'));
102 // Unset block title
103 unset($form['block_settings']['title']);
104 $form['block_settings']['title'] = array('#type' => 'value', '#value' => '');
105 } else {
106 $block = i18nblocks_get_language($module, $form['delta']['#value']);
107 $form['i18n'] = array(
108 '#type' => 'fieldset',
109 '#title' => t('Multilingual settings'),
110 '#collapsible' => TRUE,
111 );
112 // Language options will depend on block type
113 $options = array('' => t('All languages')) + locale_language_list('name');
114 if ($module == 'block') {
115 $options[I18N_BLOCK_LOCALIZE] = t('Translatable block');
116 }
117 $form['i18n']['language'] = array(
118 '#type' => 'radios',
119 '#title' => t('Language'),
120 '#default_value' => $block->language,
121 '#options' => $options,
122 );
123 // Pass i18ndelta value
124 $form['i18n']['i18ndelta'] = array('#type' => 'value', '#value' => $block->i18ndelta);
125 $form['#submit'][] = 'i18nblocks_block_admin_configure_submit';
126 }
127 }
128
129 // Content type setting: Optional nodeasblock synchronization
130 /**
131 elseif(module_exists('nodeasblock') && $form_id == 'node_type_form' && isset($form['identity']['type'])) {
132 $form['workflow']['nodeasblockset']['i18n_nodeasblock'] = array(
133 '#type' => 'radios',
134 '#title' => t('Create translation blocks automatically'),
135 '#default_value' => variable_get('i18n_nodeasblock_'. $form['#node_type']->type, 0),
136 '#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
137 '#description' => t('Automatic synchronization with blocks generated by nodeasblock module.'),
138 );
139 }
140 // Node form with nodeasblock settings
141 elseif (isset($form['type']) && ($node = $form['#node']) && $form['type']['#value'] .'_node_form' == $form_id && variable_get("i18n_nodeasblock_$node->type", 0) && isset($form['nodeasblockset'])) {
142 if ($i18nblock = _i18nblocks_nodeasblock($node)) {
143 $block = i18nblocks_get_metablock($i18nblock['delta']);
144 // Override form default values, but not block title
145 foreach( array('block_settings', 'user_vis_settings', 'role_vis_settings','page_vis_settings') as $category) {
146 if (isset($form['nodeasblockset'][$category])) {
147 foreach(element_children($form['nodeasblockset'][$category]) as $field) {
148 if(isset($block->$field) && $field != 'title') {
149 $form['nodeasblockset'][$category][$field]['#default_value'] = $block->$field;
150 }
151 }
152 }
153 }
154 // Override first level value
155 foreach(array('status', 'region', 'weight', 'visibility', 'pages', 'custom') as $field) {
156 if($form['nodeasblockset'][$field]['#type'] == 'value') {
157 $form['nodeasblockset'][$field]['#value'] = $block->$field;
158 } elseif(isset($form['nodeasblockset'][$field]['#default_value'])) {
159 $form['nodeasblockset'][$field]['#default_value'] = $block->$field;
160 }
161 }
162 $form['nodeasblockset']['i18ntxt'] = array('#value' => t('Some block settings have been overridden by the translation block'));
163 } else {
164 // Prepare a new block
165 $i18nblock = array(
166 'type' => 'nodeasblock',
167 'info' => '',
168 'i18nblocks' => array(),
169 'delta' => '',
170 'new' => TRUE
171 );
172 }
173 $form['i18nblock'] = array('#type' => 'value', '#value' => $i18nblock);
174
175 }
176 */
177 }
178
179 /**
180 * Forms api callback. Submit function
181 */
182 function i18nblocks_block_admin_configure_submit($form, &$form_state) {
183 $values = $form_state['values'];
184 i18nblocks_set_language($values['module'], $values['delta'], $values['language']);
185 i18nblocks_save($values);
186 }
187
188 /**
189 * Get block language data
190 */
191 function i18nblocks_get_language($module, $delta) {
192 $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));
193 // If no result, return default settings
194 return $block ? $block : (object)array('language' => '', 'i18ndelta' => 0);
195 }
196
197 /**
198 * Set block language data
199 */
200 function i18nblocks_set_language($module, $delta, $language) {
201 db_query("DELETE FROM {i18n_blocks_language} WHERE module = '%s' AND delta = %d", $module, $delta);
202 if ($language) {
203 db_query("INSERT INTO {i18n_blocks_language} (module, delta, language) VALUES('%s', %d, '%s')", $module, $delta, $language);
204 }
205 }
206
207 /**
208 * Update i18n block data. Only for localizable blocks
209 */
210 function i18nblocks_save($values) {
211 dargs();
212 if ($values['language'] == I18N_BLOCK_LOCALIZE) {
213 $values['info'] = t('[Translatable]'.' '.$values['info']);
214 if ($values['i18ndelta']) {
215 drupal_write_record('i18n_blocks', $values, 'i18ndelta');
216 } else {
217 drupal_write_record('i18n_blocks', $values);
218 }
219 } else {
220 db_query("DELETE FROM {i18n_blocks} WHERE module = '%s' AND delta = %d", $values['module'], $values['delta']);
221 }
222 }
223
224 /**
225 * Load and translate block data
226 */
227 function i18nblocks_get_block($delta, $language){
228 // Get block metadata
229 $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));
230 // Get block data from module
231 $block = module_invoke($meta->module, 'block', 'view', $meta->delta);
232
233 if ($block) {
234 // Override the default title
235 if ($meta->title) {
236 // Check plain here to allow module generated titles to keep any markup.
237 $block['subject'] = $meta->title == '<none>' ? '' : check_plain(tt("blocks:block:$delta:title", $meta->title, $language));
238 } elseif (!empty($block['subject'])) {
239 $block['subject'] = tt("blocks:block:$delta:title", $block['subject'], $language);
240 }
241 $block['content'] = tt("blocks:block:$delta:content", $block['content'], $language);
242 return $block;
243 }
244 }
245
246 /**
247 * Implementation of hook_nodeapi
248 *
249 function i18nblocks_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
250 if (variable_get("nodeasblock_$node->type", 1) && variable_get("i18n_nodeasblock_$node->type", 0)) {
251 switch ($op) {
252 case 'submit':
253 if ($node->i18nblock) {
254 // Copy values from the form before changing any
255 foreach(array('status', 'region', 'weight', 'visibility', 'pages', 'custom', 'info') as $field) {
256 $node->i18nblock['block'][$field] = $node->nodeasblockset[$field];
257 }
258 // If the block is new, disable the block changing status before it is saved
259 if (!$node->nodeasblock) {
260 $node->nodeasblockset['status'] = 0;
261 $node->nodeasblockset['region'] = BLOCK_REGION_NONE;
262 }
263 }
264 break;
265 case 'update':
266 case 'insert':
267 // Regenerate all translations for this block
268 // This will run after i18n, translations and nodeasblock
269 if(isset($node->i18nblock) && $metablock = $node->i18nblock) {
270 $metablock['nids'][$node->nid] = $node->nid;
271 // Recreate the translation block. Or delete if no blocks.
272 $metablock['i18nblocks'] = array();
273 $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']));
274 while($trn = db_fetch_object($result)) {
275 $metablock['i18nblocks'][$trn->language] = "nodeasblock:$trn->nid";
276 }
277 if ($metablock['i18nblocks']) {
278 // Set values if new block
279 if(!$metablock['info']) {
280 $metablock['info'] = t('Translation: !title', array('!title' => $node->title));
281 }
282 $metablock = i18nblocks_save($metablock);
283 // Only if the block is new, rehash block table
284 if (isset($metablock['new'])) {
285 _block_rehash();
286 }
287 if($block = $metablock['block']) {
288 $block['status'] = 1;
289 $block['delta'] = $metablock['delta'];
290 db_query("UPDATE {blocks} SET status = %d, region = '%s', weight = %d, visibility = %d, pages = '%s', custom = %d WHERE module = 'i18nblocks' AND delta = '%s'",
291 $block['status'], $block['region'], $block['weight'], $block['visibility'], trim($block['pages']), $block['custom'], $block['delta']);
292
293 }
294 } elseif ($metablock['delta']) {
295 i18nblocks_delete($metablock['delta']);
296 }
297 }
298 break;
299 }
300 }
301 }
302 */
303
304 /**
305 * Helper function: collect translation nids and get related nodeasblock block
306 */
307 function _i18nblocks_nodeasblock($node) {
308 $nids = $translations = array();
309 if ($node->trid) { // It is a translation
310 $translations = translation_node_get_translations(array('trid' => $node->trid));
311 } elseif($node->translation_nid) { // Translation is just being created
312 $translations = translation_node_get_translations(array('nid' => $node->translation_nid), TRUE);
313 $nids[$node->translation_nid] = $node->translation_nid;
314 }
315 foreach($translations as $lang => $trn) {
316 $nids[$trn->nid] = $trn->nid;
317 }
318 if($node->nid) { // Updating existing node, no translations yet
319 $nids[$node->nid] = $node->nid;
320 }
321 // Check for existing block
322 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))) {
323 $i18nblock['nids'] = $nids;
324 return $i18nblock;
325 }
326 }
327 /**
328 * Form for multilingual blocks
329 */
330 function i18nblocks_form($metablock, $delta = NULL){
331 $languages = i18n_supported_languages();
332 $modules = array_intersect(module_list(), module_implements('block'));
333 // Compile list of available blocks
334 $blocklist = array('' => t(' -- '));
335 foreach (module_implements('block') as $module) {
336 if($module != 'i18nblocks') { // Avoid this module's blocks, could be funny :-)
337 if (is_array($module_blocks = module_invoke($module, 'block', 'list'))) {
338 foreach($module_blocks as $number => $block) {
339 $blocklist[$module.':'.$number] = $block['info']."($module)";
340 };
341 }
342 }
343 }
344 $form['info'] = array('#type' => 'textfield', '#title' => t('Block description'),
345 '#default_value' => $metablock->info ? $metablock->info : t('Multilingual block !number', array('!number' => $delta)),
346 '#size' => 40,
347 '#maxlength' => 40
348 );
349 $form['type'] = array('#type' => 'value', '#value' => $metablock->type ? $metablock->type : '');
350 $form['i18nblocks'] = array('#type' => 'fieldset', '#tree' => TRUE, '#title' => t('Select the block to be displayed for each language'));
351
352 foreach($languages as $lang => $langname){
353 $block = isset($metablock->blocks[$lang]) ? $metablock->blocks[$lang] :NULL;
354 $form['i18nblocks'][$lang] = array(
355 '#type' => 'select',
356 '#title' => $langname,
357 '#default_value' => $block ? $block->module.':'.$block->delta : '',
358 '#options' => $blocklist
359 );
360 }
361 // Submit button only for new blocks
362 if($delta) {
363 $form['delete'] = array('#value' => l(t('Delete this block'), 'admin/build/block/i18n/delete/'.$delta));
364 $form['type'] = array(
365 '#type' => 'radios',
366 '#default_value' => $metablock->type,
367 '#options' => array('' => t('Normal translation block')),
368 '#disabled' => TRUE
369 );
370 if (module_exists('nodeasblock')) {
371 $form['type']['#options']['nodeasblock'] = t('Node as block with automatic synchronization');
372 $form['type']['#disabled'] = FALSE;
373 }
374 } else {
375 $form['submit'] = array('#type' => 'submit', '#value' => t('Create block'));
376 }
377 return $form;
378 }
379
380 /**
381 * Add a new metablock and go to settings page
382 */
383 function i18nblocks_admin($op = 'add', $delta = NULL, $confirm = FALSE){
384 if($op == 'add') {
385 $metablock = new StdClass();
386 $metablock->info = t('New multilingual block');
387 return drupal_get_form('i18nblocks_form', $metablock);
388 } elseif($op == 'delete' && $delta && $block = i18nblocks_get_metablock($delta)) {
389 i18nblocks_delete($delta);
390 drupal_set_message("The block has been deleted");
391 drupal_goto('admin/build/block');
392 }
393 }
394
395 function i18nblocks_form_submit($form_id, $form_values){
396 i18nblocks_save($form_values, NULL);
397 return 'admin/build/block';
398 }
399
400 /**
401 * Db layer: for now it stores each block as a variable
402 */
403 function i18nblocks_get_metablock($delta, $getblocks = FALSE){
404 $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));
405 if ($getblocks) {
406 $result = db_query("SELECT * FROM {i18n_blocks_i18n} WHERE bid = '%s'", $delta);
407 $metablock->blocks = array();
408 while ($block = db_fetch_object($result)) {
409 $metablock->blocks[$block->language] = $block;
410 }
411 }
412 return $metablock;
413 }
414
415
416
417 function i18nblocks_delete($delta) {
418 db_query("DELETE FROM {i18n_blocks} WHERE delta = '%s'", $delta);
419 db_query("DELETE FROM {i18n_blocks_i18n} WHERE bid = '%s'", $delta);
420 }