Index: modules/locale/locale.info =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.info,v retrieving revision 1.11 diff -u -p -r1.11 locale.info --- modules/locale/locale.info 8 Jun 2009 09:23:52 -0000 1.11 +++ modules/locale/locale.info 13 Aug 2009 15:22:35 -0000 @@ -6,4 +6,5 @@ version = VERSION core = 7.x files[] = locale.module files[] = locale.install +files[] = locale.field.inc files[] = locale.test Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.248 diff -u -p -r1.248 locale.module --- modules/locale/locale.module 12 Aug 2009 12:36:04 -0000 1.248 +++ modules/locale/locale.module 13 Aug 2009 15:22:36 -0000 @@ -312,6 +312,7 @@ function locale_form_alter(&$form, &$for '#value' => $default->language ); } + $form['#submit'][] = 'locale_field_node_form_submit'; } } Index: modules/entity_translation/entity_translation.module =================================================================== RCS file: modules/entity_translation/entity_translation.info diff -N modules/entity_translation/entity_translation.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/entity_translation/entity_translation.info 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,9 @@ +; $Id$ +name = Entity translation API +description = Expose an API to allow fieldable entities to be translated into different languages. +dependencies[] = locale +package = Core +version = VERSION +core = 7.x +files[] = entity_translation.module +files[] = entity_translation.install Index: modules/entity_translation/entity_translation.module =================================================================== RCS file: modules/entity_translation/entity_translation.module diff -N modules/entity_translation/entity_translation.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/entity_translation/entity_translation.module 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,118 @@ +fields('et') + ->condition('etid', $etid) + ->condition('entity_id', $id) + ->orderBy('created') + ->execute(); + + $translations = array(); + foreach ($results as $row) { + $translations[$row->language] = $row; + // Only the original translation has empty source. + if (empty($row->source)) { + $original = $row->language; + } + } + + return (object) array('original' => isset($original) ? $original : NULL, 'data' => $translations); +} + +function entity_translation_save_translation($obj_type, $object, $translation) { + if (isset($translation['source']) && $translation['language'] == $translation['source']) { + throw new Exception('Invalid translation language'); + } + + // Save field translations. + field_attach_update($obj_type, $object); + + $obj_info = field_info_fieldable_types($obj_type); + $translations = isset($object->{$obj_info['translations key']}) ? $object->{$obj_info['translations key']} : NULL; + $langcode = $translation['language']; + + if (isset($translations->data[$langcode])) { + // unset($translation['source']); + $translation = array_merge((array) $translations->data[$langcode], $translation); + $translation['changed'] = REQUEST_TIME; + _entity_translation_write_translation($obj_type, $object, $translation); + } + else { + _entity_translation_write_translation($obj_type, $object, $translation, TRUE); + } +} + +function entity_translation_delete_translation($obj_type, $object, $langcode = NULL) { + $etid = _field_sql_storage_etid($obj_type); + list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object); + + $query = db_delete('entity_translation') + ->condition('etid', $etid) + ->condition('entity_id', $id); + + if (!empty($langcode)) { + // Remove field translations. + foreach (field_info_instances($bundle) as $instance) { + $field_name = $instance['field_name']; + $field = field_info_field($field_name); + if ($field['translatable']) { + $object->{$field_name}[$langcode] = array(); + } + } + field_attach_update($obj_type, $object); + + $query->condition('language', $langcode); + } + + return $query->execute(); +} + +function entity_translation_change_original_language($obj_type, $object, $langcode) { + $etid = _field_sql_storage_etid($obj_type); + list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object); + $obj_info = field_info_fieldable_types($obj_type); + $translations = isset($object->{$obj_info['translations key']}) ? $object->{$obj_info['translations key']} : NULL; + return db_update('entity_translation') + ->fields(array('language' => $langcode)) + ->condition('etid', $etid) + ->condition('entity_id', $id) + ->condition('language', $translations->original) + ->execute(); +} + +function entity_translation_flag_outdated($obj_type, $object) { + $etid = _field_sql_storage_etid($obj_type); + list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object); + $obj_info = field_info_fieldable_types($obj_type); + $translations = isset($object->{$obj_info['translations key']}) ? $object->{$obj_info['translations key']} : NULL; + return db_update('entity_translation') + ->fields(array('translate' => TRUE)) + ->condition('etid', $etid) + ->condition('entity_id', $id) + ->condition('language', $translations->original, '<>') + ->execute(); +} + +function _entity_translation_write_translation($obj_type, $object, $translation, $create = FALSE) { + global $user; + list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object); + + $translation = $translation + array( + 'etid' => _field_sql_storage_etid($obj_type), + 'entity_id' => $id, + 'source' => '', + 'uid' => $user->uid, + 'translate' => FALSE, + 'status' => FALSE, + 'created' => REQUEST_TIME, + 'changed' => REQUEST_TIME, + ); + + $primary_keys = $create ? NULL : array('etid', 'entity_id', 'language'); + return drupal_write_record('entity_translation', $translation, $primary_keys); +} Index: modules/translation_field/translation_field.module =================================================================== RCS file: modules/translation_field/translation_field.module diff -N modules/translation_field/translation_field.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/translation_field/translation_field.module 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,410 @@ + 'Translate fields', + 'page callback' => 'translation_field_node_overview', + 'page arguments' => array(1), + 'access callback' => '_translation_field_tab_access', + 'access arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + 'weight' => 2, + ); + $items['node/%node/field-translation/overview'] = array( + 'title' => 'Overview', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => 0, + ); + $items['node/%node/field-translation/translate/%translation_field_language/%translation_field_language'] = array( + 'title' => 'Translate', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('translation_field_translation_form', 1, 4, 5), + 'access callback' => '_translation_field_tab_access', + 'access arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + 'weight' => 1, + ); + $items['node/%node/field-translation/delete/%translation_field_language/%translation_field_language'] = array( + 'title' => 'Delete', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('translation_field_translation_delete_confirm', 1, 4, 5), + 'access callback' => '_translation_field_tab_access', + 'access arguments' => array(1), + ); + return $items; +} + +function translation_field_language_load($langcode) { + $enabled_languages = field_multilingual_content_languages(); + return in_array($langcode, $enabled_languages) ? $langcode : FALSE; +} + +function translation_field_fieldable_info_alter(&$info) { + $info['node']['translation_handlers']['translation_field'] = TRUE; + $info['node']['translations key'] = 'translations'; +} + +function translation_field_permission() { + return array( + 'translate node fields' => array( + 'title' => t('Translate node fields'), + 'description' => t('Translate website node field content.'), + ), + ); +} + +function translation_field_form_alter(&$form, $form_state) { + if ($form['#id'] == 'node-form' && isset($form['#node']->translations)) { + $translations = $form['#node']->translations; + + // We need $node->translations on node save. + $form['translations'] = array( + '#type' => 'value', + '#value' => $translations, + ); + + $form['previous_language'] = array( + '#type' => 'value', + '#value' => $form['#node']->language, + ); + + // Remove existing translation language codes from the node language selector. + foreach ($translations->data as $langcode => $translation) { + if ($langcode != $translations->original) { + unset($form['language']['#options'][$langcode]); + } + } + + $form['field_translation'] = array( + '#type' => 'fieldset', + '#title' => t('Field translation'), + '#collapsible' => TRUE, + '#group' => 'additional_settings', + '#tree' => TRUE, + '#weight' => 100, + '#attached_js' => array(drupal_get_path('module', 'translation_field') . '/translation-field-node-form.js'), + ); + $form['field_translation']['retranslate'] = array( + '#type' => 'checkbox', + '#title' => t('Flag translations as outdated'), + '#default_value' => 0, + '#description' => t('If you made a significant change, which means translations should be updated, you can flag all translations of this post as outdated. This will not change any other property of those posts, like whether they are published or not.'), + ); + } +} + +function translation_field_translation_form($form_state, $node, $source, $langcode) { + $languages = language_list('language', LANGUAGE_TYPE_CONTENT); + drupal_set_title($node->title . ' [' . t('!language translation', array('!language' => t($languages[$langcode]->name))) . ']'); + + $form = array( + '#node' => $node, + '#source' => $source, + '#language' => $langcode, + ); + + $form['translation'] = array( + '#type' => 'fieldset', + '#title' => t('Translation settings'), + '#access' => user_access('translate content'), + '#collapsible' => TRUE, + '#collapsed' => !$node->translate, + '#tree' => TRUE, + '#weight' => -4, + ); + $form['translation']['status'] = array( + '#type' => 'checkbox', + '#title' => t('This translation is published'), + '#default_value' => isset($node->translations->data[$langcode]) && $node->translations->data[$langcode]->status, + '#description' => t('When this option is unchecked, this translation will not be visible for non-administrators.'), + ); + $form['translation']['translate'] = array( + '#type' => 'checkbox', + '#title' => t('This translation needs to be updated'), + '#default_value' => $translate = isset($node->translations->data[$langcode]) && $node->translations->data[$langcode]->translate, + '#description' => t('When this option is checked, this translation needs to be updated because the source post has changed. Uncheck when the translation is up to date again.'), + '#disabled' => !$translate, + ); + + // If we are creating a new translation we need to retrieve form elements + // populated with the source language values. + $new_translation = !isset($node->translations->data[$langcode]); + $field_view = field_attach_view('node', $node, 'full', $langcode); + $source_form = array(); + if ($new_translation) { + $source_form_state = $form_state; + field_attach_form('node', $node, $source_form, $source_form_state, $source); + } + field_attach_form('node', $node, $form, $form_state, $langcode); + list(, , $bundle) = field_attach_extract_ids('node', $node); + + foreach (field_info_instances($bundle) as $instance) { + $field_name = $instance['field_name']; + $field = field_info_field($field_name); + // If a field is not translatable it should not be editable from the + // translation form, yet it could be useful to display its value. + if (!$field['translatable']) { + $form[$field_name] = array( + '#markup' => drupal_render($field_view[$field_name]), + // Place the element where it would appear if displayed. + '#weight' => $instance['weight'], + ); + } + // If we are creating a new translation we have to change the form item + // language information from source to target language, this way the + // user can find the form items already populated with the source values + // while the field form element holds the correct language information. + else if ($new_translation && !isset($node->{$field_name}[$langcode]) && isset($source_form[$field_name][$source])) { + $form[$field_name][$langcode] = $source_form[$field_name][$source]; + } + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save translation'), + '#submit' => array('translation_field_translation_form_save_submit'), + ); + + if (!$new_translation) { + $form['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete translation'), + '#submit' => array('translation_field_translation_form_delete_submit'), + ); + } + + return $form; +} + +function translation_field_translation_form_save_submit($form, &$form_state) { + $node = (object) array_merge((array) $form['#node'], $form_state['values']); + $translation = array( + 'translate' => $node->translation['translate'], + 'status' => $node->translation['status'], + 'language' => $form['#language'], + 'source' => $form['#source'], + ); + entity_translation_save_translation('node', $node, $translation, $node->translations); + $form_state['redirect'] = 'node/' . $node->nid . '/field-translation'; +} + +function translation_field_translation_form_delete_submit($form, &$form_state) { + $form_state['redirect'] = 'node/' . $form['#node']->nid . '/field-translation/delete/' . $form['#source'] . '/' . $form['#language']; +} + +function translation_field_translation_delete_confirm($form_state, $node, $source, $langcode) { + $form['#node'] = $node; + $form['#source'] = $source; + $form['#language'] = $langcode; + $languages = language_list('language', LANGUAGE_TYPE_CONTENT); + return confirm_form($form, + t('Are you sure you want to delete the @language translation of %title?', + array('@language' => $languages[$langcode]->name, '%title' => $node->title)), + 'node/' . $node->nid . '/field-translation/translate/' . $source . '/' . $langcode, + t('This action cannot be undone.'), + t('Delete'), + t('Cancel') + ); +} + +function translation_field_translation_delete_confirm_submit($form, &$form_state) { + entity_translation_delete_translation('node', $form['#node'], $form['#language']); + if (isset($_SESSION['translation_field_source_language']) && $form['#language'] == $_SESSION['translation_field_source_language']) { + unset($_SESSION['translation_field_source_language']); + } + $form_state['redirect'] = 'node/' . $form['#node']->nid . '/field-translation'; +} + +function translation_field_node_load(&$nodes, $types) { + // TODO: entity_translation_get_all (multiple), translation_supported_type($type) + foreach ($nodes as $nid => $node) { + $nodes[$nid]->translations = entity_translation_get_all('node', $node); + } +} + +function translation_field_node_insert($node) { + _translation_field_create_source_translation($node); +} + +function translation_field_node_update($node) { + // Only create a translation on edit if the translation set is empty: + // the node might have been created with language set to "language neutral". + if (empty($node->translations->data)) { + _translation_field_create_source_translation($node); + } + elseif (!empty($node->language)) { + if ($node->previous_language != $node->language) { + entity_translation_change_original_language('node', $node, $node->language); + } + if (!empty($node->field_translation['retranslate'])) { + entity_translation_flag_outdated('node', $node); + } + } +} + +function translation_field_node_delete($node) { + entity_translation_delete_translation('node', $node); +} + +function _translation_field_create_source_translation($node) { + if (!empty($node->language)) { + $translation = array( + 'language' => $node->language, + 'status' => $node->status, + ); + entity_translation_save_translation('node', $node, $translation); + } +} + +function translation_field_node_overview($node) { + // Initialize translations if they are empty. + if (empty($node->translations->original)) { + _translation_field_create_source_translation($node); + $node->translations = entity_translation_get_all('node', $node); + } + + $translations = $node->translations->data; + $header = array(t('Language'), t('Source language'), t('Title'), t('Status'), t('Operations')); + $languages = language_list('language', LANGUAGE_TYPE_CONTENT); + $source = isset($_SESSION['translation_field_source_language']) ? $_SESSION['translation_field_source_language'] : $node->translations->original; + $source_selector = 0; + + foreach ($languages as $language) { + $options = array(); + $language_name = $language->name; + $langcode = $language->language; + if (isset($translations[$langcode])) { + $source_selector++; + // Existing translation in the translation set: display status. + $is_original = $langcode == $node->translations->original; + $translation = $translations[$langcode]; + $path = 'node/' . $node->nid . '/field-translation/translate/' . $node->translations->original . '/' . $langcode; + // TODO: title as translatable field and content language negotiation + $title = $is_original ? $node->title : t('view'); + $title = l($title, 'node/'. $node->nid, array('query' => 'content_language=' . $langcode)); + if (node_access('update', $node)) { + $options[] = l(t('edit'), $is_original ? 'node/'. $node->nid . '/edit' : $path); + } + $status = $translation->status ? t('Published') : t('Not published'); + $status .= $translation->translate ? ' - ' . t('outdated') . '' : ''; + if ($is_original) { + $language_name = t('@language_name ', array('@language_name' => $language_name)); + $source_name = t('(original content)'); + } + else { + $source_name = $languages[$translation->source]->name; + } + } + else { + // No such translation in the set yet: help user to create it. + $title = t('n/a'); + $path = 'node/' . $node->nid . '/field-translation/translate/' . $source . '/' . $langcode; + if (node_access('create', $node) && $source != $langcode) { + $options[] = l(t('add translation'), $path); + } + $status = t('Not translated'); + $source_name = '' . $languages[$source]->name . ''; + } + $rows[] = array($language_name, $source_name, $title, $status, implode(" | ", $options)); + } + + drupal_set_title(t('Translations of %title', array('%title' => $node->title)), PASS_THROUGH); + + $build['translation_node_overview'] = array(); + // Show the source language selector only if there are missing translations + // and there is more than one language available as source. + if ($source_selector > 1 && $source_selector < count($languages)) { + $build['translation_node_overview']['translation_settings_form'] = drupal_get_form('translation_field_translation_settings_form', $node, $source); + } + $build['translation_node_overview']['translation_table'] = array( + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + ); + + return $build; +} + +function translation_field_translation_settings_form($form_state, $node, $source) { + $form = array( + 'translation_settings' => array( + '#type' => 'fieldset', + '#title' => t('Translation creation settings'), + '#collapsible' => TRUE, + '#collapsed' => !isset($_GET['translation_settings']), + '#tree' => TRUE, + '#attached_js' => array(drupal_get_path('module', 'translation_field') . '/translation-field-overview.js'), + 'source_language' => array( + '#type' => 'select', + '#title' => t('Source language'), + '#default_value' => $source, + '#options' => array(), + ), + 'submit' => array( + '#type' => 'submit', + '#value' => t('Submit'), + ), + ), + ); + + foreach (language_list('language', LANGUAGE_TYPE_CONTENT) as $language) { + if (isset($node->translations->data[$language->language])) { + $form['translation_settings']['source_language']['#options'][$language->language] = t($language->name); + } + } + + return $form; +} + +function translation_field_translation_settings_form_submit($form, &$form_state) { + $langcode = $form_state['values']['translation_settings']['source_language']; + $_SESSION['translation_field_source_language'] = field_multilingual_valid_language($langcode); + $form_state['redirect'] = array('path' => $_GET['q'], 'query' => 'translation_settings'); + $languages = language_list(); + drupal_set_message(t('Source translation set to: %language', array('%language' => $languages[$langcode]->name))); +} + +function translation_field_content_language_alter(&$content_language) { + if (isset($_GET['content_language'])) { + $content_language = field_multilingual_valid_language($_GET['content_language']); + } +} + +function translation_field_node_view($node, $build_mode) { + if (!empty($node->translations)) { + $translations = $node->translations->data; + $languages = language_list('language', LANGUAGE_TYPE_CONTENT); + global $language; + foreach ($languages as $langcode => $target_language) { + // TODO: && langcode != + if (isset($translations[$langcode]) ) { + $links["node_translation_$langcode"] = array( + 'title' => $target_language->native, + 'href' => 'node/' . $node->nid, + 'language' => $language, + // TODO: 'title' => $translations[$langcode]->title + 'attributes' => array('class' => 'translation-link'), + 'query' => 'content_language=' . $langcode, + ); + $node->content['links']['translation'] = array( + '#theme' => 'links', + '#links' => $links, + '#attributes' => array('class' => 'links inline'), + ); + } + } + } +} + +function _translation_field_tab_access($node) { + return !empty($node->language) && user_access('translate node fields'); +} Index: modules/translation_field/translation-field-node-form.js =================================================================== RCS file: modules/translation_field/translation-field-node-form.js diff -N modules/translation_field/translation-field-node-form.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/translation_field/translation-field-node-form.js 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,15 @@ +// $Id$ + +(function ($) { + +Drupal.behaviors.translationFieldFieldsetSummaries = { + attach: function (context) { + $('fieldset#edit-field-translation', context).setSummary(function (context) { + return $('#edit-field-translation-retranslate', context).is(':checked') ? + Drupal.t('Flag translations as outdated') : + Drupal.t('Don\'t flag translations as outdated'); + }); + } +}; + +})(jQuery); Index: modules/locale/locale.field.inc =================================================================== RCS file: modules/locale/locale.field.inc diff -N modules/locale/locale.field.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/locale/locale.field.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,49 @@ +language) ? FIELD_LANGUAGE_NONE : $node->language; + list(, , $bundle) = field_attach_extract_ids('node', $node); + foreach (field_info_instances($bundle) as $instance) { + $field_name = $instance['field_name']; + $field = field_info_field($field_name); + $previous_language = $form[$field_name]['#language']; + // Handle a possible language change: previous language values are deleted, new ones are inserted. + if ($field['translatable'] && $previous_language != $selected_language) { + $form_state['values'][$field_name][$selected_language] = $node->{$field_name}[$previous_language]; + if ($reset_previous) { + $form_state['values'][$field_name][$previous_language] = array(); + } + } + } +} + +// TODO: (hook disabled) implement language negotiation and fallback +function __locale_field_attach_form($obj_type, $object, &$form, &$form_state) { + if (field_multilingual_check_translation_handler($obj_type, 'locale')) { + list(, , $bundle) = field_attach_extract_ids($obj_type, $object); + foreach (field_info_instances($bundle) as $instance) { + $field_name = $instance['field_name']; + $field = field_info_field($field_name); + $field_language = $form[$field_name]['#language']; + if (empty($form[$field_name][$field_language][0]['#default_value']) && isset($object->{$field_name}[FIELD_LANGUAGE_NONE])) { + unset($form[$field_name]); + $items = $object->{$field_name}[FIELD_LANGUAGE_NONE]; + $form += field_default_form($obj_type, $object, $field, $instance, FIELD_LANGUAGE_NONE, $items, $form, $form_state); + } + } + } +} Index: modules/translation_field/translation-field-overview.js =================================================================== RCS file: modules/translation_field/translation-field-overview.js diff -N modules/translation_field/translation-field-overview.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/translation_field/translation-field-overview.js 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,17 @@ +// $Id$ + +(function ($) { + +Drupal.behaviors.translationFieldOverview = { + attach: function (context) { + $('span.source-language', context).each(function() { + var item = $(this); + item.replaceWith('' + item.text() + ''); + }); + $('a.source-language', context).click(function() { + Drupal.toggleFieldset($('fieldset#edit-translation-settings.collapsed')); + }); + } +}; + +})(jQuery); Index: modules/entity_translation/entity_translation.install =================================================================== RCS file: modules/entity_translation/entity_translation.install diff -N modules/entity_translation/entity_translation.install --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/entity_translation/entity_translation.install 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,87 @@ + 'Table to track entity translations', + 'fields' => array( + 'etid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The entity type id this translation relates to', + ), + 'entity_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The entity id this translation relates to', + ), + // TODO: Consider an integer field for 'language'. + 'language' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The target language for this translation.', + ), + 'source' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The source language from which this translation was created.', + ), + 'uid' => array( + 'description' => 'The author of this translation.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'status' => array( + 'description' => 'Boolean indicating whether the translation is published (visible to non-administrators).', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 1, + ), + 'translate' => array( + 'description' => 'A boolean indicating whether this translation needs to be updated.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'created' => array( + 'description' => 'The Unix timestamp when the translation was created.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'changed' => array( + 'description' => 'The Unix timestamp when the translation was most recently saved.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('etid', 'entity_id', 'language'), + ); + + return $schema; +} Index: modules/translation_field/translation_field.info =================================================================== RCS file: modules/translation_field/translation_field.info diff -N modules/translation_field/translation_field.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/translation_field/translation_field.info 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,8 @@ +; $Id: translation.info,v 1.5 2009/06/08 09:23:54 dries Exp $ +name = Field-based content translation +description = Allows node fields to be translated into different languages. +dependencies[] = entity_translation +package = Core +version = VERSION +core = 7.x +files[] = translation_field.module