Problem/Motivation

When creating or editing a new non-node entity from a bundle configured as translatable with Entity Translation, on save the fields values are set to the default value of the language selector configured regardless of the selected language. When editing the entity after the save, the form elements for the translatable fields are empty because the form try to load the values for the entity language. If the value for the fields are entered again, the second save will save them with entity language and future edits will works as expected.

Steps to reproduce error on entity creation.

  • Install Drupal 7 using the standard profile and enabled enable Entity Translation module (enable the Devel module), or use http://simplytest.me/project/entity_translation/7.x-1.x
  • From entity Translation configuration page, enabled translation of the entity type. Configure the Tags vocabulary so that the language selector is not hidden and the language can changed once the entity has been created.
  • From the Languages configuration page, add a language (any will do)
  • Add a translated field to the Tags vocabulary (eg. a taxonomy vocabulary)
  • Create a new term in the Tags vocabulary, select a different language than the default one save it.
  • Edit the newly create term, the translatable field has no value.
  • Bonus: Inspect the term with Devel tab. The translated field as a value, but for the default language, not the entity's language.

Steps to reproduce error on entity update.

  • Install Drupal 7 using the standard profile and enabled enable Entity Translation module (enable the Devel module), or use http://simplytest.me/project/entity_translation/7.x-1.x
  • Enable Entity Translation modules.
  • From entity Translation configuration page, enabled translation of the entity type. Configure the Tags vocabulary so that the language selector is not hidden and the language can changed once the entity has been created.
  • From the Languages configuration page, add a language (any will do)
  • Add a translated field to the Tags vocabulary (eg. a taxonomy vocabulary)
  • Create a new term in the Tags vocabulary, keep the default value for the language selector.
  • Edit the newly created term, change the value of the language selector and of the translatable fields.
  • Edit the newly created term a second time, the translatable field has no value.
  • Bonus: Inspect the term with the Devel tab. The translated field as a value, but for the default language, not the entity's language. The value is the one from the second edit.

It looks like EntityTranslationDefaultHandler::entityFormLanguageWidgetSubmit() should take care of this, but when called its $form is actually the language selector widget.

The method is called from entity_translation_entity_form_language_update() used as #element_validate for the invisible entity_translation_entity_form_language_update element. The arguments of a #element_validate are ($element, &$form_state, $form), but entity_translation_entity_form_language_update() is written as ($form, &$form_state), mistaking the element with the complete form.

Proposed resolution

Fixes entity_translation_entity_form_language_update() to properly use the complete form instead of the language selector element.

Remaining tasks

  • Review the attached patch.
  • Follow up issue in Title: taxonomy terms names and descriptions are always empty after save. No issue with the latest 7.x-1.x-dev branch.

User interface changes

None

API changes

None

Comments

pbuyle’s picture

Version: 7.x-1.5 » 7.x-1.x-dev

Tested on latest dev.

pbuyle’s picture

Project: Fieldable Panels Panes (FPP) » Entity Translation
Component: Code » Base system

After some research, it looks like an Entity Translation issue. The sane issue can re reproduced with Taxonomy Term.

For nodes creation the situation is different. The form elements for field use the default language but during submission locale_field_entity_form_submit() (from node_form_submit_build_node(), via form_execute_handlers('submit', $form, $form_state)) is called to update $form['state']['values'] so form values for the fields will match the node language when entity_form_submit_build_entity() is called.

pbuyle’s picture

Issue summary: View changes

Update description to use taxonomy term.

pbuyle’s picture

Issue summary: View changes

The logic issue is also present when changing the language of an existing entity.

pbuyle’s picture

Title: Translatable fields values are lost on first edit » Fields value are always saved for default language, regardless of the value selected in the language selector.

It looks like EntityTranslationDefaultHandler::entityFormLanguageWidgetSubmit() should take care of this, but when called its $form is actually the language selector widget.

The method is called from entity_translation_entity_form_language_update() used as #element_validate for the invisible entity_translation_entity_form_language_update element. The arguments of a #element_validate are ($element, &$form_state, $form), but entity_translation_entity_form_language_update() is written as ($form, &$form_state), mistaking the element with the complete form.

The attached patch fixes entity_translation_entity_form_language_update() to properly use the complete form instead of the language selector element. This fixes the issue, but it breaks Title integration (at least for name and description of taxonomy terms).

pbuyle’s picture

Status: Active » Needs review
StatusFileSize
new1.63 KB

And here is the patch.

pbuyle’s picture

Issue summary: View changes
pbuyle’s picture

Issue summary: View changes
mraichelson’s picture

Gave this patch a quick run in an existing project install yesterday and found that I was having issues with creating new fieldable panels panes from the page manager UI (via modal window) afterwards. I'll try to set up a cleaner environment to try this in to see if I can track down what was going on a bit more (since it looks like in my case it was something getting twisted up between FPP, WYSIWYG/IMCE and this).

Essentially I could choose to add a pane, find my pane type, fill out the form, but when clicking submit it would keep the Ajax indicator/spinner indefinitely and not complete the process of saving the entity. Based on the log messages and some quick googling it could be an interaction between what's going on here when combined with long text fields that use WYSIWYG/IMCE.

Matroschker’s picture

Hello,

it seems to be the the same issue I have if creating a new book page (book module enabled) or create a new child book page. In the entity translation configuration page I have set "German" as default language, but in every case the form page for the new book page shows "language neutral". There is no effect if changing the value in the form if this is the first save of the book page. If I open the page again and change the language - the second save, saves the right language.

This patch (#6) here based on the DEV (7.x-1.0-beta3+13-dev) does not solve my problem!

Matroschker

alcroito’s picture

Status: Needs review » Needs work

I have the same issue with Fieldable panel panes + Entity Translation + Field collection, and it seems that sending the complete form as an argument is not enough, because certain validation callbacks (for widgets) still use the old LANGUAGE_NONE to access the form structure, but the values have already been moved to the appropriate language.
Specifically I have this problem in field_collection_field_widget_embed_validate().
I am still not sure what is the proper solution.

alcroito’s picture

So I was able to shoehorn Entity Translation + FPP + Field Collection, with some serious dirty code, hacks and duct tape, to actually kinda work, and save field data values with the proper selected Language on Entity creation.

I hardcoded the bit that I needed into the FPP module method EntityTranslationFieldablePanelsPaneHandler::entityFormLanguageWidgetSubmit(). But it should theoretically work by adding the same code into the default EntityTranslationDefaultHandler

/**
   * @see EntityTranslationHandlerInterface::entityFormLanguageWidgetSubmit()
   */
  public function entityFormLanguageWidgetSubmit($form, &$form_state) {
    $this->updateFormLanguage($form_state);
    $form_langcode = $this->getFormLanguage();

    $complete_form = &$form_state['complete form'];

    foreach (field_info_instances($this->entityType, $this->bundle) as $instance) {
      $field_name = $instance['field_name'];
      if (isset($complete_form[$field_name]['#language'])) {
        $field = field_info_field($field_name);
        $previous_langcode = $complete_form[$field_name]['#language'];

        // Handle a possible language change: new language values are inserted,
        // previous ones are deleted.
        if ($field['translatable'] && $previous_langcode != $form_langcode && isset($form_state['values'][$field_name][$previous_langcode])) {
          $form_state['values'][$field_name][$form_langcode] = $form_state['values'][$field_name][$previous_langcode];
          $form_state['values'][$field_name][$previous_langcode] = array();

          // Fix the field data language code, and array parents stored in the
          // $form_state.
          if (isset($form_state['field'][$field_name][$previous_langcode])) {
            // Move lang code.
            $form_state['field'][$field_name][$form_langcode] = $form_state['field'][$field_name][$previous_langcode];
            unset($form_state['field'][$field_name][$previous_langcode]);

            // Fix array parents.
            $field_array_parents = &$form_state['field'][$field_name][$form_langcode]['array_parents'];
            if ($field_array_parents[1] == LANGUAGE_NONE) {
              $field_array_parents[1] = $form_langcode;
            }
          }

          // Fix the forms language codes.
          if (isset($complete_form[$field_name][$previous_langcode])) {
            // Move data to another language code in form.
            $complete_form[$field_name]['#language'] = $form_langcode;
            $complete_form[$field_name][$form_langcode] = $complete_form[$field_name][$previous_langcode];
            unset($complete_form[$field_name][$previous_langcode]);

            // Fix language code first level.
            $complete_form[$field_name][$form_langcode]['#language'] = $form_langcode;

            // Fix the array parents.
            $complete_form[$field_name][$form_langcode]['#parents'] = $complete_form[$field_name][$form_langcode]['#tree'] && $complete_form[$field_name]['#tree'] ? array_merge($complete_form[$field_name]['#parents'], array($form_langcode)) : array($form_langcode);
            // Ensure #array_parents follows the actual form structure.
            $array_parents = $complete_form[$field_name]['#array_parents'];
            $array_parents[] = $form_langcode;
            $complete_form[$field_name][$form_langcode]['#array_parents'] = $array_parents;

            // For each delta item.
            foreach (element_children($complete_form[$field_name][$form_langcode]) as $delta_key) {
              if (isset($complete_form[$field_name][$form_langcode][$delta_key]['#language'])) {
                // Fix second level language code.
                $complete_form[$field_name][$form_langcode][$delta_key]['#language'] = $form_langcode;

                // Fix array parents.
                $complete_form[$field_name][$form_langcode][$delta_key]['#parents'] = $complete_form[$field_name][$form_langcode][$delta_key]['#tree'] && $complete_form[$field_name][$form_langcode]['#tree'] ? array_merge($complete_form[$field_name][$form_langcode]['#parents'], array($delta_key)) : array($delta_key);
                // Ensure #array_parents follows the actual form structure.
                $array_parents = $complete_form[$field_name][$form_langcode]['#array_parents'];
                $array_parents[] = $delta_key;
                $complete_form[$field_name][$form_langcode][$delta_key]['#array_parents'] = $array_parents;
              }
            }
          }
        }
      }
    }
  }

The gist of it, is that when we move the field values from one $lang_code to another inside $form_state, we need to do some cleanup in the $form as well.
For example we need to change all LANGUAGE_NONE's into 'en' in the field container hierarchy, we have to fix the array parents, we have to do the same in the special $form_state['field'] storage.

This is dirty, unmaintainable, but it worked for my test use-cases, so I can only assume that something along these lines should be done to make it work.

pbuyle’s picture

Integration of Entity Translation FPP and Field Collection is not the original issue. The original issue was more general as it affected Entity Translation directly, no integration with complex entity or field module such as FPP and Field Collection.

I suggest moving it the issue with FFP and Field Collection to a dedicated issue.

PS: Shameless plug, if you use ET and FPP, you may be interested in https://www.drupal.org/sandbox/mongolito404/2329745. It's still a sandbox project and any feedback is welcome.

baso’s picture

See #18 in https://www.drupal.org/node/1669494 for a possible workaround.

pbuyle’s picture

Status: Needs work » Needs review

Workaround to what exactly? The original issue is about "Fields value are always saved for default language, regardless of the value selected in the language selector" for core entity types using core field types, so no interaction with complex widgets (eg. WYSIWYG, Field Collection) or complex entity types (eg. FPP, Field Collection). The patch in #6 fixes that specific issue (so not a workaround). So far, the only feedback on the patch have been issue with FPP and/or Field Collection and what looks like an unrelated Book issue (description of the issue does mention a behaviour not observed in the original issue). If there is specific integration issue for ET and third party modules they should, IMHO, be addressed in separated issues.

Commit f4df0047530f56e62f5b9f18bedeb270bd185a2b apply the same fix as the patch in #6 and does fix the original issue. I suggest closing this issue and open separated ones for the, maybe related, issues with Field Collection, FPP and books.

alcroito’s picture

@mongolito I might check out your sandbox on a new project, and leave some feedback.

Indeed your patch has been committed and it seems to work now.
Related to FPPs / FCs, I've tested it one more time, and it seems to be working properly (haven't done extensive testing), with the latest patch in #1344672: Field Collection: Field translation (entity_translation) support..

So I guess the issue can be marked as fixed.

  • 1ef688d committed on 7.x-1.x
    Issue #2301649: Updated CHANGELOG.
    
plach’s picture

Status: Needs review » Closed (duplicate)
Related issues: +#2396653: Fix validation handler for the entity language widget

@mongolito404:

Thanks for the beautiful bug report and sorry it took me so long to get to it. I followed the steps to reproduce the issue and it seems f4df0047 actually fixed it, so marking this as a duplicate.

I updated the change log to credit you too for the solution :)