/[drupal]/contributions/modules/translatable/translatable.node.inc
ViewVC logotype

Contents of /contributions/modules/translatable/translatable.node.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.7 - (show annotations) (download) (as text)
Fri Nov 14 01:11:34 2008 UTC (12 months, 2 weeks ago) by sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +89 -91 lines
File MIME type: text/x-php
#334057 by smk-ka: Code clean-up.
1 <?php
2 // $Id: translatable.node.inc,v 1.6 2008/09/12 17:01:11 smk Exp $
3
4 /**
5 * @file
6 * Provides translation services for nodes.
7 */
8
9 /**
10 * Implementation of hook_menu().
11 */
12 function translatable_node_menu($may_cache) {
13 $items = array();
14
15 if (!$may_cache) {
16 if (arg(0) == 'node' && is_numeric(arg(1))) {
17 $node = node_load(arg(1));
18 if (translatable_content_type_enabled($node->type)) {
19 // Add link to translation overview page to local tasks.
20 $items[] = array(
21 'path' => 'node/'. $node->nid .'/translations',
22 'title' => t('Translations'),
23 'callback' => 'translatable_node_node_page',
24 'access' => user_access('access translatable'),
25 'type' => MENU_LOCAL_TASK,
26 'weight' => 3,
27 );
28 if (arg(2) == 'edit' && !arg(3) && $node->tnid != $node->nid) {
29 // An existing destination url would override our path, pass it
30 // through instead.
31 $destination = isset($_REQUEST['destination']) ? 'destination='. urlencode($_REQUEST['destination']) : NULL;
32 unset($_REQUEST['destination']);
33 drupal_goto('node/'. $node->tnid .'/edit/translation/'. $node->language, $destination);
34 }
35 if (arg(3) == 'translation' && translatable_validate_locale(arg(4))) {
36 $items[] = array(
37 'path' => 'node/'. $node->nid .'/edit/translation/'. arg(4),
38 'title' => t('Edit translation'),
39 'callback' => 'translatable_node_edit_translation',
40 'callback arguments' => array($node->type .'_node_form', $node, arg(4)),
41 'access' => user_access('access translatable') && node_access('update', $node),
42 'type' => MENU_CALLBACK,
43 );
44 }
45 }
46 }
47 }
48 return $items;
49 }
50
51 /**
52 * Menu callback; presents the translation editing form, or redirects to delete confirmation.
53 */
54 function translatable_node_edit_translation($form_id, $node, $lang) {
55 if ($_POST['op'] == t('Delete')) {
56 // Redirect to node/%/delete to make the tabs disappear, passing through
57 // destination.
58 if (isset($_REQUEST['destination'])) {
59 $destination = drupal_get_destination();
60 unset($_REQUEST['destination']);
61 }
62 // @todo This looks wrong (we'd like to delete the translation, not the source).
63 drupal_goto('node/'. $node->nid .'/delete', isset($destination) ? $destination : NULL);
64 }
65
66 $languages = translatable_available_languages();
67 $adminlocale = translatable_set_adminlocale($lang, FALSE);
68 drupal_set_title(t('%language translation of %title', array('%language' => $languages[$adminlocale], '%title' => $node->title)));
69
70 // Check whether we're creating a new translation or editing an existing one.
71 $translation = translatable_find('node', "tnid = $node->nid AND language = '$lang'");
72 if (!$translation) {
73 $node->is_new = TRUE;
74 }
75 else {
76 $node = node_load(key($translation));
77 }
78
79 return translatable_get_form($form_id, $node);
80 }
81
82 /**
83 * Implementation of hook_nodeapi().
84 */
85 function translatable_nodeapi(&$node, $op, $teaser, $page) {
86 if (!translatable_content_type_enabled($node->type)) {
87 return;
88 }
89
90 switch ($op) {
91 case 'load':
92 // Add translation properties to the node.
93 $properties = translatable_findbyid('node', $node->nid);
94 if ($properties) {
95 $extra = array(
96 'language' => $properties['language'],
97 'tnid' => $properties['tnid'],
98 'translatable_node_any' => $properties['any'],
99 );
100 }
101 else {
102 // Legacy node which hasn't been enabled for translation before.
103 // Set language to the default site language.
104 $extra = array(
105 'language' => translatable_get_defaultcontentlocale(),
106 'tnid' => $node->nid,
107 );
108 if (!empty($node->nid)) {
109 $extra['translatable_node_any'] = 0;
110 }
111 }
112 return $extra;
113
114 case 'prepare':
115 if (isset($node->language, $node->tnid)) {
116 translatable_node_update_fields($node);
117 }
118 // If a completely new node is created, we need to assign the language.
119 if (!isset($node->nid, $node->tnid, $node->language)) {
120 $node->language = translatable_get_adminlocale();
121 }
122 break;
123
124 case 'submit':
125 // If tnid of the processed node is equal to the node's nid, this is a source
126 // node. We then fetch and update all translations of this node instead.
127 if ($node->nid && $node->nid == $node->tnid) {
128 $target_nodes = translatable_find('node', "tnid = $node->nid AND nid != $node->nid");
129 foreach (array_keys($target_nodes) as $nid) {
130 $target_node = node_load($nid);
131 translatable_node_update_fields($target_node);
132 node_save($target_node);
133 }
134 }
135 break;
136
137 case 'insert':
138 // For new translations: add node to the global path index, so modules
139 // like pathauto are able to find a menu path for it.
140 if (!empty($node->tnid)) {
141 global $_menu;
142 $node_default_locale = translatable_find('node', 'tnid = '. (int)$node->tnid ." AND language = '". translatable_get_default_locale() ."'");
143 if ($node_default_locale) {
144 $_menu['path index']['node/'. $node->nid] = $_menu['path index']['node/'. key($node_default_locale)];
145 }
146 }
147 // If a completely new node is created, we need to assign the language.
148 if (!isset($node->tnid, $node->language)) {
149 $node->tnid = $node->nid;
150 $node->language = translatable_get_adminlocale();
151 }
152 // Fall through to save translation.
153 case 'update':
154 if (isset($node->language)) {
155 // For new or legacy source nodes: set parent nid to ourself.
156 if (empty($node->tnid)) {
157 $node->tnid = $node->nid;
158 }
159 $translatable_node = array(
160 'nid' => $node->nid,
161 'tnid' => $node->tnid,
162 'language' => $node->language,
163 'any' => (int)$node->translatable_node_any,
164 );
165 translatable_save('node', $translatable_node);
166 }
167 break;
168
169 case 'delete':
170 translatable_delete('node', $node->nid);
171 break;
172 }
173 }
174
175 /**
176 * Implementation of hook_form_alter().
177 *
178 * If the content type is enabled for translation, add a checkbox to allow
179 * displaying the content for all languages.
180 */
181 function translatable_node_form_alter($form_id, &$form) {
182 if (!isset($form['type']) || $form['type']['#value'] .'_node_form' != $form_id || !translatable_content_type_enabled($form['type']['#value'])) {
183 return;
184 }
185
186 // If we are on node/#/edit (a source node), our translation callback has
187 // not been executed, so we need to ensure that the proper translation
188 // language is set.
189 if (arg(3) != 'translation') {
190 translatable_set_adminlocale($form['#node']->language, FALSE);
191 }
192
193 // Enable translation language block.
194 translatable_adminlocale_formselect($form_id, $form);
195
196 // If configured, enable any language by default for new nodes.
197 if (!isset($form['#node']->translatable_node_any)) {
198 $form['#node']->translatable_node_any = variable_get('translatable_default_content_any', FALSE) ? 1 : 0;
199 }
200 $form['translatable_node_any'] = array(
201 '#type' => 'checkbox',
202 '#title' => t('Display this content in any language'),
203 '#default_value' => $form['#node']->translatable_node_any,
204 '#weight' => 0,
205 );
206 // Disable any language property if it is already set for another language.
207 $anynode = translatable_find('node', 'tnid = '. (int)$form['#node']->tnid .' AND nid != '. (int)$form['#node']->nid .' AND any = 1', FALSE);
208 if ($anynode) {
209 $form['translatable_node_any']['#disabled'] = TRUE;
210 $form['translatable_node_any']['#description'] = t('Another translation is currently displayed in any language. <a href="!any">Click here to switch to this translation.</a>', array('!any' => url('node/'. $anynode['nid'] .'/edit')));
211 }
212
213 // Remove certain fields when creating or editing a new node and we're not
214 // in the default locale. Otherwise, contents of these fields would be
215 // stored in the default locale while the node is stored in the current
216 // admin locale.
217 // @todo Taxonomy free tagging
218 if (translatable_get_default_locale() != translatable_get_adminlocale()) {
219 $form['menu']['#access'] = FALSE;
220 }
221
222 // Add parent node id, needed in nodeapi op 'submit'.
223 $form['tnid'] = array(
224 '#type' => 'hidden',
225 '#value' => $form['#node']->tnid,
226 );
227 }
228
229 /**
230 * Callback invoked by translatable_get_form(), right after hook_form_alter().
231 *
232 * Prepopulates a node form with source content values and disables
233 * untranslatable form fields.
234 */
235 function translatable_node_alter_form($form_id, &$form) {
236 if (!isset($form['type']) || $form['type']['#value'] .'_node_form' != $form_id) {
237 return;
238 }
239
240 // Creating a new translation requires more work.
241 if ($form['#node']->is_new) {
242 global $user;
243
244 // Load the source node.
245 $source_node = node_load(arg(1));
246
247 /*
248 // Let 3rd party modules prepare certain form fields that need extra treatment.
249 $_form = array();
250 foreach (module_implements('translatable_prepare_node') as $module) {
251 $function = $module .'_translatable_prepare_node';
252 $result = $function($source_node);
253 if (isset($result) && is_array($result)) {
254 $_form = array_merge($_form, $result);
255 }
256 }
257 */
258
259 // Reset some values to defaults.
260 $source_node->nid = NULL;
261 $form['nid']['#value'] = NULL;
262 $source_node->vid = NULL;
263 $form['vid']['#value'] = NULL;
264 $source_node->uid = $user->uid;
265 $form['uid']['#value'] = $user->uid;
266 $source_node->created = '';
267 $form['created']['#value'] = '';
268 if (isset($source_node->menu)) {
269 $source_node->menu = NULL;
270 }
271 if (isset($source_node->path)) {
272 $source_node->path = NULL;
273 }
274 // Replace the stored node in the form.
275 $form['#node'] = $form['#parameters'][1] = $source_node;
276
277 // Switch language
278 translatable_set_adminlocale(arg(4), FALSE);
279
280 // Generate a clean translation form and merge values from the source node form.
281 $new_node = array(
282 'uid' => $user->uid,
283 'name' => $user->name,
284 'type' => $source_node->type,
285 'tnid' => $source_node->tnid,
286 // @todo Get rid of arg(). Ideally, this would be already set in $form[#node]
287 'language' => arg(4),
288 );
289 $new_form = translatable_retrieve_form($form_id, $new_node);
290 $new_form['#is_new'] = TRUE;
291
292 // Give modules a chance to assign #translatable after all form alterations
293 // are done. This is needed, because modules like CCK fieldgroup perform
294 // excessive alterations.
295 foreach (module_implements('translatable_form_alter') as $module) {
296 $function = $module .'_translatable_form_alter';
297 $function($form_id, $new_form);
298 }
299
300 translatable_filter_form($new_form, $form);
301 $form = $new_form;
302
303 // @doc Why?
304 $form['#node']->translatable_node_any = 0;
305 }
306 else {
307 // Editing a translation: load the source node.
308 $parent_node = node_load($form['#node']->tnid);
309 // Generate the parent editing form and use it to filter current values.
310 $parent_form = translatable_retrieve_form($form_id, $parent_node);
311 // Give modules a chance to assign #translatable after all form alterations
312 // are done. This is needed, because modules like CCK fieldgroup perform
313 // excessive alterations.
314 foreach (module_implements('translatable_form_alter') as $module) {
315 $function = $module .'_translatable_form_alter';
316 $function($form_id, $form);
317 }
318 translatable_filter_form($form, $parent_form);
319 }
320
321 // Set parent node id.
322 $form['tnid'] = array(
323 '#type' => 'hidden',
324 '#value' => $form['#node']->tnid,
325 );
326
327 // Determine and set target language for new translations.
328 if (!isset($form['#node']->language)) {
329 $form['#node']->language = translatable_get_adminlocale();
330 }
331 $form['language'] = array(
332 '#type' => 'hidden',
333 '#default_value' => $form['#node']->language,
334 );
335
336 // Ensure that untranslatable fields are not altered.
337 $form['#submit'] = array('translatable_filter_form_submit' => array($form)) + (array)$form['#submit'];
338 }
339
340 /**
341 * Updates fields in translations of a node.
342 *
343 * If a node translation is saved, all untranslatable values have to be
344 * copied from the source node into the translation node.
345 *
346 * If a source node is saved, all translations of this node have to be
347 * updated to synchronize untranslatable values.
348 *
349 * @param &$node
350 * A node object to process.
351 *
352 * @todo Update to translatable_get_translatable_fields().
353 */
354 function translatable_node_update_fields(&$node) {
355 if ($node->nid == $node->tnid) {
356 return;
357 }
358 // Retrieve a list of all node fields that have to be updated.
359 $update_fields = module_invoke_all('translatable_fields', 'node_form');
360
361 // Load field values from parent node.
362 $source_node = node_load($node->tnid);
363
364 // Update fields in translated node.
365 foreach ($source_node as $field => $value) {
366 if (isset($update_fields[$field])) {
367 $node->$field = $value;
368 }
369 }
370 }
371
372 /**
373 * Implementation of hook_link_alter().
374 */
375 function translatable_link_alter(&$node, &$links) {
376 if ($node->language != translatable_get_locale()) {
377 foreach ($links as $id => $link) {
378 if (isset($links[$id]['query'])) {
379 $links[$id]['query'] = $links[$id]['query'] .'&locale='. $node->language;
380 }
381 else {
382 $links[$id]['query'] = 'locale='. $node->language;
383 }
384 }
385 }
386 }
387
388 /**
389 * Intercepts all the calls for the page.
390 */
391 function translatable_node_node_page() {
392 $args = func_get_args();
393 $op = array_shift($args);
394
395 return translatable_page_translations($op, $args);
396 }
397
398 /**
399 * Get the id of a node that is a translation of a given node in a given language.
400 *
401 * @todo Make this function generic and move it to translatable.database.inc.
402 *
403 * @param $nid
404 * The parent node id.
405 * @param $_locale
406 * The locale to search for.
407 *
408 * @return
409 * The corresponding translated node's nid or FALSE if no translation exists.
410 */
411 function translatable_node_get_localizednid($nid, $locale) {
412 $translatable_node = translatable_findbyid('node', $nid);
413 if ($locale != $translatable_node['language']) {
414 if ($tnid = $translatable_node['tnid']) {
415 $translatable_node = translatable_find('node', 'tnid = '. (int)$tnid ." AND language = '". $locale ."'", FALSE);
416 return $translatable_node['nid'];
417 }
418 }
419 return FALSE;
420 }
421
422 function translatable_node_get_contentlocale($alias) {
423 $path = drupal_get_normal_path($alias);
424 $args = explode('/', $path);
425 $language = '';
426 if ($args[0] == 'node' && is_numeric($args[1])) {
427 $translatable_node = translatable_findbyid('node', $args[1]);
428 $language = $translatable_node['language'];
429 }
430 return $language;
431 }
432
433 function translatable_node_existscontentlocale($alias, $language) {
434 $path = drupal_get_normal_path($alias);
435 $args = explode('/', $path);
436 $nid = '';
437 if ($args[0] == 'node' && is_numeric($args[1])) {
438 $translatable_node = translatable_findbyid('node', $args[1]);
439 if ($tnid = $translatable_node['tnid']) {
440 $translatable_node = translatable_find('node', 'tnid = '. (int)$tnid ." AND language = '". $language ."'", FALSE);
441 $nid = $translatable_node['nid'];
442 }
443 }
444 if ($nid) {
445 return TRUE;
446 }
447 else {
448 return FALSE;
449 }
450 }
451
452 /**
453 * Temporary hard-coded #translatable field properties.
454 */
455 function translatable_translatable_form_alter($form_id, &$form) {
456 // Synchronize general node fields and properties.
457 $form['title']['#translatable'] = TRUE;
458 if (!empty($form['body_filter'])) {
459 $form['body_filter']['#translatable'] = TRUE;
460 }
461 $form['options']['#translatable'] = TRUE;
462
463 // Synchronize menu options for nodes; we default to Localizer (not i18n)
464 // translations currently, so menu items are translated elsewhere. Since
465 // Drupal assumes the default locale as default language for all menu items,
466 // menu items can only be added or edited in the default language.
467 if (translatable_get_default_locale() != translatable_get_adminlocale()) {
468 $form['menu']['#translatable'] = FALSE;
469 }
470
471 // Synchronize comment options from source.
472 if (module_exists('comment')) {
473 $form['comment_settings']['#translatable'] = TRUE;
474 }
475
476 // Disable taxonomy fields; we default to Localizer (not i18n) translations
477 // currently, so taxonomies are translated elsewhere.
478 if (module_exists('taxonomy')) {
479 foreach (element_children($form['taxonomy']) as $key => $vocab) {
480 $form['taxonomy'][$vocab]['#translatable'] = FALSE;
481 }
482 }
483 }
484

  ViewVC Help
Powered by ViewVC 1.1.2