After initial node_clone support we finally reached the need of i18n translation support.

If we're adding a node translation using i18n, the components won't be copied in current -dev. Only the base form information is there.

I18n is using the node data as a prepopulation when adding node translation. However on node save only the base form gets saved. Al components are missing then.

We might use nodeapi op=insert to copy components from translation source.

webform_nodeapi(...) {
  if($op=='insert') {
    if (!empty($node->translation_source)) {
      if ($node->translation_source->tnid) {
        $tnid = $node->translation_source->tnid;
        # add components to translated form here from tnid
      }
    }
  }
}

We might sync component updates on forms later if they're part of the same tnid.
Also results could be aggregated on the tnid instead of nid for the results' display.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

miro_dietiker’s picture

Well there's some general i18n support task which i didn't realize before.
#245424: Make Webform multilingual (i18n) aware through contributed modules

Still leaving this issue here for the moment.

miro_dietiker’s picture

Further notes about how to solve this.. not tested yet.

Note this is support for content translation (translation.module) from core. I18n only improves the situation (and is state of the art), but in general this sequence is directly core support.

function webform_node_insert($node) {
...
  // add components from translation source
  if (!empty($node->translation_source)) {
    if ($node->translation_source->tnid) {
      $node_src = node_load($node->translation_source->tnid);
      // saving everything that is not in the primary node form here.
      if (isset($node_src->webform['components']) && !empty($node_src->webform['components'])) {
        foreach ($node_src->webform['components'] as $cid => $component) {
          $component['nid'] = $node->nid; // Required for translation.module.
          webform_component_insert($component);
        }
      }
    }
  }
...
}

I think this would work pretty well. Any objections to this approach?

miro_dietiker’s picture

Title: Add webform components on i18n translation duplication » Add webform components on translation.module duplication
Status: Active » Needs review
FileSize
1.07 KB

Providing patch.
Tested and works. Please review and include in 3.x-dev.
Changing title to make it match core translation.module. However this is also core base for i18n.

Anonymous’s picture

I add this patch to latest version (beta5) but the problem I have is not solved : http://drupal.org/node/245424#comment-2906920

Maybe this is not the subject of this ticket after all.

quicksketch’s picture

This was never necessary in the 2.x branch (was it?), I'm not sure why it would be required in 3.x.

miro_dietiker’s picture

quicksketch, this is a new feature. There was no translation support in 2.x.

Checked plain installation of drupal (node+translation.module) with i18n and webform in 2.9 (current revisions):
You need to do the following to check the situation:
- Enable "Content translation"
- Add at least 2 languages
- Switch Content type webform to Workflow "Multilanguage enabled, with translation"
- Add a webform with components
After adding a node translation, components are lost.

This is because the components are not part of $form and there's no invocation to apply the components / elements from origin $node (translation source) to the final translated node. Indeed we're missing a hook here, but i'm not yet sure what would be the best name / definition of it.

For the current 3.x dev webform we have the same situation.

This patch adds the new feature of adding elements to the new $node which are not in $form as a first step.
Further modifications of the elements are possible, nothing will be synced, on further steps users can modify fields freely.
There's a lot of additional work for advanced translation support, see #245424: Make Webform multilingual (i18n) aware through contributed modules
But it's already nice to see them available as a first step.

quicksketch’s picture

Thanks for the explanation miro_dietiker, I had assumed that it was already working in 2.x since this had never been explicitly brought up before.

Regarding the patch, it seems to be duplicating a lot of unnecessary work. It seems like we should modify the component comparison a few lines lower and simply make it insert if $node->translation_source is set. Otherwise we're going to end up duplicate both the component insertion and the e-mail insertion (which is the current topic of #768960: Webform nodes no longer can be cloned).

Checking this out, we already have this code in place:

  // Check if there is an existing entry at all for this node.
  $exists = db_result(db_query('SELECT nid FROM {webform} WHERE nid = %d', $node->nid));

  // If a webform row doesn't even exist, we can assume it needs to be inserted.
  if (!$exists) {
    webform_node_insert($node);
    return;
  }

Since a webform entry won't exist for the new translation, doesn't this already have the same effect as your patch?

yhager’s picture

Subscribing

ehudash’s picture

subscribing

miro_dietiker’s picture

To follow this whole process i'm missing some details.
I don't understand why "webform_node_update" on update currently needs to check for existence of $node->nid and switch to insert if not. Sounds like some edge case where invocation was a bug or weight of node resaves (insert + update) within a single cycle leads to a twisted sequence (update+insert) invocation...
So it's a workaround?

You're quoting the _update function. Note that we're talking about the insert case.

Note that the only nodeapi things that happen are: validate, presave, save - leading to webform_node_insert with present translation_source. The $form['webform']['component'] part is empty for all cases.

Already on the node add form (reached from "add translation") we're encountering a webform array with empty components.

Note that cloning a node is somewhat different from making translation duplicates. Regular clones are always separated, while translation dupes have some entanglement (which not yet happens here on a component basis) in most cases...

quicksketch, any further inputs about your ideas?

quicksketch’s picture

Sounds like some edge case where invocation was a bug or weight of node resaves (insert + update) within a single cycle leads to a twisted sequence (update+insert) invocation...
So it's a workaround?

This case is to handle when a node type was not a webform originally, but then because a webform node type later by the administrator adding another type from admin/settings/webform.

You're quoting the _update function. Note that we're talking about the insert case.

Ah right. So with inserting then, we already have this code:

  // Insert the components into the database. Used with clone.module.
  if (isset($node->webform['components']) && !empty($node->webform['components'])) {
    foreach ($node->webform['components'] as $cid => $component) {
      $component['nid'] = $node->nid; // Required for clone.module.
      webform_component_insert($component);
    }
  }

Which seems to indicate we should just be able to do this:

if ($node->translation_source) {
  $source_node = node_load($node->translation_source->tnid)
  $node['webform'] = $source_node['webform'];
}

And have it re-insert everything as necessary.

miro_dietiker’s picture

OK, understood.

Attached patch provides the tested result when following your example.
Swapping array and object style, switching tnid to nid (since translation_source is the $node of the source/origin).

At least in this clean drupal+i18n+webform 3.x checkout it works neat.

Thanks for your inputs. Please review again.

quicksketch’s picture

Fantastic. We should double-check, it looks like putting this below the INSERT statement would prevent things like the confirmation message and redirect URL from being properly copied. Just moving the new lines up above the INSERT statement should ensure they get copied also.

miro_dietiker’s picture

But there's a big oops now.

We're overwriting the node->webform part. This means, if some form part is on the node edit form, we're overwriting something with original/untranslated content that might be edited by the user.

You're also right since the $node object now is in invalid state - it doesn't represent the saved state. Doing another node_save to resave the node will write different values. (Some tools like rules.module do that on one single node save after triggering rulebased changes.)

The node cloning should happen before the nodeapi validate thing happens. I think it should even happen before node validate occurs.

Checking the translation.module implementation of nodeapi which finally invokes this after loading the node:

node_invoke_nodeapi($node, 'prepare translation');

I think i've found the right direction with implementing this hook. My forms cleanly copy now and the webform values can be overridden in the drupal standard form / submit / save process.

Is there any compareable situation from a different module?

quicksketch’s picture

That looks much better. We've done similar things for Flag module I know (in addition to working with Translation Helpers).

Just a note that this should never be the case (not that it makes any difference with the new approach):

This means, if some form part is on the node edit form, we're overwriting something with original/untranslated content that might be edited by the user.

All Webform settings are now under the node/x/webform tab and never on the node edit form, so this shouldn't ever come into play.

EugenMayer’s picture

Status: Needs review » Reviewed & tested by the community

Also done similar things in content_moderation with i18n support. Sounds reasonable here to keep the relation to the webform on cloning the node for i18n.

miro_dietiker’s picture

Thanks for review Eugen. Hope this remains self-explanatory and fast forward.

quicksketch’s picture

Status: Reviewed & tested by the community » Fixed
FileSize
2.13 KB

I've committed this patch with some changes for consistency with the Drupal 7 version. I broke out the hook_node_prepare() functionality to match that of Drupal 7. Probably not entirely related to this issue, but while we were fixing "prepare" hooks it seemed to be a good time to make the change.

Committed to both 3.x branches.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.