diff --git a/src/Entity/ExternalEntity.php b/src/Entity/ExternalEntity.php index ca917dbdb07a94279e072a5213f1daa39030010b..46a3e8774fa327f4d606972eabf571c14109a718 100644 --- a/src/Entity/ExternalEntity.php +++ b/src/Entity/ExternalEntity.php @@ -127,6 +127,7 @@ class ExternalEntity extends ContentEntityBase implements ExternalEntityInterfac 'type' => 'string', 'label' => 'hidden', ]) + ->setTranslatable(TRUE) ->setDisplayConfigurable('view', TRUE) ->setDisplayOptions('form', [ 'type' => 'string_textfield', diff --git a/src/ExternalEntityStorage.php b/src/ExternalEntityStorage.php index 144dceb857dfb9e9ee4dce926785815cb9b5abe2..c56b95257e935ce834e20330521fc41d8a76ace5 100644 --- a/src/ExternalEntityStorage.php +++ b/src/ExternalEntityStorage.php @@ -106,6 +106,14 @@ class ExternalEntityStorage extends ContentEntityStorageBase implements External */ protected $xnttIdFieldName; + /** + * Prefix to detect translation data in remote source raw data. + * + * If found the trailing langcode after the prefix is used to populate an + * entity translation. + */ + public const EXTERNAL_ENTITY_TRANSLATION_SUB_FIELD_PREFIX = '__external_entity_translation__'; + /** * Constructs a new ExternalEntityStorage object. * @@ -717,6 +725,24 @@ class ExternalEntityStorage extends ContentEntityStorageBase implements External catch (EntityStorageException $exception) { DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '10.1.0', fn() => Error::logException(\Drupal::logger('external_entities'), $exception), fn() => watchdog_exception('external_entities', $exception)); } + + // Check if there are translation data available. + foreach ($all_raw_data[$id] as $key => $raw_translation_data) { + if (str_starts_with($key, self::EXTERNAL_ENTITY_TRANSLATION_SUB_FIELD_PREFIX)) { + try { + $langcode = str_replace(self::EXTERNAL_ENTITY_TRANSLATION_SUB_FIELD_PREFIX, '', $key); + $entity_translation_data = $this->extractEntityValuesFromRawData($raw_translation_data[$id]); + $entities[$id]->addTranslation($langcode, $entity_translation_data); + } catch (\Throwable $exception) { + // Don't completely fail if a translation can't be handled. + $this->logger->error( + 'Error while mapping translation data for external entity @entity_id: @message', + ['@entity_id' => $id, '@message' => $exception->getMessage()] + ); + } + } + } + $entities[$id]->enforceIsNew(FALSE); } diff --git a/src/Plugin/ExternalEntities/DataAggregator/GroupAggregator.php b/src/Plugin/ExternalEntities/DataAggregator/GroupAggregator.php index cc8f624258b0f2ae48922280bb04c5ae55bc42b3..d21bdc4e9f8fc7e500321cffe89e4365e53f5cfe 100644 --- a/src/Plugin/ExternalEntities/DataAggregator/GroupAggregator.php +++ b/src/Plugin/ExternalEntities/DataAggregator/GroupAggregator.php @@ -640,7 +640,7 @@ class GroupAggregator extends DataAggregatorBase implements DataAggregatorInterf // matching ids which is given by $client_ids values. // Sets default merge behavior. $config['storage_clients'][$client_index]['aggr']['merge'] ??= 'keep'; - if ('sub' == $config['storage_clients'][$client_index]['aggr']['merge']) { + if (in_array($config['storage_clients'][$client_index]['aggr']['merge'], ['sub', 'translation'])) { // Store corresponding client entities as member. $member = ($config['storage_clients'][$client_index]['aggr']['merge_as_member'] ?? '') diff --git a/src/Plugin/ExternalEntities/DataAggregator/VerticalDataAggregator.php b/src/Plugin/ExternalEntities/DataAggregator/VerticalDataAggregator.php index 0de5ebbcbf13afae24ecf2c91963b1f6d497b5c3..ea608dfdf97eab615fcff40189b5cd775f9973a1 100644 --- a/src/Plugin/ExternalEntities/DataAggregator/VerticalDataAggregator.php +++ b/src/Plugin/ExternalEntities/DataAggregator/VerticalDataAggregator.php @@ -3,6 +3,8 @@ namespace Drupal\external_entities\Plugin\ExternalEntities\DataAggregator; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Language\Language; +use Drupal\external_entities\ExternalEntityStorage; /** * External entities data aggregator by groups. @@ -83,6 +85,7 @@ class VerticalDataAggregator extends GroupAggregator { 'over' => $this->t('Override previous field values'), 'ovem' => $this->t('Override previous field values if empty'), 'sub' => $this->t('As a sub-object'), + 'translation' => $this->t('As a translation'), ], '#description' => $this->t( 'If set, entity field values provided by this storage client will override existing values with the same field name provided by previous storage clients (except for the identifier and join fields).' @@ -106,6 +109,20 @@ class VerticalDataAggregator extends GroupAggregator { ], ], ]; + $storage_client_form['merge_as_member_translation'] = [ + '#type' => 'language_select', + '#languages' => Language::STATE_ALL, + '#title' => $this->t('Language'), + '#description' => $this->t( + 'Select the language this source is used for. The data from the first source are used as values for the sites default language!' + ), + '#default_value' => str_replace(ExternalEntityStorage::EXTERNAL_ENTITY_TRANSLATION_SUB_FIELD_PREFIX, '', $aggr_config[$client_index]['aggr']['merge_as_member'] ?? ''), + '#states' => [ + 'visible' => [ + ':input[id="' . $aggr_selector . '_merge"]' => ['value' => 'translation'], + ], + ], + ]; } else { // First storage client. @@ -141,6 +158,13 @@ class VerticalDataAggregator extends GroupAggregator { $aggr_settings = $form_state->getValue(['storage_clients', $client_index, 'aggr'], []); $aggr_settings['groups'] = []; $aggr_settings['group_prefix_strip'] = FALSE; + + // If translation aggregation is enabled create a compound merge_as_member + // value. + if (($aggr_settings['merge'] ?? '') == 'translation') { + $aggr_settings['merge_as_member'] = ExternalEntityStorage::EXTERNAL_ENTITY_TRANSLATION_SUB_FIELD_PREFIX .$aggr_settings['merge_as_member_translation'] ?? ''; + } + $form_state->setValue(['storage_clients', $client_index, 'aggr'], $aggr_settings); }