first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
README.txt
==========
Drupal module: i18n_sync (Synchronization)
This module will handle content synchronization accross translations.
The available list of fields to synchronize will include standard node fields and cck fields.
To have aditional fields, add the list in a variable in the settings.php file, like this:
// Available fields for synchronization, for all node types.
$conf['i18n_sync_fields_node'] = array(
'field1' => t('Field 1 name'),
'field2' => t('Field 2 name'),
...
);
// More fields for a specific content type 'nodetype' only.
$conf['i18n_sync_fields_node_nodetype'] = array(
'field3' => t('Field 3 name'),
...
);

View File

@@ -0,0 +1,68 @@
<?php
/**
* @file
* Synchronization API documentation
*/
/**
* Provide information about which fields to synchronize for each entity type.
*
* @see i18n_sync_options()
*
* Field definitions defined on hook_field_info() may contain a synchronization
* callback used for that field to be synchronized. This callback can be set by:
* $field['i18n_sync_callback'] = 'sychcronize_function_callback
*
* This callback will be invoked with the following parameters
* - $entity_type, $entity, $field, $instance, $langcode, $items, $source_entity, $source_langcode);
*
* @see i18n_sync_field_info_alter()
* @see i18n_sync_field_file_sync()
*
* @return array
* Array of fields indexed by field name that will be presented as options
* to be synchronized. Each element is an array with the following keys:
* - 'title', Field title to be displayed
* - 'description', Field description to be displayed.
* - 'field_name', Field name for configurable Fields.
* - 'group', Group for the UI only to display this field.
*
*/
function hook_i18n_sync_options($entity_type, $bundle_name) {
if ($entity_type == 'node') {
return array(
'parent' => array(
'title' => t('Book outline'),
'description' => t('Set the translated parent for each translation if possible.')
),
);
}
}
/**
* Alter information about synchronization options for entities/field
*
* @see hook_i18n_sync_options()
*/
function hook_i18n_sync_options_alter(&$fields, $entity_type, $bundle_name) {
}
/**
* Perform aditional synchronization on entities
*
* @param $entity_type
* @param $translation
* Translated entity.
* @param $translation_language
* Translated entity language code.
* @param $source
* Source entity.
* @param $source_language
* Source entity language code.
* @param $field_names
* Array of field names to synchronize.
*/
function hook_i18n_sync_translation($entity_type, $translation, $translation_language, $source, $source_language, $field_names) {
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* @file
* Feature integration
*/
/**
* Implements hook_features_pipe_node_alter().
*/
function i18n_sync_features_pipe_node_alter(&$pipe, $data, $export) {
if (!empty($data) && module_exists('variable')) {
variable_include();
foreach (variable_list_module('i18n_sync') as $variable) {
if (isset($variable['multiple']) && $variable['multiple'] === 'node_type') {
$children = variable_build($variable['name']);
if (!empty($children['children'])) {
foreach ($children['children'] as $child_variable) {
if (in_array($child_variable['index'], $data)) {
$pipe['variable'][] = $child_variable['name'];
}
}
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
name = Synchronize translations
description = Synchronizes taxonomy and fields accross translations of the same content.
dependencies[] = i18n
dependencies[] = translation
package = Multilingual - Internationalization
core = 7.x
files[] = i18n_sync.module
files[] = i18n_sync.install
files[] = i18n_sync.module.inc
files[] = i18n_sync.node.inc
files[] = i18n_sync.test
; Information added by drupal.org packaging script on 2013-01-13
version = "7.x-1.8"
core = "7.x"
project = "i18n"
datestamp = "1358075001"

View File

@@ -0,0 +1,32 @@
<?php
/**
* @file
* Installation file for i18n_sync module.
*/
/**
* Set module weight.
*
* Make sure this runs after taxonomy, i18n and translation modules
* and ideally after all other modules implementing nodeapi hook.
*/
function i18n_sync_install() {
db_query("UPDATE {system} SET weight = 100 WHERE name = 'i18n_sync' AND type = 'module'");
// If updating from D6, module changed name
if (variable_get('i18n_drupal6_update')) {
i18n_sync_update_7000();
}
}
/*
* Update variable names from Drupal 6
*/
function i18n_sync_update_7000() {
foreach (node_type_get_types() as $type => $info) {
if ($fields = variable_get('i18nsync_nodeapi_' . $type)) {
variable_set('i18n_sync_node_type_' . $type, $fields);
variable_del('i18nsync_nodeapi_' . $type);
}
}
}

View File

@@ -0,0 +1,359 @@
<?php
/**
* @file
* Internationalization (i18n) package. Synchronization of translations
*
* Keeps vocabulary terms in sync for translations.
* This is a per-vocabulary option.
*
* Ref: http://drupal.org/node/115463
*
* Notes:
* This module needs to run after taxonomy, i18n, translation. Check module weight.
*
* @ TODO Test with CCK when possible, api may have changed.
*/
/**
* Global switch to enable / disable syncing and check whether we are synching at the moment
*
* @return boolean
* TRUE if we need to run sync operations. FALSE during syncing so we don't have recursion.
*/
function i18n_sync($status = NULL) {
static $current = TRUE;
if (isset($status)) {
$current = $status;
}
return $current;
}
/**
* Implements hook_help().
*/
function i18n_sync_help($path, $arg) {
switch ($path) {
case 'admin/help#i18n_sync' :
$output = '<p>' . t('This module synchronizes content taxonomy and fields accross translations:') . '</p>';
$output .= '<p>' . t('First you need to select which fields should be synchronized. Then, after a node has been updated, all enabled vocabularies and fields will be synchronized as follows:') . '</p>';
$output .= '<ul>';
$output .= '<li>' . t('All the node fields selected for synchronization will be set to the same value for all translations.') . '</li>';
$output .= '<li>' . t('For multilingual vocabularies, the terms for all translations will be replaced by the translations of the original node terms.') . '</li>';
$output .= '<li>' . t('For other vocabularies, the terms will be just copied over to all the translations.') . '</li>';
$output .= '</ul>';
$output .= '<p><strong>' . t('Note that permissions are not checked for each node. So if someone can edit a node and it is set to synchronize, all the translations will be synchronized anyway.') . '</strong></p>';
$output .= '<p>' . t('To enable synchronization check content type options to select which fields to synchronize for each node type.') . '</p>';
$output .= '<p>' . t('The list of available fields for synchronization will include some standard node fields and all CCK fields. You can add more fields to the list in a configuration variable. See README.txt for how to do it.') . '</p>';
$output .= '<p>' . t('For more information, see the online handbook entry for <a href="@i18n">Internationalization module</a>.', array('@i18n' => 'http://drupal.org/node/133977')) . '</p>';
return $output;
}
}
/**
* Implements hook_hook_info().
*/
function i18n_sync_hook_info() {
$hooks['i18n_sync_options'] = array(
'group' => 'i18n',
);
return $hooks;
}
/**
* Implements hook_field_info_alter()
*/
function i18n_sync_field_info_alter(&$fields) {
foreach (array('file', 'image') as $type) {
if (isset($fields[$type])) {
$fields[$type]['i18n_sync_callback'] = 'i18n_sync_field_file_sync';
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function i18n_sync_form_node_admin_content_alter(&$form, &$form_state) {
if (!empty($form['operation']) && $form['operation']['#value'] == 'delete') {
$form['#submit'] = array_merge(array('i18n_sync_node_delete_submit'), $form['#submit']);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function i18n_sync_form_node_delete_confirm_alter(&$form, &$form_state) {
// Intercept form submission so we can handle uploads, replace callback
$form['#submit'] = array_merge(array('i18n_sync_node_delete_submit'), $form['#submit']);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function i18n_sync_form_node_type_form_alter(&$form, &$form_state) {
if (isset($form['type'])) {
$type = $form['#node_type']->type;
$disabled = !translation_supported_type($type);
$form['i18n_sync'] = array(
'#type' => 'fieldset',
'#title' => t('Synchronize translations'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'additional_settings',
'#attributes' => array(
'class' => array('i18n-node-type-settings-form'),
),
'#description' => t('Select which fields to synchronize for all translations of this content type.'),
'#disabled' => $disabled,
);
$form['i18n_sync']['i18n_sync_node_type'] = array(
'#tree' => TRUE,
);
// Each set provides title and options. We build a big checkboxes control for it to be
// saved as an array.
$current = i18n_sync_node_fields($type);
// Group options, group fields by type.
$groups = array(
'node' => t('Standard node fields'),
'fields' => t('Configurable fields'),
);
$fields = array();
foreach (i18n_sync_node_options($type) as $field => $info) {
$group = isset($info['group']) && isset($groups[$info['group']]) ? $info['group'] : 'node';
$fields[$group][$field] = $info;
}
foreach ($fields as $group => $group_fields) {
$form['i18n_sync']['i18n_sync_node_type']['i18n_sync_group_' . $group] = array(
'#prefix' => '<strong>', '#suffix' => '</strong>',
'#markup' => $groups[$group],
);
foreach ($group_fields as $field => $info) {
$form['i18n_sync']['i18n_sync_node_type'][$field] = array(
'#title' => $info['title'],
'#type' => 'checkbox',
'#default_value' => in_array($field, $current),
'#disabled' => $disabled,
'#description' => isset($info['description']) ? $info['description'] : '',
);
}
}
}
}
/**
* Submit callback for
* - node delete confirm
* - node multiple delete confirm
*/
function i18n_sync_node_delete_submit($form, $form_state) {
if ($form_state['values']['confirm']) {
if (!empty($form_state['values']['nid'])) {
// Single node
i18n_sync_node_delete_prepare($form_state['values']['nid']);
}
elseif (!empty($form_state['values']['nodes'])) {
// Multiple nodes
foreach ($form_state['values']['nodes'] as $nid => $value) {
i18n_sync_node_delete_prepare($nid);
}
}
}
// Then it will go through normal form submission
}
/**
* Prepare node for deletion, work out synchronization issues
*/
function i18n_sync_node_delete_prepare($nid) {
$node = node_load($nid);
// Delete file associations when files are shared with existing translations
// so they are not removed by upload module
if (!empty($node->tnid) && module_exists('upload')) {
$result = db_query('SELECT u.* FROM {upload} u WHERE u.nid = %d AND u.fid IN (SELECT t.fid FROM {upload} t WHERE t.fid = u.fid AND t.nid <> u.nid)', $nid);
while ($up = db_fetch_object($result)) {
db_query("DELETE FROM {upload} WHERE fid = %d AND vid = %d", $up->fid, $up->vid);
}
}
}
/**
* Check whether this node is to be synced
*/
function i18n_sync_node_check($node) {
return translation_supported_type($node->type) && i18n_object_langcode($node) && i18n_sync();
}
/**
* Get node translations if any, excluding the node itself
*
* @param $reset
* Whether to reset the translation_node_get_translations cache.
*/
function i18n_sync_node_get_translations($node, $reset = FALSE) {
if (!empty($node->tnid)) {
if ($reset) {
// Clear the static cache of translation_node_get_translations
$translations_cache = &drupal_static('translation_node_get_translations', array());
unset($translations_cache[$node->tnid]);
}
// Maybe translations are already here
if ($translations = translation_node_get_translations($node->tnid)) {
unset($translations[$node->language]);
return $translations;
}
}
}
/**
* Implements hook_node_insert().
*/
function i18n_sync_node_insert($node) {
// When creating a translation, there are some aditional steps, different from update
if (i18n_sync_node_check($node) && !empty($node->translation_source)) {
i18n_sync_node_update($node);
}
}
/**
* Implements hook_node_update().
*/
function i18n_sync_node_update($node) {
// Let's go with field synchronization.
if (i18n_sync_node_check($node) && !empty($node->tnid) && ($fields = i18n_sync_node_fields($node->type)) && ($translations = i18n_sync_node_get_translations($node, TRUE))) {
module_load_include('node.inc', 'i18n_sync');
i18n_sync_node_translation($node, $translations, $fields, 'update');
}
}
/**
* Implements hook_node_prepare().
*/
function i18n_sync_node_prepare($node) {
// If creating a translation, copy over all the fields to be synchronized.
if (empty($node->nid) && !empty($node->translation_source) && ($sync_fields = i18n_sync_node_fields($node->type))) {
$source = $node->translation_source;
$i18n_options = i18n_sync_node_options($node->type);
// Copy over standard node fields. The rest are handled by field_attach_prepare_translation()
foreach ($sync_fields as $field) {
if (!empty($source->$field) && empty($i18n_options[$field]['field_name'])) {
if ($field == 'uid') {
$node->name = $source->name;
}
elseif ($field == 'created') {
$node->date = format_date($source->created, 'custom', 'Y-m-d H:i:s O');
}
else {
$node->$field = $source->$field;
}
}
}
}
}
/**
* Returns list of fields to synchronize for a given content type.
*
* @param $type
* Node type.
* @param $field
* Optional field name to check whether it is in the list
*/
function i18n_sync_node_fields($type, $field = NULL) {
$fields = variable_get('i18n_sync_node_type_' . $type, array());
return $field ? in_array($field, $fields) : $fields;
}
/**
* Returns list of available fields for given content type.
*
* Fields can also be changed using hook_i18n_sync_fields_alter($fields, $type)
*
* @param $type
* Node type.
*/
function i18n_sync_node_options($type) {
return i18n_sync_options('node', $type);
}
/**
* Returns list of available fields for given entity / bundle.
*
* Fields can also be changed using hook_i18n_sync_options_alter($fields, $type)
*
* @param $entity_type
* Entity type.
* @param
*/
function i18n_sync_options($entity_type, $bundle_name) {
$cache = &drupal_static(__FUNCTION__);
if (!isset($cache[$entity_type][$bundle_name])) {
module_load_include('modules.inc', 'i18n_sync');
$fields = module_invoke_all('i18n_sync_options', $entity_type, $bundle_name);
// Give a chance to modules to change/remove/add their own fields
drupal_alter('i18n_sync_options', $fields, $entity_type, $bundle_name);
$cache[$entity_type][$bundle_name] = $fields;
}
return $cache[$entity_type][$bundle_name];
}
/**
* Synchronize entity field translation
*/
function i18n_sync_field_translation_sync($entity_type, $bundle_name, $entity, $langcode, $source_entity, $source_langcode, $field_name) {
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle_name);
$source_lang = field_language($entity_type, $source_entity, $field_name);
$translation_lang = field_is_translatable($entity_type, $field) ? $entity->language : LANGUAGE_NONE;
if (isset($source_entity->{$field_name}[$source_lang])) {
$items = $source_entity->{$field_name}[$source_lang];
// Determine the function to synchronize this field. If none, just copy over.
$type_info = field_info_field_types($field['type']);
if (isset($type_info['i18n_sync_callback'])) {
$function = $type_info['i18n_sync_callback'];
$function($entity_type, $entity, $field, $instance, $langcode, $items, $source_entity, $source_langcode);
}
$entity->{$field_name}[$translation_lang] = $items;
}
else {
// If source not set, unset translation too
unset($entity->{$field_name}[$translation_lang]);
}
}
/**
* Sync a file or image field (i18n_sync_callback)
*
* - file-id's (fid) are synced
* - order of fid's is synced
* - description, alt, title is kept if already existing, copied otherwise
*/
function i18n_sync_field_file_sync($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_language) {
$field_name = $instance['field_name'];
// Build a copy of the existing files in the translation node
// indexed by fid for easy retrieval in the copy loop below
$existing_files = array();
$field_language = field_language($entity_type, $entity, $field_name, $langcode);
if (isset($entity->{$field_name}[$field_language])) {
foreach ($entity->{$field_name}[$field_language] as $delta => $file) {
$existing_files[$file['fid']] = $file;
}
}
// Start creating the translated copy
foreach ($items as $delta => &$file) {
// keep alt, title, description if they already exist
if (isset($existing_files[$file['fid']])) {
foreach (array('title', 'description', 'alt') as $property) {
if (!empty($existing_files[$file['fid']][$property])) {
$file[$property] = $existing_files[$file['fid']][$property];
}
}
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* @file
* Internationalization (i18n) package. Synchronization of translations
*
* Implements hook_i18n_sync_node_fields() for several core modules.
*/
/**
* Book module. Implements hook_i18n_sync_options().
*/
function book_i18n_sync_options($entity_type, $bundle_name) {
if ($entity_type == 'node') {
return array(
'parent' => array(
'title' => t('Book outline'),
'description' => t('Set the translated parent for each translation if possible.')
),
);
}
}
/**
* Comment module. Implements hook_i18n_sync_options().
*/
function comment_i18n_sync_options($entity_type, $bundle_name) {
if ($entity_type == 'node') {
$fields['comment'] = array('title' => t('Comment settings'));
return $fields;
}
}
/**
* Field module. Implements hook_i18n_sync_options().
*/
function field_i18n_sync_options($entity_type, $bundle_name) {
$sync_fields = array();
if ($bundle_name) {
$instances = field_info_instances($entity_type, $bundle_name);
foreach ($instances as $name => $instance) {
$sync_fields[$name] = array(
'title' => $instance['label'],
'description' => $instance['description'],
'field_name' => $instance['field_name'],
'group' => 'fields',
);
}
}
return $sync_fields;
}
/**
* Node module. Implements hook_i18n_sync_options().
*/
function node_i18n_sync_options($entity_type, $bundle_name) {
if ($entity_type == 'node') {
return array(
'uid' => array('title' => t('Author')),
'status' => array('title' => t('Status')),
'created' => array('title' => t('Post date')),
'promote' => array('title' => t('Promote')),
'moderate' => array('title' => t('Moderate')),
'sticky' => array('title' => t('Sticky')),
'revision' => array('title' => t('Revision'), 'description' => t('Create also new revision for translations')),
);
}
}

View File

@@ -0,0 +1,170 @@
<?php
/**
* @file
* Internationalization (i18n) package. Synchronization of translations
*
* Node synchronization.
*/
/**
* Synchronizes fields for node translation.
*
* There's some specific handling for known fields like:
* - files, for file attachments.
* - iid (CCK node attachments, translations for them will be handled too).
*
* All the rest of the fields will be just copied over.
* The 'revision' field will have the special effect of creating a revision too for the translation.
*
* @param $node
* Source node being edited.
* @param $translations
* Node translations to synchronize, just needs nid property.
* @param $fields
* List of fields to synchronize.
* @param $op
* Node operation (insert|update).
*/
function i18n_sync_node_translation($node, $translations, $field_names, $op) {
$count = 0;
// Disable language selection and synchronization temporarily, enable it again later
$i18n_select = i18n_select(FALSE);
i18n_sync(FALSE);
foreach ($translations as $translation) {
// If translation is the same node, we cannot synchronize with itself
if ($node->nid == $translation->nid) {
continue;
}
// Load full node, we need all data here.
$translation = node_load($translation->nid, NULL, TRUE);
$i18n_options = i18n_sync_node_options($node->type);
// Invoke callback for each field, the default is just copy over
foreach ($field_names as $field) {
if (!empty($i18n_options[$field]['field_name'])) {
i18n_sync_field_translation_sync('node', $node->type, $translation, $translation->language, $node, $node->language, $i18n_options[$field]['field_name']);
}
elseif (isset($node->$field)) {
// Standard node field, just copy over.
$translation->$field = $node->$field;
}
}
// Give a chance to other modules for additional sync
module_invoke_all('i18n_sync_translation', 'node', $translation, $translation->language, $node, $node->language, $field_names);
node_save($translation);
$count++;
}
i18n_sync(TRUE);
i18n_select($i18n_select);
drupal_set_message(format_plural($count, 'One node translation has been synchronized.', 'All @count node translations have been synchronized.'));
}
/**
* Node attachments (CCK) that may have translation.
*/
function i18n_sync_node_translation_attached_node(&$node, &$translation, $field) {
if ($attached = node_load($node->$field)) {
$translation->$field = i18n_sync_node_translation_reference_field($attached, $node->$field, $translation->language);
}
}
/**
* Translating a nodereference field (cck).
*/
function i18n_sync_node_translation_nodereference_field(&$node, &$translation, $field) {
$translated_references = array();
foreach ($node->$field as $reference) {
if ($reference_node = node_load($reference['nid'])) {
$translated_references[] = array(
'nid' => i18n_sync_node_translation_reference_field($reference_node, $reference['nid'], $translation->language)
);
}
}
$translation->$field = $translated_references;
}
/**
* Helper function to which translates reference field. We try to use translations for reference, otherwise fallback.
* Example:
* English A references English B and English C.
* English A and B are translated to German A and B, but English C is not.
* The syncronization from English A to German A would it German B and English C.
*/
function i18n_sync_node_translation_reference_field(&$reference_node, $default_value, $langcode) {
if (isset($reference_node->tnid) && translation_supported_type($reference_node->type)) {
// This content type has translations, find the one.
if (($reference_trans = translation_node_get_translations($reference_node->tnid)) && isset($reference_trans[$langcode])) {
return $reference_trans[$langcode]->nid;
}
else {
// No requested language found, just copy the field.
return $default_value;
}
}
else {
// Content type without language, just copy the field.
return $default_value;
}
}
/**
* Synchronize configurable field
*
* @param $field_info
* Field API field information.
*/
function i18n_sync_node_translation_default_field($node, $translation, $field, $field_info) {
switch ($field_info['field']['type']) {
case 'file':
case 'image':
i18n_sync_node_translation_file_field($node, $translation, $field);
break;
default:
// For fields that don't need special handling, just copy it over if defined.
// Field languages are completely unconsistent, for not to say broken
// both in Drupal core and entity translation. Let's hope this works.
$source_lang = field_language('node', $node, $field);
$translation_lang = field_language('node', $translation, $field);
if (isset($node->{$field}[$source_lang])) {
$translation->{$field}[$translation_lang] = $node->{$field}[$source_lang];
}
break;
}
}
/**
* Sync a file or image field:
* - file-id's (fid) are synced
* - order of fid's is synced
* - description, alt, title is kept if already existing, copied otherwise
*
* @param object $node the node whose changes are to be synced
* @param object $translation a node to which the changes need to be synced
* @param string $field field name
*/
function i18n_sync_node_translation_file_field($node, $translation, $field) {
if (isset($node->{$field}[$node->language])) {
// Build a copy of the existing files in the translation node
// indexed by fid for easy retrieval in the copy loop below
$existing_files = array();
if (isset($translation->{$field}[$translation->language])) {
foreach ($translation->{$field}[$translation->language] as $delta => $file) {
$existing_files[$file['fid']] = $file;
}
}
// Start creating the translated copy
$translated_files = $node->{$field}[$node->language];
foreach ($translated_files as $delta => &$file) {
// keep alt, title, description if they already exist
if (array_key_exists($file['fid'], $existing_files)) {
foreach (array('title', 'description', 'alt') as $property) {
if (!empty($existing_files[$file['fid']][$property])) {
$file[$property] = $existing_files[$file['fid']][$property];
}
}
}
}
$translation->{$field}[$translation->language] = $translated_files;
}
}

View File

@@ -0,0 +1,85 @@
<?php
/**
* @file
* Test field synchronization
*/
class i18nSyncTestCase extends Drupali18nTestCase {
public static function getInfo() {
return array(
'name' => 'Synchronize translations',
'group' => 'Internationalization',
'description' => 'Internationalization Content Synchronization'
);
}
function setUp() {
parent::setUp('translation', 'i18n_string', 'i18n_sync', 'i18n_node', 'i18n_taxonomy');
parent::setUpLanguages();
parent::setUpContentTranslation();
}
function testIi18nSync() {
drupal_static_reset('language_list');
$language_list = language_list();
$language_count = count($language_list);
// Enable tags field for page content type.
$edit = array(
'fields[_add_existing_field][label]' => t('Tags'),
'fields[_add_existing_field][field_name]' => 'field_tags',
'fields[_add_existing_field][widget_type]' => 'taxonomy_autocomplete',
);
$this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
$this->drupalPost(NULL, array(), t('Save settings'));
// Create some content and check selection modes
$this->drupalLogin($this->content_editor);
// variable_set('language_content_type_story', 1);
$source = $this->createNode('page', $this->randomName(), $this->randomString(20), language_default('language'), array('field_tags[und]' => $tag_name = $this->randomName()));
$this->drupalGet('node/' . $source->nid . '/translate');
$translations = $this->createNodeTranslationSet($source);
drupal_static_reset('translation_node_get_translations');
$this->assertEqual(count(translation_node_get_translations($source->tnid)), $language_count, "Created $language_count $source->type translations.");
// Set up fields for synchronization: promoted, field_tags
$this->drupalLogin($this->admin_user);
$edit = array(
'i18n_sync_node_type[sticky]' => 1,
'i18n_sync_node_type[promote]' => 1,
'i18n_sync_node_type[field_tags]' => 1,
);
$this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->drupalGet('admin/structure/types/manage/page');
// Update source fields and check translations have been updated.
$new_title = $this->randomName();
$new_tag = $this->randomName();
$edit = array(
'promote' => 1,
'sticky' => 1,
'field_tags[und]' => $new_tag,
);
$this->drupalPost('node/' . $source->nid . '/edit', $edit, t('Save'));
$terms = taxonomy_get_term_by_name($new_tag);
$term = reset($terms);
// Refresh cache and load translations again.
drupal_static_reset('translation_node_get_translations');
// For some reason the field cache for the node translation gets outdated values.
// This only happens when running unit tests.
// If we don't do this, we miss the field_tags value for the second node.
field_cache_clear();
$translations = translation_node_get_translations($source->tnid);
foreach ($translations as $lang => $node) {
$node = node_load($node->nid, NULL, TRUE);
$this->assertTrue($node->promote && $node->sticky, "Translation for language $lang has been promoted an made sticky.");
$this->assertEqual($node->field_tags['und'][0]['tid'], $term->tid, "Tag for translation $lang has been properly updated.");
$this->drupalGet('node/' . $node->nid);
$this->assertRaw($new_tag, "New tag for translation $lang is showing up.");
}
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* @file
* Variable information
*/
/**
* Implements hook_variable_info().
*/
function i18n_sync_variable_info($options = array()) {
$variables['i18n_sync_node_type_[node_type]'] = array(
'title' => t('Synchronize fields for node type.', array(), $options),
'type' => 'multiple',
'repeat' => array(
'type' => 'array',
),
'group' => 'i18n',
);
return $variables;
}