You are here

public function LingotekContentTranslationService::saveTargetData in Lingotek Translation 3.6.x

Same name and namespace in other branches
  1. 8 src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  2. 8.2 src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  3. 4.0.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  4. 3.0.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  5. 3.1.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  6. 3.2.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  7. 3.3.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  8. 3.4.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  9. 3.5.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  10. 3.7.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()
  11. 3.8.x src/LingotekContentTranslationService.php \Drupal\lingotek\LingotekContentTranslationService::saveTargetData()

Save the entity translation.

Parameters

\Drupal\Core\Entity\ContentEntityInterface &$entity: The entity we want to save a translation for.

$locale: The locale of the translation being saved.

$data: The data being saved.

Return value

\Drupal\Core\Entity\ContentEntityInterface Returns the entity which translations are saved.

Overrides LingotekContentTranslationServiceInterface::saveTargetData

2 calls to LingotekContentTranslationService::saveTargetData()
LingotekContentTranslationService::downloadDocument in src/LingotekContentTranslationService.php
Downloads a document from the Lingotek service for a given locale.
LingotekContentTranslationService::downloadDocuments in src/LingotekContentTranslationService.php
Downloads a document from the Lingotek service for all available locales.

File

src/LingotekContentTranslationService.php, line 1594

Class

LingotekContentTranslationService
Service for managing Lingotek content translations.

Namespace

Drupal\lingotek

Code

public function saveTargetData(ContentEntityInterface &$entity, $langcode, $data) {

  // Without a defined langcode, we can't proceed
  if (!$langcode) {

    // TODO: log warning that downloaded translation's langcode is not enabled.
    return FALSE;
  }
  $storage_definitions = $this->entityFieldManager
    ->getFieldStorageDefinitions($entity
    ->getEntityTypeId());
  try {

    // We need to load the revision that was uploaded for consistency. For that,
    // we check if we have a valid revision in the response, and if not, we
    // check the date of the uploaded document.

    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $revision = isset($data['_lingotek_metadata']) && isset($data['_lingotek_metadata']['_entity_revision']) ? $data['_lingotek_metadata']['_entity_revision'] : NULL;
    $revision = $this
      ->loadUploadedRevision($entity, $revision);

    // We should reload the last revision of the entity at all times.
    // This check here is only because of the case when we have asymmetric
    // paragraphs for translations, as in that case we get a duplicate that
    // still has not a valid entity id.
    // Also take into account that we may have just removed paragraph
    // translations form previous translation approaches, and in that case we
    // are forced to remove those, but there will be a mark of translation
    // changes.
    if ($entity
      ->id() && !$entity
      ->hasTranslationChanges()) {
      $entity = $this->entityTypeManager
        ->getStorage($entity
        ->getEntityTypeId())
        ->load($entity
        ->id());
    }

    // Initialize the translation on the Drupal side, if necessary.

    /** @var \Drupal\Core\Entity\ContentEntityInterface $translation */
    if (!$entity
      ->hasTranslation($langcode)) {
      $entity
        ->addTranslation($langcode, $revision
        ->toArray());
    }
    $translation = $entity
      ->getTranslation($langcode);
    foreach ($data as $name => $field_data) {
      if (strpos($name, '_') === 0) {

        // Skip special fields underscored.
        break;
      }
      $field_definition = $entity
        ->getFieldDefinition($name);
      if ($field_definition && ($field_definition
        ->isTranslatable() || $field_definition
        ->getType() === 'cohesion_entity_reference_revisions' || $field_definition
        ->getType() === 'entity_reference_revisions') && $this->lingotekConfiguration
        ->isFieldLingotekEnabled($entity
        ->getEntityTypeId(), $entity
        ->bundle(), $name)) {

        // First we check if this is a entity reference, and save the translated entity.
        $field_type = $field_definition
          ->getType();
        if ($field_type === 'entity_reference' || $field_type === 'er_viewmode' || $field_type === 'bricks') {
          $target_entity_type_id = $field_definition
            ->getFieldStorageDefinition()
            ->getSetting('target_type');
          $translation->{$name} = NULL;
          $delta = 0;
          foreach ($field_data as $index => $field_item) {
            if (isset($field_item['_lingotek_metadata'])) {
              $target_entity_type_id = $field_item['_lingotek_metadata']['_entity_type_id'];
              $embedded_entity_id = $field_item['_lingotek_metadata']['_entity_id'];
              $embedded_entity_revision_id = $field_item['_lingotek_metadata']['_entity_revision'];
            }
            else {

              // Try to get it from the revision itself. It may have been
              // modified, so this can be a source of errors, but we need this
              // because we didn't have metadata before.
              $embedded_entity_id = $revision->{$name}
                ->get($index)
                ->get('target_id')
                ->getValue();
            }
            $embedded_entity = $this->entityTypeManager
              ->getStorage($target_entity_type_id)
              ->load($embedded_entity_id);

            // We may have orphan references, so ensure that they exist before
            // continuing.
            if ($embedded_entity !== NULL) {

              // ToDo: It can be a content entity, or a config entity.
              if ($embedded_entity instanceof ContentEntityInterface) {
                if ($this->lingotekConfiguration
                  ->isEnabled($embedded_entity
                  ->getEntityTypeId(), $embedded_entity
                  ->bundle())) {
                  $this
                    ->saveTargetData($embedded_entity, $langcode, $field_item);
                }
                else {
                  \Drupal::logger('lingotek')
                    ->warning('Field %field not saved as its referenced entity is not translatable by Lingotek', [
                    '%field' => $name,
                  ]);
                }
              }
              elseif ($embedded_entity instanceof ConfigEntityInterface) {
                $this->lingotekConfigTranslation
                  ->saveTargetData($embedded_entity, $langcode, $field_item);
              }

              // Now the embedded entity is saved, but we need to ensure
              // the reference will be saved too.
              $translation->{$name}
                ->set($delta, $embedded_entity_id);
              $delta++;
            }
          }
        }
        elseif ($field_type === 'entity_reference_revisions') {
          $paragraphTranslatable = $field_definition
            ->isTranslatable();
          $target_entity_type_id = $field_definition
            ->getFieldStorageDefinition()
            ->getSetting('target_type');
          if ($paragraphTranslatable) {
            $translation->{$name} = NULL;
          }
          $delta = 0;
          $fieldValues = [];
          foreach ($field_data as $index => $field_item) {
            $embedded_entity_id = $revision->{$name}
              ->get($index)
              ->get('target_id')
              ->getValue();

            /** @var \Drupal\Core\Entity\RevisionableInterface $embedded_entity */
            $embedded_entity = $this->entityTypeManager
              ->getStorage($target_entity_type_id)
              ->load($embedded_entity_id);
            if ($embedded_entity !== NULL) {

              // If there is asymmetrical paragraphs enabled, we need a new one duplicated and stored.
              if ($paragraphTranslatable && \Drupal::moduleHandler()
                ->moduleExists('paragraphs_asymmetric_translation_widgets')) {

                /** @var \Drupal\paragraphs\ParagraphInterface $duplicate */
                $duplicate = $embedded_entity
                  ->createDuplicate();
                if ($duplicate
                  ->isTranslatable()) {

                  // If there is already a translation for the language we
                  // want to set as default, we have to remove it. This should
                  // never happen, but there may different previous approaches
                  // to translating paragraphs, so we need to make sure the
                  // download does not break because of this.
                  if ($duplicate
                    ->hasTranslation($langcode)) {
                    $duplicate
                      ->removeTranslation($langcode);
                    $duplicate
                      ->save();
                  }
                  $duplicate
                    ->set('langcode', $langcode);
                  foreach ($duplicate
                    ->getTranslationLanguages(FALSE) as $translationLanguage) {
                    try {
                      $duplicate
                        ->removeTranslation($translationLanguage
                        ->getId());
                    } catch (\InvalidArgumentException $e) {

                      // Should never happen.
                    }
                  }
                }
                $embedded_entity = $duplicate;
              }
              $this
                ->saveTargetData($embedded_entity, $langcode, $field_item);

              // Now the embedded entity is saved, but we need to ensure
              // the reference will be saved too. Ensure it's the same revision.
              $fieldValues[$delta] = [
                'target_id' => $embedded_entity
                  ->id(),
                'target_revision_id' => $embedded_entity
                  ->getRevisionId(),
              ];
              $delta++;
            }
          }

          // If the paragraph was not translatable, we avoid at all costs to modify the field,
          // as this will override the source and may have unintended consequences.
          if ($paragraphTranslatable) {
            $translation->{$name} = $fieldValues;
          }
        }
        elseif ($field_type === 'tablefield') {
          foreach ($field_data as $delta => $field_item_data) {
            $embedded_data = [];
            $caption = '';
            $table = [];
            foreach ($field_item_data as $row_index => $row) {
              if ($row_index === 'caption') {
                $caption = $row;
              }
              else {
                foreach ($row as $col_index => $cell) {
                  $table[intval(str_replace('row:', '', $row_index))][intval(str_replace('col:', '', $col_index))] = $cell;
                }
              }
            }
            $translation->{$name}
              ->set($delta, [
              'caption' => $caption,
              'value' => $table,
            ]);
          }
        }
        elseif ($field_type === 'cohesion_entity_reference_revisions') {
          $cohesionLayoutTranslatable = $field_definition
            ->isTranslatable();
          $target_entity_type_id = $field_definition
            ->getFieldStorageDefinition()
            ->getSetting('target_type');
          if ($cohesionLayoutTranslatable) {
            $translation->{$name} = NULL;
          }
          $delta = 0;
          $fieldValues = [];
          foreach ($field_data as $index => $field_item) {
            $embedded_entity_id = $revision->{$name}
              ->get($index)
              ->get('target_id')
              ->getValue();

            /** @var \Drupal\Core\Entity\RevisionableInterface $embedded_entity */
            $embedded_entity = $this->entityTypeManager
              ->getStorage($target_entity_type_id)
              ->load($embedded_entity_id);
            if ($embedded_entity !== NULL) {
              $this
                ->saveTargetData($embedded_entity, $langcode, $field_item);

              // Now the embedded entity is saved, but we need to ensure
              // the reference will be saved too. Ensure it's the same revision.
              $fieldValues[$delta] = [
                'target_id' => $embedded_entity
                  ->id(),
                'target_revision_id' => $embedded_entity
                  ->getRevisionId(),
              ];
              $delta++;
            }
          }

          // If the cohesion layout was not translatable, we avoid at all costs to modify the field,
          // as this will override the source and may have unintended consequences.
          if ($cohesionLayoutTranslatable) {
            $translation->{$name} = $fieldValues;
          }
        }
        elseif ($field_type === 'path') {
          $pid = NULL;
          $source = '/' . $entity
            ->toUrl()
            ->getInternalPath();

          /** @var \Drupal\Core\Entity\EntityStorageInterface $aliasStorage */
          $alias_storage = $this->entityTypeManager
            ->getStorage('path_alias');

          /** @var \Drupal\path_alias\PathAliasInterface[] $original_paths */
          $original_paths = $alias_storage
            ->loadByProperties([
            'path' => $source,
            'langcode' => $entity
              ->getUntranslated()
              ->language()
              ->getId(),
          ]);
          $original_path = NULL;
          $alias = $field_data[0]['alias'];

          // Validate the alias before saving.
          if (!UrlHelper::isValid($alias)) {
            \Drupal::logger('lingotek')
              ->warning('Alias for %type %label in language %langcode not saved, invalid uri "%uri"', [
              '%type' => $entity
                ->getEntityTypeId(),
              '%label' => $entity
                ->label(),
              '%langcode' => $langcode,
              '%uri' => $alias,
            ]);

            // Default to the original path.
            if (count($original_paths) > 0) {
              $original_path = reset($original_paths);
              $alias = $original_path
                ->getAlias();
            }
            else {
              $alias = $source;
            }
            if (\Drupal::moduleHandler()
              ->moduleExists('pathauto')) {
              $alias = '';
              $translation
                ->get($name)
                ->offsetGet(0)
                ->set('alias', $alias);
              $translation
                ->get($name)
                ->offsetGet(0)
                ->set('pathauto', TRUE);
            }
          }
          if ($alias !== NULL) {
            $translation
              ->get($name)
              ->offsetGet(0)
              ->set('alias', $alias);
            if (\Drupal::moduleHandler()
              ->moduleExists('pathauto') && !empty($alias) && $alias !== $original_path) {
              $translation
                ->get($name)
                ->offsetGet(0)
                ->set('pathauto', FALSE);
            }
          }
        }
        elseif ($field_type === 'metatag') {
          $index = 0;
          foreach ($field_data as $field_item) {
            $metatag_value = serialize($field_item);
            $translation->{$name}
              ->set($index, $metatag_value);
            ++$index;
          }
        }
        elseif ($field_type === 'string_long' && $field_definition
          ->getName() === 'json_values' && $field_definition
          ->getTargetEntityTypeId() === 'cohesion_layout') {
          $existingData = $revision
            ->get($name)
            ->offsetGet(0)->value;
          $layout_canvas = new LayoutCanvas($existingData);
          foreach ($layout_canvas
            ->iterateCanvas() as $element) {
            if (!$element
              ->isComponent() || !($component = Component::load($element
              ->getComponentID()))) {
              continue;
            }
            if (!($model = $element
              ->getModel())) {
              continue;
            }
            $component_model = $component
              ->getLayoutCanvasInstance()
              ->iterateModels('component_form');
            $component_data = $field_data[$element
              ->getUUID()] ?? NULL;
            if (!$component_data) {
              continue;
            }
            $this
              ->setCohesionComponentValues($component_model, $model, $component_data);
          }
          $translation
            ->get($name)
            ->offsetGet(0)
            ->set('value', json_encode($layout_canvas));
        }
        elseif ($field_type === 'layout_section') {

          // TODO: Ensure we use LB_AT.
          $sourceSections = $revision->{$name};
          $translation->{$name} = NULL;

          // If we are embedding content blocks, we need to translate those too.
          // And we need to do that before saving the sections, as we need to
          // reference the latest revision.
          if (isset($field_data['entities']['block_content'])) {
            foreach ($field_data['entities']['block_content'] as $embedded_entity_revision_id => $blockContentData) {
              $target_entity_type_id = 'block_content';
              $embedded_entity = $this->entityTypeManager
                ->getStorage($target_entity_type_id)
                ->loadRevision($embedded_entity_revision_id);

              // We may have orphan references, so ensure that they exist before
              // continuing.
              if ($embedded_entity !== NULL) {
                if ($embedded_entity instanceof ContentEntityInterface) {
                  if ($this->lingotekConfiguration
                    ->isEnabled($embedded_entity
                    ->getEntityTypeId(), $embedded_entity
                    ->bundle())) {
                    $this
                      ->saveTargetData($embedded_entity, $langcode, $blockContentData);
                  }
                  else {
                    \Drupal::logger('lingotek')
                      ->warning('Field %field not saved as its referenced entity is not translatable by Lingotek', [
                      '%field' => $name,
                    ]);
                  }
                }
              }
            }
          }
          foreach ($sourceSections as $delta => &$field_item) {

            /** @var \Drupal\layout_builder\SectionComponent $sectionObject */
            $sectionObject = clone $field_item->section;
            $components = $sectionObject
              ->getComponents();

            /** @var \Drupal\layout_builder\SectionComponent $component */
            foreach ($components as $componentUuid => &$component) {
              $config = $component
                ->get('configuration');
              if (isset($field_data['components'][$componentUuid])) {
                $componentData = $field_data['components'][$componentUuid];
                foreach ($componentData as $componentDataKey => $componentDataValue) {
                  $componentDataKeyParts = explode('.', $componentDataKey);
                  NestedArray::setValue($config, $componentDataKeyParts, $componentDataValue);
                }
              }

              // We need to reference the latest revision.
              if (isset($config['block_revision_id']) && strpos($config['id'], 'inline_block') === 0) {
                $old_revision_id = $config['block_revision_id'];
                $storage = $this->entityTypeManager
                  ->getStorage('block_content');
                $bc = $storage
                  ->loadRevision($old_revision_id);
                $latest = $storage
                  ->load($bc
                  ->id());
                $rev = $latest
                  ->getRevisionId();
                $config['block_revision_id'] = $rev;
              }
              $component
                ->setConfiguration($config);
            }
            $translation->{$name}
              ->set($delta, [
              'section' => $sectionObject,
            ]);
          }
        }
        elseif ($field_type === 'layout_translation') {
          $components = [];

          // We need the original layout, as the translation must store the
          // non-translatable properties too. So we need to copy them to the
          // translated field.
          $block_manager = \Drupal::service('plugin.manager.block');
          $layoutField = $entity->{OverridesSectionStorage::FIELD_NAME};
          $layout = $layoutField
            ->getValue();
          foreach ($field_data['components'] as $componentUuid => $componentData) {

            /** @var \Drupal\layout_builder\SectionComponent $originalComponent */
            $originalComponent = NULL;

            /** @var \Drupal\layout_builder\Section $section */
            foreach ($layout as $sectionInfo) {
              $sectionComponents = $sectionInfo['section']
                ->getComponents();
              if (isset($sectionComponents[$componentUuid])) {
                $originalComponent = $sectionComponents[$componentUuid];
                break;
              }
            }
            $block_instance = $block_manager
              ->createInstance($originalComponent
              ->getPluginId(), $originalComponent
              ->get('configuration'));
            $blockConfig = $block_instance
              ->getConfiguration();
            $components[$componentUuid] = [];
            foreach ($componentData as $componentDataKey => $componentDataValue) {
              $componentDataKeyParts = explode('.', $componentDataKey);
              if (count($componentDataKeyParts) > 1) {

                // The translation must store the non-translatable properties
                // too. So we copy them from the original field. The key to be
                // copied is the complete key but the last piece.
                $originalDataKeyParts = array_slice($componentDataKeyParts, 0, -1);
                NestedArray::setValue($components[$componentUuid], $originalDataKeyParts, NestedArray::getValue($blockConfig, $originalDataKeyParts));
              }
              NestedArray::setValue($components[$componentUuid], $componentDataKeyParts, $componentDataValue);
            }
          }

          // If we are embedding content blocks, we need to translate those too.
          if (isset($field_data['entities']['block_content'])) {
            foreach ($field_data['entities']['block_content'] as $embedded_entity_revision_id => $blockContentData) {
              $target_entity_type_id = 'block_content';
              $embedded_entity = $this->entityTypeManager
                ->getStorage($target_entity_type_id)
                ->loadRevision($embedded_entity_revision_id);

              // We may have orphan references, so ensure that they exist before
              // continuing.
              if ($embedded_entity !== NULL) {
                if ($embedded_entity instanceof ContentEntityInterface) {
                  if ($this->lingotekConfiguration
                    ->isEnabled($embedded_entity
                    ->getEntityTypeId(), $embedded_entity
                    ->bundle())) {
                    $this
                      ->saveTargetData($embedded_entity, $langcode, $blockContentData);
                  }
                  else {
                    \Drupal::logger('lingotek')
                      ->warning('Field %field not saved as its referenced entity is not translatable by Lingotek', [
                      '%field' => $name,
                    ]);
                  }
                }
              }
            }
          }
          $translation->{$name}->value = [
            'components' => $components,
          ];
        }
        elseif ($field_type === 'block_field') {
          $translation->{$name} = NULL;
          foreach ($field_data as $index => $field_item) {

            /** @var \Drupal\Core\Block\BlockPluginInterface $block */
            $block = $revision
              ->get($name)
              ->get($index)
              ->getBlock();
            if ($block !== NULL) {
              $entityData = NULL;
              if (isset($field_item['entity'])) {
                $entityData = $field_item['entity'];
                unset($field_item['entity']);
              }
              $configuration = $block
                ->getConfiguration();
              $newConfiguration = $configuration;
              foreach ($field_item as $fieldItemProperty => $fieldItemPropertyData) {
                $componentDataKeyParts = explode('.', $fieldItemProperty);
                NestedArray::setValue($newConfiguration, $componentDataKeyParts, $fieldItemPropertyData);
              }
              $translation->{$name}
                ->set($index, [
                'plugin_id' => $block
                  ->getPluginId(),
                'settings' => $newConfiguration,
              ]);
              if ($entityData !== NULL) {
                $embedded_entity_id = NULL;
                if (isset($entityData['_lingotek_metadata'])) {
                  $target_entity_type_id = $entityData['_lingotek_metadata']['_entity_type_id'];
                  $embedded_entity_id = $entityData['_lingotek_metadata']['_entity_id'];
                  $embedded_entity_revision_id = $entityData['_lingotek_metadata']['_entity_revision'];
                  $embedded_entity = $this->entityTypeManager
                    ->getStorage($target_entity_type_id)
                    ->load($embedded_entity_id);

                  // We may have orphan references, so ensure that they exist before
                  // continuing.
                  if ($embedded_entity !== NULL) {
                    if ($embedded_entity instanceof ContentEntityInterface) {
                      if ($this->lingotekConfiguration
                        ->isEnabled($embedded_entity
                        ->getEntityTypeId(), $embedded_entity
                        ->bundle())) {
                        $this
                          ->saveTargetData($embedded_entity, $langcode, $entityData);
                      }
                      else {
                        \Drupal::logger('lingotek')
                          ->warning('Field %field not saved as its referenced entity is not translatable by Lingotek', [
                          '%field' => $name,
                        ]);
                      }
                    }
                  }
                }
              }
            }
          }
        }
        else {

          // Initialize delta in case there are no items in $field_data.
          $delta = -1;

          // Save regular fields.
          foreach ($field_data as $delta => $delta_data) {
            foreach ($delta_data as $property => $property_data) {
              $property_definition = $storage_definitions[$name]
                ->getPropertyDefinition($property);
              $data_type = $property_definition
                ->getDataType();
              if ($data_type === 'uri') {

                // Validate an uri.
                if (!\Drupal::pathValidator()
                  ->isValid($property_data)) {
                  \Drupal::logger('lingotek')
                    ->warning('Field %field for %type %label in language %langcode not saved, invalid uri "%uri"', [
                    '%field' => $name,
                    '%type' => $entity
                      ->getEntityTypeId(),
                    '%label' => $entity
                      ->label(),
                    '%langcode' => $langcode,
                    '%uri' => $property_data,
                  ]);

                  // Let's default to the original value given that there was a problem.
                  $property_data = $revision
                    ->get($name)
                    ->offsetGet($delta)->{$property};
                }
              }
              if ($translation
                ->get($name)
                ->offsetExists($delta) && method_exists($translation
                ->get($name)
                ->offsetGet($delta), "set")) {
                $translation
                  ->get($name)
                  ->offsetGet($delta)
                  ->set($property, html_entity_decode($property_data));
              }
              elseif ($translation
                ->get($name)) {
                $translation
                  ->get($name)
                  ->appendItem()
                  ->set($property, html_entity_decode($property_data));
              }
            }
          }

          // Remove the rest of deltas that were no longer found in the document downloaded from lingotek.
          $continue = TRUE;
          while ($continue) {
            if ($translation
              ->get($name)
              ->offsetExists($delta + 1)) {
              $translation
                ->get($name)
                ->removeItem($delta + 1);
            }
            else {
              $continue = FALSE;
            }
          }
        }
      }
    }

    // We need to set the content_translation source so the files are synced
    // properly. See https://www.drupal.org/node/2544696 for more information.
    $translation
      ->set('content_translation_source', $entity
      ->getUntranslated()
      ->language()
      ->getId());
    $entity->lingotek_processed = TRUE;

    // Allow other modules to alter the translation before is saved.
    \Drupal::moduleHandler()
      ->invokeAll('lingotek_content_entity_translation_presave', [
      &$translation,
      $langcode,
      $data,
    ]);
    $status_field = $entity
      ->getEntityType()
      ->getKey('status');
    $status_field_definition = $entity
      ->getFieldDefinition($status_field);
    if ($status_field_definition !== NULL && $status_field_definition
      ->isTranslatable()) {
      $status_setting = $this->lingotekConfiguration
        ->getPreference('target_download_status');
      if ($status_setting !== "same-as-source") {
        $status_value = $status_setting === 'published' ? NodeInterface::PUBLISHED : NodeInterface::NOT_PUBLISHED;
        $translation
          ->set($status_field, $status_value);
      }
    }

    // If there is any content moderation module is enabled, we may need to
    // perform a transition in their workflow.

    /** @var \Drupal\lingotek\Moderation\LingotekModerationFactoryInterface $moderation_factory */
    $moderation_factory = \Drupal::service('lingotek.moderation_factory');
    $moderation_handler = $moderation_factory
      ->getModerationHandler();
    $moderation_handler
      ->performModerationTransitionIfNeeded($translation);
    if ($moderation_handler
      ->isModerationEnabled($translation) && $translation
      ->getEntityType()
      ->isRevisionable()) {
      if ($bundle_entity_type = $entity
        ->getEntityType()
        ->getBundleEntityType()) {
        $bundle_entity = $this->entityTypeManager
          ->getStorage($bundle_entity_type)
          ->load($entity
          ->bundle());
        if ($bundle_entity instanceof RevisionableEntityBundleInterface) {
          $translation
            ->setNewRevision($bundle_entity
            ->shouldCreateNewRevision());
        }
      }
      if ($translation instanceof RevisionLogInterface && $translation
        ->isNewRevision()) {
        $requestTime = \Drupal::time()
          ->getRequestTime();
        $translation
          ->setRevisionUserId(\Drupal::currentUser()
          ->id());
        $translation
          ->setRevisionCreationTime($requestTime);
        $translation
          ->setRevisionLogMessage((string) new FormattableMarkup('Document translated into @langcode by Lingotek.', [
          '@langcode' => strtoupper($langcode),
        ]));
      }
    }
    $translation
      ->save();
    return $entity;
  } catch (EntityStorageException $storage_exception) {
    $this
      ->setTargetStatus($entity, $langcode, Lingotek::STATUS_ERROR);
    throw new LingotekContentEntityStorageException($entity, $storage_exception, $storage_exception
      ->getMessage());
  }
}