I have a module which uses the field API to create a custom field. So I have an install file implementing hook_field_schema, and module file using some standard hooks like hook_field_info(), hook_field_widget_form(), etc.. I followed the Drupal examples module code pretty closely.

This module works fine for storing the values for one language.

I'm running into a problem that when we try to translate the values to another language, the values in the field_data & field_revision tables seem to be updated rather than new records inserted.

So from the admin's point of view - you save values in the German page, okay.. then you click translate tab and go to edit the English page, and save the values there - okay.. then go back to German and those values are now gone. In the database, there's only one set of values that just keeps being edited, either to be "en" or "de". What am I missing?

Here is part of my module that might help:

/**
 * Implements hook_field_widget_form().
 *
 * hook_widget_form() is where Drupal tells us to create form elements for
 * our field's widget.
 *
 */
function specs_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  global $bspecs;  //this is an array of all the product specs
      
  $widget = $element;
  $widget['#delta'] = $delta;
  
  switch ($instance['widget']['type']) {

    case 'specs_text':
      $widget += array(
        '#type' => 'fieldset',
        '#element_validate' => array('specs_text_validate'),
		'#delta' => $delta,
        '#attached' => array(
          'css' => array(drupal_get_path('module', 'specs') . '/specs.css'),
        ),
      );
	  
	  //create text field for each spec
      foreach ($bspecs as $key => $title) {
        $widget[$key] = array(  
          '#type' => 'textfield',
          '#title' => t($title),
          '#size' => 20,
          '#default_value' => isset($items[$delta][$key]) ? $items[$delta][$key] : '',
          '#attributes' => array('class' => array('specs-entry')),
        );
        // Since Form API doesn't allow a fieldset to be required, we
        // have to require each field element individually.
        if ($instance['required'] == 1) $widget[$key]['#required'] = 1;
      }
	  break;
	}
   
  $element['specs'] = $widget;  
  return $element;
}

/** 
*  Implements hook_field_presave
*/
function specs_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items){
	
    //$items[0] = array();
    if (empty($items)) {
      return;
    }
    //reformat the items array for our data to store into our schema correctly
    $items[0] = $items[0]['specs'];
}

The above code is based somewhat on this example:
https://api.drupal.org/api/examples/field_example!field_example.module/g...

Comments

fprevos2’s picture

I'm having a similar issue I'm not sure if it's the same bug both we both wrap our field in a fieldset. (I'm creating a custom radio/checkbox field with a wrapping fieldset and it won't translate the options.)

espurnes’s picture

Similar issue here.

I have a custom field with text_filed + text_format. It works well in a non multilingual site but with multilingual site the body content (text_format) blow away.

Steps to reproduce:
Custom field with two components: tab-title (text_field) and tab-body (text-format).

  1. Create a node with the custom field in language A. It saves correctly
  2. Translate the content to language B. New content saves correctly. You can see both components.
  3. Go to original language (lang A). tab-titles are there, but tab_bodies are not there. There is an '<' instead of the content.

I guess is a misconfiguration of my custom module. Perhaps in HOOK_field_presave. Any suggestion?

Here you have my module's code:

T_field_format_tabs.install

/**
 * Implements hook_field_schema().
 */
function T_field_format_tabs_field_schema($field) {
  $columns = array(
    'heading' => array(
      'type' => 'varchar',
      'length' => 256,
      'not null' => FALSE
    ),
      'body' => array(
      'type' => 'text',
      'not null' => FALSE
    ),
      'format' => array(
      'type' => 'varchar',
      'length' => 255,
      'not null' => FALSE,
    ),
    );
    return array(
      'columns' => $columns,
      'indexes' => array(
      'format' => array('format'),
    ),
      'foreign keys' => array(
      'format' => array(
      'table' => 'filter_format',
      'columns' => array('format' => 'format'),
    ),
    ),
  );
}

T_field_format_tabs.module

// $Id$

function T_field_format_tabs_field_info() {
  return array(
    'format_tabs_field' => array(
      'label' => t('Format tabs'),
      'description' => t('Field with heading + body'),
      'default_widget' => 'format_tabs_widget',
      'default_formatter' => 'format_tabs_formatter',
    ),
  );
}

function T_field_format_tabs_field_is_empty($item, $field)
{
    if(empty($item['heading']))
        return true;
    if(empty($item['body']))
        return true;
    else
        return false;
}

function T_field_format_tabs_field_formatter_info()
{
    return array(
        'format_tabs_formatter' => array(
            'label' => t('Field to create tabs: title + body'),
            'field types' => array('format_tabs_field'),
        ),

        'simple_text_formatter' => array(
            'label' => t('Displayed continuous'),
            'field types' => array('format_tabs_field'),
        ),
    );
}

function T_field_format_tabs_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display)
{
  $heading = '';
  $body = '';
    //var_dump($items);
  $element = array();
  switch ($display['type']) {
    case 'format_tabs_formatter':
      foreach ($items as $delta => $item) {
        $element['0']['#markup'] ='';
        if($item['heading'])
        {
            $heading .= '<div class="tab-title item-' . $delta . ' title-' . $delta . '">' . check_plain($item['heading']) . '</div>';
        }
        if($item['body'])
        {
            $body .= '<div class="tab-body item-' . $delta . ' body-' . $delta . ' ">' . $item['body'] . '</div>';
        }
      }
      $element['0']['#markup'] .= '<div class="title-tab-container">' . $heading . '</div><div class="body-tab-container">' . $body . '</div>';
    break;
    
    case 'simple_text_formatter':
      foreach ($items as $delta => $item) {
        $element[$delta]['#markup'] ='';
        if($item['heading'])
        {
            $element[$delta]['#markup'] .= '<div class="tab-title continious">' . check_plain($item['heading']) . '</div>' ;
        }
        if($item['body'])
        {
            $element[$delta]['#markup'] .= '<div class="tab-body continious">' . $item['body'] . '</div>';
        }
      }      
    break;
  }
  return $element;
}

/**
 * Implements hook_field_widget_info().
 */
function T_field_format_tabs_field_widget_info()
{
  return array(
    'format_tabs_widget' => array(
      'label' => t('Format tabs widget'),
      'field types' => array('format_tabs_field'),
    ),
  );
}
/**
 * Implements hook_field_widget_form().
 */
function T_field_format_tabs_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element)
{
 
  $element += array(
    '#delta' => $delta,
  );
  $element['heading'] = array();
  $element['body'] = array();
  switch ($instance['widget']['type'])
  {
    case 'format_tabs_widget':
      $element['heading'] = array(
        '#title' => t('Tab heading'),
        '#default_value' => isset($items[$delta]['heading']) ? $items[$delta]['heading'] : '',
        '#type' => 'textfield',
        '#size' => 20,
        '#maxlength' => 255,
        );
      $element['body'] = array(
        '#title' => t('Tab body'),
        '#default_value' => isset($items[$delta]['body']) ? $items[$delta]['body'] : '',
        '#type' => 'text_format',
        '#rows' => 10,
        '#resizable' => TRUE,
        );
    break;
    default:
        break;
  }
  return $element;
}

/**
 * Implements hook_field_presave().
 */
function T_field_format_tabs_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  foreach($items as $i => $item) {
    $item['format'] = $item['body']['format'];
    $item['body'] = $item['body']['value'];
    $items[$i] = $item;
  }
}

I used this page to create the module.