In i18n_sync_options() we have the lines:

    // Give a chance to modules to change/remove/add their own fields
    drupal_alter('i18n_sync_options', $fields, $entity_type, $bundle_name);

However, the comment is misleading because fields can be altered but not added or removed. If any field names are added to or removed from the array returned by implementations of hook_i18n_sync_options_alter() this information is not used in i18n_sync_node_translation() when actually cycling through each field to sync. That function has
foreach ($field_names as $field)
where $field_names comes directly from i18n_sync_node_fields($node->type) ie the configured list of fields that should be synced, regardless of any change to names made in the hook alter.

(a) To allow hook_i18n_sync_options_alter() to remove fields from the syncing list we could use
$field_names_for_sync = array_intersect($field_names, array_keys($i18n_options))
for the foreach expression above. $i18n_options holds the list as returned and modified by hook_i18n_sync_options_alter() and $field_names holds the set of fields that the admin has selected to be synced. So their intersection will be the list ultimately needing to be synced.

(b) For hook_i18n_sync_options_alter() to be able to add fields which are not previously defined by any hook_i18n_sync_options() it would need a little more work, as the returned array would need some way to store the fact a field has been added not simply that the admin has not ticked the checkbox to sync it. This is because hook_i18n_sync_options() returns the full list of fields available to be selected for syncing. I can imagine that there may be fields which a contrib module needs to control without giving the admin the choice whether to sync or not.

In Scheduler we need the functionality to remove our fields when the process is being run by cron but have them synced during normal user editing of the node. So I am particularly intersted in case (a) above. See #1182450-32: i18n support - Synchronize scheduled dates in translated nodes for the background and #2136557: Provide hook for modules to turn off synchronisation for an alternative method I requested.

Jonathan

Comments

jonathan1055’s picture

Issue summary: View changes

Corrected link

Jose Reyero’s picture

Well, basically you are right though I think this is just how it is supposed to work:
- sync options provides a list of fields for the admin to select from, and then that is stored in settings.
- stored settings are used for the actual synchronization (Really, I don't think hooks changing the settings at runtime are very common).

Anyway, let's try to find a solution that doesn't overcomplicate an already complex piece of code. I can think of some options:

a) Modules can change settings (global $conf) at runtime. That's maybe what a module should do if it pretends to override an admin setting for specific purposes.

b) You can also form alter the settings form so the admin cannot select a field for syncing that will cause some trouble with some specific module (scheduler not allowing syncing node status). Then hook_i18n_sync_translation can be used to synchronize that field under some circumstances.

c) We can add some -should be as simple as possible- hook to allow other modules at runtime to change sync options but if we are invoking one more hook, we can allow some other options there. How does this look like?:

// Prepare sync operation, stuff all the info here. Note this is an object and will be passed by reference always.
$sync = (object)array(
  'source' => $node,
  'translations' => $translations,
  'sync_options' => $i18n_options,
  'field_names' => ...
);
// Modules can change fields, options, even the list of translations to sync.
module_invoke_all('i18n_sync_prepare', $entity_type, $bundle_name, $sync);

// Then run the sync operation for each translation...