i18n_sync.node.inc 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. /**
  3. * @file
  4. * Internationalization (i18n) package. Synchronization of translations
  5. *
  6. * Node synchronization.
  7. */
  8. /**
  9. * Synchronizes fields for node translation.
  10. *
  11. * There's some specific handling for known fields like:
  12. * - files, for file attachments.
  13. * - iid (CCK node attachments, translations for them will be handled too).
  14. *
  15. * All the rest of the fields will be just copied over.
  16. * The 'revision' field will have the special effect of creating a revision too for the translation.
  17. *
  18. * @param $node
  19. * Source node being edited.
  20. * @param $translations
  21. * Node translations to synchronize, just needs nid property.
  22. * @param $fields
  23. * List of fields to synchronize.
  24. * @param $op
  25. * Node operation (insert|update).
  26. */
  27. function i18n_sync_node_translation($node, $translations, $field_names, $op) {
  28. $count = 0;
  29. // Disable language selection and synchronization temporarily, enable it again later
  30. $i18n_select = i18n_select(FALSE);
  31. i18n_sync(FALSE);
  32. foreach ($translations as $translation) {
  33. // If translation is the same node, we cannot synchronize with itself
  34. if ($node->nid == $translation->nid) {
  35. continue;
  36. }
  37. // Load full node, we need all data here.
  38. $translation = node_load($translation->nid, NULL, TRUE);
  39. $i18n_options = i18n_sync_node_options($node->type);
  40. // Invoke callback for each field, the default is just copy over
  41. foreach ($field_names as $field) {
  42. if (!empty($i18n_options[$field]['field_name'])) {
  43. i18n_sync_field_translation_sync('node', $node->type, $translation, $translation->language, $node, $node->language, $i18n_options[$field]['field_name']);
  44. }
  45. elseif (isset($node->$field)) {
  46. // Standard node field, just copy over.
  47. $translation->$field = $node->$field;
  48. }
  49. }
  50. // Give a chance to other modules for additional sync
  51. module_invoke_all('i18n_sync_translation', 'node', $translation, $translation->language, $node, $node->language, $field_names);
  52. node_save($translation);
  53. $count++;
  54. }
  55. i18n_sync(TRUE);
  56. i18n_select($i18n_select);
  57. drupal_set_message(format_plural($count, 'One node translation has been synchronized.', 'All @count node translations have been synchronized.'));
  58. }
  59. /**
  60. * Node attachments (CCK) that may have translation.
  61. */
  62. function i18n_sync_node_translation_attached_node(&$node, &$translation, $field) {
  63. if ($attached = node_load($node->$field)) {
  64. $translation->$field = i18n_sync_node_translation_reference_field($attached, $node->$field, $translation->language);
  65. }
  66. }
  67. /**
  68. * Translating a nodereference field (cck).
  69. */
  70. function i18n_sync_node_translation_nodereference_field(&$node, &$translation, $field) {
  71. $translated_references = array();
  72. foreach ($node->$field as $reference) {
  73. if ($reference_node = node_load($reference['nid'])) {
  74. $translated_references[] = array(
  75. 'nid' => i18n_sync_node_translation_reference_field($reference_node, $reference['nid'], $translation->language)
  76. );
  77. }
  78. }
  79. $translation->$field = $translated_references;
  80. }
  81. /**
  82. * Helper function to which translates reference field. We try to use translations for reference, otherwise fallback.
  83. * Example:
  84. * English A references English B and English C.
  85. * English A and B are translated to German A and B, but English C is not.
  86. * The syncronization from English A to German A would it German B and English C.
  87. */
  88. function i18n_sync_node_translation_reference_field(&$reference_node, $default_value, $langcode) {
  89. if (isset($reference_node->tnid) && translation_supported_type($reference_node->type)) {
  90. // This content type has translations, find the one.
  91. if (($reference_trans = translation_node_get_translations($reference_node->tnid)) && isset($reference_trans[$langcode])) {
  92. return $reference_trans[$langcode]->nid;
  93. }
  94. else {
  95. // No requested language found, just copy the field.
  96. return $default_value;
  97. }
  98. }
  99. else {
  100. // Content type without language, just copy the field.
  101. return $default_value;
  102. }
  103. }
  104. /**
  105. * Synchronize configurable field
  106. *
  107. * @param $field_info
  108. * Field API field information.
  109. */
  110. function i18n_sync_node_translation_default_field($node, $translation, $field, $field_info) {
  111. switch ($field_info['field']['type']) {
  112. case 'file':
  113. case 'image':
  114. i18n_sync_node_translation_file_field($node, $translation, $field);
  115. break;
  116. default:
  117. // For fields that don't need special handling, just copy it over if defined.
  118. // Field languages are completely unconsistent, for not to say broken
  119. // both in Drupal core and entity translation. Let's hope this works.
  120. $source_lang = field_language('node', $node, $field);
  121. $translation_lang = field_language('node', $translation, $field);
  122. if (isset($node->{$field}[$source_lang])) {
  123. $translation->{$field}[$translation_lang] = $node->{$field}[$source_lang];
  124. }
  125. break;
  126. }
  127. }
  128. /**
  129. * Sync a file or image field:
  130. * - file-id's (fid) are synced
  131. * - order of fid's is synced
  132. * - description, alt, title is kept if already existing, copied otherwise
  133. *
  134. * @param object $node the node whose changes are to be synced
  135. * @param object $translation a node to which the changes need to be synced
  136. * @param string $field field name
  137. */
  138. function i18n_sync_node_translation_file_field($node, $translation, $field) {
  139. if (isset($node->{$field}[$node->language])) {
  140. // Build a copy of the existing files in the translation node
  141. // indexed by fid for easy retrieval in the copy loop below
  142. $existing_files = array();
  143. if (isset($translation->{$field}[$translation->language])) {
  144. foreach ($translation->{$field}[$translation->language] as $delta => $file) {
  145. $existing_files[$file['fid']] = $file;
  146. }
  147. }
  148. // Start creating the translated copy
  149. $translated_files = $node->{$field}[$node->language];
  150. foreach ($translated_files as $delta => &$file) {
  151. // keep alt, title, description if they already exist
  152. if (array_key_exists($file['fid'], $existing_files)) {
  153. foreach (array('title', 'description', 'alt') as $property) {
  154. if (!empty($existing_files[$file['fid']][$property])) {
  155. $file[$property] = $existing_files[$file['fid']][$property];
  156. }
  157. }
  158. }
  159. }
  160. $translation->{$field}[$translation->language] = $translated_files;
  161. }
  162. }