Batch callback: Converts field data to or from Language::LANGCODE_NOT_SPECIFIED.
bool $translatable: Indicator of whether the field should be made translatable (TRUE) or untranslatble (FALSE).
string $field_name: Field machine name.
function translation_entity_translatable_batch($translatable, $field_name, &$context) {
$field = field_info_field($field_name);
$column = isset($field['columns']['value']) ? 'value' : key($field['columns']);
$query_field = "{$field_name}.{$column}";
// Determine the entity types to act on.
$entity_types = array();
foreach (field_info_instances() as $entity_type => $info) {
foreach ($info as $bundle => $instances) {
foreach ($instances as $instance_field_name => $instance) {
if ($instance_field_name == $field_name) {
$entity_types[] = $entity_type;
break 2;
}
}
}
}
if (empty($context['sandbox'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['max'] = 0;
foreach ($entity_types as $entity_type) {
// How many entities will need processing?
$query = Drupal::entityQuery($entity_type);
$count = $query
->exists($query_field)
->count()
->execute();
$context['sandbox']['max'] += $count;
$context['sandbox']['progress_entity_type'][$entity_type] = 0;
$context['sandbox']['max_entity_type'][$entity_type] = $count;
}
if ($context['sandbox']['max'] === 0) {
// Nothing to do.
$context['finished'] = 1;
return;
}
}
foreach ($entity_types as $entity_type) {
if ($context['sandbox']['max_entity_type'][$entity_type] === 0) {
continue;
}
$info = entity_get_info($entity_type);
$offset = $context['sandbox']['progress_entity_type'][$entity_type];
$query = Drupal::entityQuery($entity_type);
$result = $query
->exists($query_field)
->sort($info['entity_keys']['id'])
->range($offset, 10)
->execute();
foreach (entity_load_multiple($entity_type, $result) as $id => $entity) {
$context['sandbox']['max_entity_type'][$entity_type] -= count($result);
$context['sandbox']['progress_entity_type'][$entity_type]++;
$context['sandbox']['progress']++;
$langcode = $entity
->language()->langcode;
// Skip process for language neutral entities.
if ($langcode == Language::LANGCODE_NOT_SPECIFIED) {
continue;
}
// We need a two-step approach while updating field translations: given
// that field-specific update functions might rely on the stored values to
// perform their processing, see for instance file_field_update(), first
// we need to store the new translations and only after we can remove the
// old ones. Otherwise we might have data loss, since the removal of the
// old translations might occur before the new ones are stored.
if ($translatable && isset($entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED])) {
// If the field is being switched to translatable and has data for
// Language::LANGCODE_NOT_SPECIFIED then we need to move the data to the right
// language.
$entity->{$field_name}[$langcode] = $entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED];
// Store the original value.
_translation_entity_update_field($entity_type, $entity, $field_name);
$entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED] = array();
// Remove the language neutral value.
_translation_entity_update_field($entity_type, $entity, $field_name);
}
elseif (!$translatable && isset($entity->{$field_name}[$langcode])) {
// The field has been marked untranslatable and has data in the entity
// language: we need to move it to Language::LANGCODE_NOT_SPECIFIED and drop the
// other translations.
$entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED] = $entity->{$field_name}[$langcode];
// Store the original value.
_translation_entity_update_field($entity_type, $entity, $field_name);
// Remove translations.
foreach ($entity->{$field_name} as $langcode => $items) {
if ($langcode != Language::LANGCODE_NOT_SPECIFIED) {
$entity->{$field_name}[$langcode] = array();
}
}
_translation_entity_update_field($entity_type, $entity, $field_name);
}
else {
// No need to save unchanged entities.
continue;
}
}
}
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
}