When working with on #242601: translate node references with i18nsync I began to wonder: can we reuse 'prepare translation' instead of doing custom synchronization?

i18nsync provides great and needed functionality, but currently has a number of limitations:

  1. It doesn't implement a hook and so modules can't add their own support. Rather, every time we want to add support for a module we need to edit i18nsync.
  2. Sync functionality is primarily focused on updates. On 'create translation', we use a very basic sync--assign the field value of the source translation. This functionality risks collisions with modules that properly implement hook_nodeapi's 'prepare translation' op. For example, on 'prepare translation', nodereference module correctly localizes nodereferences, selecting a corresponding translation. But if i18nsync is enabled for the field, it overwrites (breaks) nodereference's translation-aware approach by reinstating the nodereference values of the source translation.
  3. As a result of 1. and 2., we can end up with code duplication. For example, #242601: translate node references with i18nsync, a current patch to add nodereference support to i18nsync, basically duplicates code from nodereference module.

What I'm struck by is that, in every case I can think of, what we want for specified fields on sync is exactly the same as what we want for all fields on 'prepare translation'. That is:

  • For most fields, we want the same value as the source translation (on 'prepare translation', the translation source; on node update, the translation that was updated).
  • For some special fields, rather than the same value, we want a localized version of the value. Examples include nodereference, organic groups (not yet implemented), and image attach, where we want a translation of the (image, nodereference, organic group) node in the language of the target node, if one exists.

There may be some exceptions I'm not thinking of, but even if there are, it does seem that in the vast majority of cases, the two needs are the same. So, rather than reproducing 'prepare translation', we should be able to reuse it for specified fields.

Here's a possible approach:

On nodeapi update, fetch translations and for each translation

  • Create a clone of the translation.
  • Add the updated node as the $clone->translation_source.
  • Invoke nodeapi 'prepare translation' on the clone.
  • Iterate through the fields and set the values.

The result would look like:


function i18nsync_node_translation($node, $translation, $fields, $op) {
  // Load full node, we need all data here.
  $translation = node_load($translation->nid, NULL, TRUE);
  // Create a clone, as we don't want to keep all changes.
  $clone = drupal_clone($translation);
  // Set a flag so that 'prepare translation' implementations know this is a
  // synchronization, in case they differentiate between sync and prepare translation.
  $clone->i18nsync = TRUE;
  // Set the translation source.
  $clone->translation_source = $node;
  // Invoke nodeapi's 'prepare translation' op.
  node_invoke_nodeapi($clone, 'prepare translation');
  // We want only some of the changes that may have been made.
  foreach ($fields as $field) {
    $translation->$field = $clone->$field;
  }
  node_save($translation);
}

The main thing missing from this approach would be a way to know what node fields a particular module provides. Currently this is hard-coded into i18nsync_node_available_fields().

Likely we'd need to introduce a new hook, e.g. hook_fields(), which returns these data. Such an op could be useful for other applications beyond translation sync.

This approach could enable us to greatly simplify i18nsync, while pushing future changes not into i18nsync but into the modules that supply the data, in the form of nodeapi 'prepare translation' implementations.

Comments

dasjo’s picture

subscribing

nedjo’s picture

Likely we'd need to introduce a new hook, e.g. hook_fields()

Rather than a new hook, we could use CCK's hook_content_extra_fields(), which looks to provide the needed data. See Eaton's blog post for usage, http://www.lullabot.com/articles/great-pretender-making-your-data-act-field.

paranojik’s picture

subscribing

rjmackay’s picture

subscribing

any chance of development going ahead on this?

jose reyero’s picture

Component: Code » Blocks
Status: Active » Closed (won't fix)

Late for 6.x, new features for 7.x