You are here

entity_translation_unified_form.module in Entity Translation Unified Form 8

Same filename and directory in other branches
  1. 7 entity_translation_unified_form.module

File

entity_translation_unified_form.module
View source
<?php

/**
 * @file
 */
use Drupal\content_translation\BundleTranslationSettingsInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\entity_translation_unified_form\EtufHelper;
use Drupal\field\Entity\FieldStorageConfig;
define('ENTITY_TRANSLATION_ENABLED', 4);

/**
 * @file
 * Places entity translated fields inline in a single form.
 */

/**
 * Place our form_alter at the end (after content_translation) to prevent bad
 * interaction with this module (title problems)
 */
function entity_translation_unified_form_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'form_alter' && isset($implementations['entity_translation_unified_form'])) {

    // Move this module's implementation of form_alter to the end of the list.
    // We are doing this so that the form_node_page_form_alter
    // function is called AFTER ContentTranslationHandler::entityFormAlter
    // which contains the code we are trying to alter.
    $hookInit = $implementations['entity_translation_unified_form'];
    unset($implementations['entity_translation_unified_form']);
    $implementations['entity_translation_unified_form'] = $hookInit;
  }
}

/**
 * Add a class only if the page is in add or edit mode.
 */
function entity_translation_unified_form_preprocess_html(&$variables) {
  $current_path = \Drupal::service('path.current')
    ->getPath();
  $patterns = "/node/add/*\n/node/*/edit";
  $match = \Drupal::service('path.matcher')
    ->matchPath($current_path, $patterns);
  if (!empty($match)) {
    $variables['attributes']['class'][] = 'etuf-sbs';

    // For css.
    $variables['attributes']['class'][] = 'sync';

    // For sync js.
  }
}

/**
 * Implements hook_page_attachments().
 *
 * Adds the libraries to only the edit node and add node page.
 */
function entity_translation_unified_form_page_attachments(array &$page) {
  $current_path = \Drupal::service('path.current')
    ->getPath();
  $patterns = "/node/add/*\n/node/*/edit";
  $match = \Drupal::service('path.matcher')
    ->matchPath($current_path, $patterns);
  if (!empty($match)) {
    $bundle = '';
    if (strpos($current_path, '/edit') > 4) {

      // Get the node object.
      $node = \Drupal::routeMatch()
        ->getParameter('node');
      $bundle = $node
        ->bundle();
    }
    else {

      // Get the bundle.
      $array_of_segments = explode('/', $current_path);
      $bundle = end($array_of_segments);
    }
    if (entity_translation_unified_form_sbs_enabled('node', $bundle)) {

      // Get the CSS for the current theme
      $theme = \Drupal::service('theme.manager')
        ->getActiveTheme()
        ->getName();
      if (file_exists(drupal_get_path('module', 'entity_translation_unified_form') . "/css/etuf-side-by-side-{$theme}.css")) {
        $page['#attached']['library'][] = 'entity_translation_unified_form/etuf-' . $theme;
      }
      else {

        // Default theme
        $page['#attached']['library'][] = 'entity_translation_unified_form/etuf';
      }
      $other_languages = EtufHelper::getOtherEnabledLanguages();
      foreach ($other_languages as $other_langcode => $other_language) {
        $page['#attached']['drupalSettings']['other_langs'][] = $other_langcode;
      }
    }
    if (!entity_translation_unified_form_moderation_sync_disabled('node', $bundle)) {
      $page['#attached']['library'][] = 'entity_translation_unified_form/etuf-moderation-sync';
      $other_languages = EtufHelper::getOtherEnabledLanguages();
      foreach ($other_languages as $other_langcode => $other_language) {
        $page['#attached']['drupalSettings']['other_langs'][] = $other_langcode;
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add checkbox to node type form to set whether or not the node type should enable unified forms.
 */
function entity_translation_unified_form_form_node_type_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#process'][] = 'entity_translation_unified_form_form_node_type_form_process';
  $form['actions']['submit']['#submit'][] = 'entity_translation_unified_form_form_node_type_form_submit';
}

/**
 * Add an "enable" checkbox to the node type's multilingual settings.
 */
function entity_translation_unified_form_form_node_type_form_process(&$form, $form_state) {
  $entity_type_id = 'node';
  $bundle = $form['type']['#default_value'];

  // Hide settings when entity translation is disabled for this content type.
  $states = [
    'visible' => [
      ':input[name="language_content_type"]' => [
        'value' => ENTITY_TRANSLATION_ENABLED,
      ],
    ],
  ];
  $form['workflow']['entity_translation_unified_form'] = [
    '#title' => t('Unified form'),
    '#type' => 'fieldset',
    '#weight' => 10,
    '#states' => $states,
  ];
  $form['workflow']['entity_translation_unified_form']['entity_translation_unified_form_enable'] = [
    '#title' => t('Place all content-translatable fields for all enabled languages inline on the node add/edit form'),
    '#type' => 'checkbox',
    '#default_value' => $form["#id"] === 'node-type-add-form' ? 0 : entity_translation_unified_form_bundle_enabled($entity_type_id, $bundle),
    '#disabled' => FALSE,
    '#states' => $states,
  ];
  $form['workflow']['entity_translation_unified_form']['entity_translation_unified_form_sbs_enable'] = [
    '#title' => t('Enable side-by-side UI mode on the node add/edit form'),
    '#type' => 'checkbox',
    '#default_value' => $form["#id"] === 'node-type-add-form' ? 0 : entity_translation_unified_form_sbs_enabled($entity_type_id, $bundle),
    '#disabled' => FALSE,
    '#states' => $states,
  ];
  $form['workflow']['entity_translation_unified_form']['entity_translation_unified_form_moderation_sync_disable'] = [
    '#title' => t('Disable moderation sync mode on the node add/edit form'),
    '#type' => 'checkbox',
    '#default_value' => $form["#id"] === 'node-type-add-form' ? 0 : entity_translation_unified_form_moderation_sync_disabled($entity_type_id, $bundle),
    '#disabled' => FALSE,
    '#states' => $states,
  ];
  return $form;
}

/**
 * Submit handler. Sets content type-specific variable that is used to determine whether or not the content type may used unified forms.
 */
function entity_translation_unified_form_form_node_type_form_submit(&$form, FormStateInterface $form_state) {
  $entity_type_id = 'node';
  $bundle = $form_state
    ->getValues()['type'];
  $enabled = $form_state
    ->getValues()['entity_translation_unified_form_enable'];
  entity_translation_unified_form_set_bundle_enabled($entity_type_id, $bundle, $enabled);
  $enabled = $form_state
    ->getValues()['entity_translation_unified_form_sbs_enable'];
  entity_translation_unified_form_set_sbs_enabled($entity_type_id, $bundle, $enabled);
  $enabled = $form_state
    ->getValues()['entity_translation_unified_form_moderation_sync_disable'];
  entity_translation_unified_form_set_moderation_sync_disabled($entity_type_id, $bundle, $enabled);
  $enabled = $form_state
    ->getValues()['entity_translation_unified_form_translate_labels'];
  entity_translation_unified_form_set_translate_labels_enabled($entity_type_id, $bundle, $enabled);
}

/**
 * Sets the configuration for a given bundle.
 */
function entity_translation_unified_form_set_bundle_enabled($entity_type_id, $bundle, $enabled) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    $settings['entity_translation_unified_form_enable'] = $enabled;
    $content_translation_manager
      ->setBundleTranslationSettings($entity_type_id, $bundle, $settings);
  }
}

/**
 * Returns true if ETUF is enabled for a given bundle.
 */
function entity_translation_unified_form_bundle_enabled($entity_type_id, $bundle) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    return !empty($settings['entity_translation_unified_form_enable']);
  }
  return FALSE;
}

/**
 * Sets the configuration for a given bundle.
 */
function entity_translation_unified_form_set_sbs_enabled($entity_type_id, $bundle, $enabled) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    $settings['entity_translation_unified_form_sbs_enable'] = $enabled;
    $content_translation_manager
      ->setBundleTranslationSettings($entity_type_id, $bundle, $settings);
  }
}

/**
 * Sets the configuration for a given bundle.
 */
function entity_translation_unified_form_set_moderation_sync_disabled($entity_type_id, $bundle, $enabled) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    if (isset($settings['entity_translation_unified_form_moderation_sync_disable'])) {
      $settings['entity_translation_unified_form_moderation_sync_disable'] = $enabled;
    }
    else {
      $settings['entity_translation_unified_form_moderation_sync_disable'] = FALSE;
    }
    $content_translation_manager
      ->setBundleTranslationSettings($entity_type_id, $bundle, $settings);
  }
}

/**
 * Returns true if ETUF sbs is enabled for a given bundle.
 */
function entity_translation_unified_form_sbs_enabled($entity_type_id, $bundle) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    return !empty($settings['entity_translation_unified_form_sbs_enable']);
  }
  return FALSE;
}

/**
 * Sets the configuration for a given bundle.
 */
function entity_translation_unified_form_set_translate_labels_enabled($entity_type_id, $bundle, $enabled) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    $settings['entity_translation_unified_form_translate_labels'] = $enabled;
    $content_translation_manager
      ->setBundleTranslationSettings($entity_type_id, $bundle, $settings);
  }
}

/**
 * Returns true if translate labels is enabled for a given bundle.
 */
function entity_translation_unified_form_translate_labels_enabled($entity_type_id, $bundle) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    return !empty($settings['entity_translation_unified_form_translate_labels']);
  }
  return FALSE;
}

/**
 * Returns true if moderation sync mode is disabled for a given bundle.
 */
function entity_translation_unified_form_moderation_sync_disabled($entity_type_id, $bundle) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    return !empty($settings['entity_translation_unified_form_moderation_sync_disable']);
  }
  return FALSE;
}

/**
 * Returns the display mode for a given bundle.
 */
function entity_translation_unified_form_bundle_display_mode($entity_type_id, $bundle) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    if (!empty($settings['entity_translation_unified_form_theme'])) {
      return $settings['entity_translation_unified_form_theme'];
    }
  }
  return NULL;
}

/**
 * Returns the language display mode for a given bundle
 */
function entity_translation_unified_form_language_display($entity_type_id, $bundle) {

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  if ($content_translation_manager instanceof BundleTranslationSettingsInterface) {
    $settings = $content_translation_manager
      ->getBundleTranslationSettings($entity_type_id, $bundle);
    if (!empty($settings['entity_translation_unified_form_language'])) {
      return $settings['entity_translation_unified_form_language'];
    }
  }
  return NULL;
}

/**
 * Returns the different display modes for the language part
 */
function entity_translation_unified_form_get_language_display_options() {

  // TODO: make constants rather than strings
  return [
    'current' => t('Current language'),
    'native' => t('Native language'),
    'code' => t('Language code'),
  ];
}

/**
 * Gather the different modes from EntityTranslationUnifiedFormMode plugins,
 *  in an id => label array.
 */
function entity_translation_unified_form_get_mode_options() {
  $mode_options =& drupal_static(__FUNCTION__);
  if (empty($mode_options)) {
    $type = \Drupal::service('plugin.manager.entity_translation_unified_form_mode');
    $plugin_definitions = $type
      ->getDefinitions();
    $mode_options = [];
    foreach ($plugin_definitions as $definition) {
      $mode_id = $definition['id'];
      $mode_options[$mode_id] = $definition['admin_label'];
    }
  }
  return $mode_options;
}

/**
 * Get a EntityTranslationUnifiedFormMode plugin instance by its id.
 */
function entity_translation_unified_form_get_mode_plugin($mode_plugin_id) {
  $type = \Drupal::service('plugin.manager.entity_translation_unified_form_mode');
  $plugin_definitions = $type
    ->getDefinitions();
  foreach ($plugin_definitions as $classname => $definition) {
    if ($mode_plugin_id == $definition['id']) {
      return $type
        ->createInstance($classname);
    }
  }
  return NULL;
}

/**
 * Implements hook_form_form_language_content_settings_form_alter().
 *
 * Add the "Enable ETUF" checkbox to the content language page: admin/config/regional/content-language.
 */
function entity_translation_unified_form_form_language_content_settings_form_alter(&$form, FormStateInterface $form_state) {

  // Inject into the content language settings the translation settings if the
  // user has the required permission.
  if (!\Drupal::currentUser()
    ->hasPermission('administer content translation')) {
    return;
  }

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
  $content_translation_manager = \Drupal::service('content_translation.manager');
  $entity_manager = \Drupal::entityTypeManager();
  $bundle_info_service = \Drupal::service('entity_type.bundle.info');
  foreach ($form['#labels'] as $entity_type_id => $label) {
    $entity_type = $entity_manager
      ->getDefinition($entity_type_id);
    $entity_type_translatable = $content_translation_manager
      ->isSupported($entity_type_id);
    if ($entity_type_translatable) {
      foreach ($bundle_info_service
        ->getBundleInfo($entity_type_id) as $bundle => $bundle_info) {
        $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_enable'] = [
          '#title' => t('Place all content-translatable fields for all enabled languages inline on the entity add/edit form'),
          '#type' => 'checkbox',
          '#default_value' => entity_translation_unified_form_bundle_enabled($entity_type_id, $bundle),
          '#states' => [
            'visible' => [
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                'checked' => TRUE,
              ],
            ],
          ],
        ];
        $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_theme'] = [
          '#title' => t('Select the inline display mode'),
          '#type' => 'select',
          '#default_value' => entity_translation_unified_form_bundle_display_mode($entity_type_id, $bundle),
          '#options' => entity_translation_unified_form_get_mode_options(),
          '#states' => [
            'visible' => [
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                'checked' => TRUE,
              ],
              'and',
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]' => [
                'checked' => TRUE,
              ],
            ],
          ],
        ];
        $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_language'] = [
          '#title' => t('Select how to display language name'),
          '#type' => 'select',
          '#default_value' => entity_translation_unified_form_language_display($entity_type_id, $bundle),
          '#options' => entity_translation_unified_form_get_language_display_options(),
          '#states' => [
            'visible' => [
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]' => [
                'checked' => TRUE,
              ],
              'and',
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_theme]"]' => [
                'value' => 'EntityTranslationUnifiedFormInlineMode',
              ],
              'and',
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                'checked' => TRUE,
              ],
            ],
          ],
        ];
        $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_translate_labels'] = [
          '#title' => t('Translate fields labels and descriptions in each language'),
          '#type' => 'checkbox',
          '#default_value' => entity_translation_unified_form_translate_labels_enabled($entity_type_id, $bundle),
          '#states' => [
            'visible' => [
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]' => [
                'checked' => TRUE,
              ],
              'and',
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_theme]"]' => [
                'value' => 'EntityTranslationUnifiedFormInlineMode',
              ],
              'and',
              ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                'checked' => TRUE,
              ],
            ],
          ],
        ];
        if ($entity_type_id == 'node') {
          $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_sbs_enable'] = [
            '#title' => t('Enable side-by-side UI mode on the node add/edit form'),
            '#type' => 'checkbox',
            '#default_value' => entity_translation_unified_form_sbs_enabled('node', $bundle),
            '#states' => [
              'visible' => [
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                  'checked' => TRUE,
                ],
                'and',
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]' => [
                  'checked' => TRUE,
                ],
              ],
            ],
          ];
        }
        if ($entity_type_id == 'node') {
          $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_moderation_sync_disable'] = [
            '#title' => t('Disable moderation sync mode on the node add/edit form for this bundle'),
            '#type' => 'checkbox',
            '#default_value' => entity_translation_unified_form_moderation_sync_disabled('node', $bundle),
            '#states' => [
              'visible' => [
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                  'checked' => TRUE,
                ],
              ],
            ],
          ];
        }
      }
    }
  }
}

/**
 * Add language fields to node forms.
 *
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function entity_translation_unified_form_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form_object = $form_state
    ->getFormObject();
  if (!$form_object instanceof EntityForm) {
    return;
  }
  $entity = $form_object
    ->getEntity();
  $entity_type_id = $entity
    ->getEntityTypeId();
  $bundle = $entity
    ->bundle();
  if (!empty($entity) && entity_translation_unified_form_bundle_enabled($entity_type_id, $bundle)) {

    // Inject our submit handler immediately before the entity save function
    // If we don't find the save function, don't do anything.
    $key = array_search('::save', $form['actions']['submit']['#submit']);
    if (isset($form['actions']['preview'])) {
      $keyp = array_search('::preview', $form['actions']['preview']['#submit']);
    }
    if ($key !== FALSE) {
      array_splice($form['actions']['submit']['#submit'], $key, 0, 'entity_translation_unified_form_node_form_submit');
      if (isset($form['actions']['preview'])) {
        array_splice($form['actions']['preview']['#submit'], $keyp, 0, 'entity_translation_unified_form_node_form_preview');
      }

      // Add entity translation form elements for unified language node form.
      entity_translation_unified_form_add_fields($form, $form_state);
    }
  }
}

/**
 * Add opposite-language ET fields to a form.
 */
function entity_translation_unified_form_add_fields(&$form, FormStateInterface $form_state) {
  $form_state
    ->loadInclude('entity_translation_unified_form', 'inc', 'entity_translation_unified_form.theme');
  $form_object = $form_state
    ->getFormObject();
  if ($form_object instanceof EntityForm) {
    $entity = $form_object
      ->getEntity();
    $entity_type = $entity
      ->getEntityTypeId();
    $bundle = $entity
      ->bundle();
    $entityManager = \Drupal::service('entity_field.manager');
    $fields = $entityManager
      ->getFieldDefinitions($entity_type, $bundle);
    $mode_plugin_id = entity_translation_unified_form_bundle_display_mode($entity_type, $bundle);
    if ($mode_plugin_id != NULL) {

      // If side-by-side selected only Inline plugin is allowed (note: should be treated at config level, not here)
      $sbs = entity_translation_unified_form_sbs_enabled($entity_type, $bundle);
      if ($sbs) {
        $mode_plugin_id = 'EntityTranslationUnifiedFormInlineMode';
      }
      $mode_plugin = entity_translation_unified_form_get_mode_plugin($mode_plugin_id);

      // Process each of the entity type's fields.
      foreach ($fields as $field_name => $field_definition) {
        entity_translation_unified_form_node_insert_other_language_fields($form, $form_state, $field_definition, $mode_plugin);
      }
    }
  }
}

/**
 * Instanciate one value (for default_value)
 */
function entity_translation_unified_form_def_value($val, $mono = false) {
  if ($mono) {
    return $val;
  }
  if (!is_array($val)) {
    return $val;
  }
  if (isset($val['date'])) {
    return $val['date'];

    // date only needs date object
  }
  if (count($val) == 1) {
    return current($val);
  }

  // this probably wont work in all cases
  return $val;
}

/**
 * Create a field definition from the existing one. Checks about the fields should have been
 * done before calling this
 */
function entity_translation_unified_form_build_field($form, $form_state, $entity, $entity_type, $bundle, $field_name, $langcode) {
  $language_manager = \Drupal::languageManager();
  $initial_language = $language_manager
    ->getConfigOverrideLanguage();
  $translate_labels = entity_translation_unified_form_translate_labels_enabled($entity_type, $bundle);

  // force language
  if ($translate_labels) {
    $language_manager
      ->setConfigOverrideLanguage($language_manager
      ->getLanguage($langcode));
    \Drupal::service("entity_field.manager")
      ->clearCachedFieldDefinitions();
  }

  // get data for language
  if ($entity
    ->hasTranslation($langcode)) {
    $entity = $entity
      ->getTranslation($langcode);
  }
  else {
    $entity = $entity
      ->addTranslation($langcode);
  }
  $form_display = EntityFormDisplay::collectRenderDisplay($entity, 'default');

  // get the items depending of the $entity
  if ($entity
    ->hasTranslation($langcode)) {
    if ($entity_type == 'node' && $entity
      ->isLatestRevision()) {

      // @todo Simplify this code that was written without sleep, for now, holding my nose.
      // LatestRevision default language is not the same revision id as other lang or vice versa.
      // Might want to add a check to see if content_moderation is activated for this content type.
      $storage = \Drupal::entityTypeManager()
        ->getStorage($entity_type);
      if (!empty($entity
        ->id())) {
        $latestTranslationAffectedRevisionId = $storage
          ->getLatestTranslationAffectedRevisionId($entity
          ->id(), $langcode);
        if (is_numeric($latestTranslationAffectedRevisionId)) {
          $entityOtherLangLatestRevision = $storage
            ->loadRevision($latestTranslationAffectedRevisionId);
        }
      }
      if (empty($entityOtherLangLatestRevision)) {
        $definition = $entity
          ->getFieldDefinition($field_name);
        if (isset($definition) && $definition
          ->isTranslatable()) {
          $items = $entity
            ->getTranslation($langcode)
            ->get($field_name);
        }
        else {
          $items = $entity
            ->get($field_name);
        }
      }
      else {
        $definitionLatest = $entityOtherLangLatestRevision
          ->getFieldDefinition($field_name);
        if (!empty($definitionLatest
          ->getType()) && $definitionLatest
          ->isTranslatable()) {

          // Now get the latest revision of $other_langcode.
          $items = $entityOtherLangLatestRevision
            ->getTranslation($langcode)
            ->get($field_name);
        }
        else {
          $items = $entityOtherLangLatestRevision
            ->get($field_name);
        }
      }
    }
    else {
      $items = $entity
        ->getTranslation($langcode)
        ->get($field_name);
    }
  }
  else {
    $items = $entity
      ->addTranslation($langcode)
      ->get($field_name);
  }
  $widget = $form_display
    ->getRenderer($field_name);
  if (empty($widget)) {

    // restore language
    if ($translate_labels) {
      $language_manager
        ->setConfigOverrideLanguage($initial_language);
      \Drupal::service("entity_field.manager")
        ->clearCachedFieldDefinitions();
    }
    return [];
  }
  $field_form = $widget
    ->form($items, $form, $form_state);

  // manage default value (because Drupal is not able to set the default_value that matches the
  // forced language, so it has to be done by hand…). This is probably incomplete.
  if ($entity
    ->isNew()) {

    // get default value (at least 'title' field don't have any definition)
    if (!$translate_labels) {

      // default value must come with forced language
      $language_manager
        ->setConfigOverrideLanguage($language_manager
        ->getLanguage($langcode));
      \Drupal::service("entity_field.manager")
        ->clearCachedFieldDefinitions();
    }
    $field_definition = \Drupal\field\Entity\FieldConfig::loadByName($entity_type, $bundle, $field_name);
    if ($field_definition) {
      $def = $field_definition
        ->getDefaultValue($entity);
    }
    else {
      $def = [];
    }
    if (!$translate_labels) {
      $language_manager
        ->setConfigOverrideLanguage($initial_language);
      \Drupal::service("entity_field.manager")
        ->clearCachedFieldDefinitions();
    }
    if (isset($def) and !empty($def)) {
      if (isset($field_form['widget']['#default_value'])) {
        $field_form['widget']['#default_value'] = entity_translation_unified_form_def_value($def, true);
      }
      else {
        foreach ($def as $idx => $cont) {
          if (isset($field_form['widget'][$idx]['value'])) {
            if (!empty($cont)) {
              $field_form['widget'][$idx]['value']['#default_value'] = entity_translation_unified_form_def_value($cont);
            }
          }
        }
      }
    }
  }

  // restore language
  if ($translate_labels) {
    $language_manager
      ->setConfigOverrideLanguage($initial_language);
    \Drupal::service("entity_field.manager")
      ->clearCachedFieldDefinitions();
  }
  return $field_form;
}

/**
 * Add all enabled language fields for a single field.
 */
function entity_translation_unified_form_node_insert_other_language_fields(&$form, &$form_state, $field_definition, $mode_plugin) {
  $language_manager = \Drupal::languageManager();
  $language = $language_manager
    ->getCurrentLanguage();
  $form_object = $form_state
    ->getFormObject();
  $entity = NULL;
  if ($form_object instanceof EntityForm) {
    $entity = $form_object
      ->getEntity();
    $entity_type = $entity
      ->getEntityTypeId();
    $bundle = $entity
      ->bundle();
    $sbs = entity_translation_unified_form_sbs_enabled($entity_type, $bundle);
    $field_name = $field_definition
      ->getName();
    $field = FieldStorageConfig::loadByName($entity_type, $field_name);
    $form_display = EntityFormDisplay::collectRenderDisplay($entity, 'default');
    $display_options = $field_definition
      ->getDisplayOptions('form');
    $hidden = empty($display_options) || isset($display_options['type']) && $display_options['type'] == 'hidden';

    // Only process entity-translatable fields.
    if ($field_definition
      ->isTranslatable() && !$hidden) {
      $other_languages = EtufHelper::getOtherEnabledLanguages();
      foreach ($other_languages as $other_langcode => $other_language) {
        $current_language = $language_manager
          ->getLanguage($other_langcode);

        // Get the field definition for this language
        $field_form = entity_translation_unified_form_build_field($form, $form_state, $entity, $entity_type, $bundle, $field_name, $other_langcode);

        // Build and attach the translated field.
        if (!empty($field_form)) {
          $field_form['widget']['#field_name'] = $field_name . '-etuf-' . $other_langcode;

          // Update the parents array.
          if (!is_array($field_form['widget']['#parents'])) {
            $field_form['widget']['#parents'] = [];
          }
          $field_form['widget']['#parents'] = [];
          $field_form['widget']['#parents'][] = $field_form['widget']['#field_name'];

          // Update the "Add another item" button's name.
          if (isset($field_form['widget']['add_more'])) {
            $field_form['widget']['add_more']['#name'] = $field_form['widget']['#field_name'] . '_add_more';
          }

          // Add the language to the render array, for additional information.
          $field_form['#etuf_field_language'] = $current_language;

          // Add the language field's theme wrapper, if any.
          $field_wrapper = $mode_plugin
            ->getFieldThemeWrapper($form, $form_state, $field_form, $field_name, $current_language);
          if (!empty($field_wrapper)) {
            $field_form['#theme_wrappers'][] = $field_wrapper;
          }

          // Give plugins a chance to alter the language field.
          $mode_plugin
            ->fieldformAlter($form, $form_state, $field_form, $field_name, $current_language);

          // Add the new field to the form.
          $form[$field_name][$other_langcode] = $field_form;
        }
      }

      // Mark this field as a multilingual field
      // Without this, Content Translation will incorrectly add the "all languages" hints.
      $form[$field_name]['#multilingual'] = TRUE;

      // Add the language to the render array, for additional information.
      $form[$field_name]['#etuf_field_language'] = $language;
      if (!isset($form[$field_name]['#access'])) {
        $form[$field_name]['#access'] = NULL;
      }

      // Add CSS class to identify translated fields.
      $form[$field_name]['#attributes']['class'][] = 'etuf-translated-field';

      // Add the original language field's theme wrapper, if any.
      $field_wrapper = $mode_plugin
        ->getFieldThemeWrapper($form, $form_state, $form[$field_name], $field_name, $language);
      if (!empty($field_wrapper)) {
        $form[$field_name]['#theme_wrappers'][] = $field_wrapper;
      }

      // Give plugins a chance to alter the language field.
      $mode_plugin
        ->fieldFormAlter($form, $form_state, $form[$field_name], $field_name, $language);

      // Add a wrapper for the group of unified form fields.
      $field_group_wrapper = $mode_plugin
        ->getFieldGroupThemeWrapper($form, $form_state, $form[$field_name], $field_name);
      if (!empty($field_group_wrapper)) {
        $form[$field_name]['#theme_wrappers'][] = $field_group_wrapper;
      }
    }
    elseif (entity_translation_unified_form_sbs_enabled($entity_type, $bundle) && !$hidden) {

      // In case of side-by-side add a wrapper to prevent moving to the right in case of field height change
      if (isset($form[$field_name]['#prefix'])) {
        $form[$field_name]['#prefix'] = '<div class="etuf-sbs-none">' . $form[$field_name]['#prefix'];
      }
      else {
        $form[$field_name]['#prefix'] = '<div class="etuf-sbs-none">';
      }
      if (isset($form[$field_name]['#suffix'])) {
        $form[$field_name]['#suffix'] = $form[$field_name]['#suffix'] . '</div>';
      }
      else {
        $form[$field_name]['#suffix'] = '</div>';
      }
    }
    if (entity_translation_unified_form_sbs_enabled($entity_type, $bundle)) {
      if (!$hidden && isset($form[$field_name]['#weight'])) {
        $form['etuf-' . $field_name . '-sep'] = [
          '#markup' => '',
          '#prefix' => '<div class="etuf-sbs-none">',
          '#suffix' => '</div>',
          '#weight' => $form[$field_name]['#weight'],
        ];
      }
    }
  }
}

/**
 * Form submission handler for node_form_preview().
 *
 * Configure entity translation node object for entity_translation_unified_form.
 */
function entity_translation_unified_form_node_form_preview(array $form, FormStateInterface $form_state) {
  $language = \Drupal::languageManager()
    ->getCurrentLanguage();
  $langcode = $language
    ->getId();
  $other_languages = EtufHelper::getOtherEnabledLanguages();
  $form_object = $form_state
    ->getFormObject();
  $entity = NULL;
  if ($form_object instanceof EntityForm) {
    $entity = $form_object
      ->getEntity();
    $entity_type = $entity
      ->getEntityTypeId();
    $bundle = $entity
      ->bundle();
    $entityManager = \Drupal::service('entity_field.manager');
    $fields = $entityManager
      ->getFieldDefinitions($entity_type, $bundle);

    // Process the translated values.
    $values = $form_state
      ->getValues();
    $stateOtherLang = '';
    foreach ($other_languages as $other_langcode => $other_language) {

      // Get the existing translation, or create one if it doesn't currently exist.
      $action = 'add';
      if ($entity
        ->hasTranslation($other_langcode)) {
        $action = 'update';
        $translation = $entity
          ->getTranslation($other_langcode);
      }
      else {
        $translation = $entity
          ->addTranslation($other_langcode);
      }
      $translation
        ->setRevisionTranslationAffected(TRUE);
      foreach ($fields as $field_name => $field_definition) {
        $etuf_name = $field_name . '-etuf-' . $other_langcode;
        $field_type = $field_definition
          ->getType();

        // Copy the translated values from form_state to the entity translation.
        if (isset($values[$etuf_name])) {
          if ($field_type == 'metatag' && isset($values[$etuf_name])) {

            // Begin processing form for metatags into the expected format.
            $metatags_from_form = $values[$etuf_name];
            $metatags_reset_form = reset($metatags_from_form);
            $metatags_prep = [];
            foreach ($metatags_reset_form as $outer_key => $metatags_part) {
              if (is_array($metatags_part)) {
                foreach ($metatags_part as $key => $value) {

                  // Flatten metatags to key=>value.
                  $metatags_prep[$key] = $value;
                }
              }
            }

            // End of metatag transformation, now serialize.
            $metatags_serialized = serialize($metatags_prep);

            // Save the serialized metatags to the field.
            $translation
              ->set($field_name, $metatags_serialized);
          }
          elseif ($field_name == 'created' && $field_type == 'created') {

            // Fix date/time bug #3117164.
            // Part 1/4 fix date/time bug #3117164, would otherwise be 1970, copy from source.
            $dateObj = $values[$etuf_name][0]['value'];
            $translation
              ->set($field_name, $dateObj
              ->getTimestamp());
          }
          elseif ($field_type == 'image') {

            // Special treatment for managed files, not sure why? (core bug workaround?).
            if (isset($values[$etuf_name][0]['fids'][0])) {
              $numberOfFiles = count($values[$etuf_name]);
              if ($numberOfFiles == 1) {

                // Just one file/image to fix, otherwise seems ok.
                if (!isset($values[$etuf_name][0]['target_id'])) {
                  $values[$etuf_name][0]['target_id'] = $values[$etuf_name][0]['fids'][0];
                  unset($values[$etuf_name][0]['fids']);
                }
              }
              elseif ($numberOfFiles > 1) {
                for ($i = 0; $i < $numberOfFiles; $i++) {
                  if (!isset($values[$etuf_name][$i]['target_id']) && isset($values[$etuf_name][$i]['fids'][0])) {
                    $values[$etuf_name][$i]['target_id'] = $values[$etuf_name][$i]['fids'][0];
                    unset($values[$etuf_name][$i]['fids']);
                  }
                }
              }
            }
            $translation
              ->set($field_name, $values[$etuf_name]);
          }
          elseif (isset($field_name) && !is_null($translation)) {

            // Default.
            $translation
              ->set($field_name, $values[$etuf_name]);
          }
          elseif ($field_name == 'created' && $field_type == 'created' && isset($values[$field_name])) {

            // Fix date/time bug #3117164.
            // Part 2/4 fix date/time bug #3117164, would otherwise be 1970, copy from source.
            $dateObj = $values[$field_name][0]['value'];
            if (!is_null($dateObj)) {
              $translation
                ->set($field_name, $dateObj
                ->getTimestamp());
            }
          }
          elseif (isset($translation) && $field_name == 'revision_timestamp') {

            // Part 3/4 fix date/time bug #3117164, would otherwise be NULL.
            // $values[$field_name] = \Drupal::time()->getCurrentTime();
            $values[$etuf_name] = \Drupal::time()
              ->getCurrentTime();
          }
          elseif (isset($translation) && $field_name == 'changed' && $field_type == 'changed') {

            // Part 4/4 fix date/time bug #3117164, would otherwise be NULL.
            $values[$etuf_name] = \Drupal::time()
              ->getCurrentTime();
          }
        }
      }

      // End of foreach field_definition.
      if (!isset($once_only)) {
        $once_only = TRUE;
        if (!empty($stateOtherLang)) {

          // Content Moderation is enabled.
          // We must set this flag otherwise the translated revisions do not get the correct worfklow state.
          $entity
            ->setRevisionTranslationAffected(TRUE);
          $entity
            ->setChangedTime(time());
        }
      }

      // Fill in title, if it isn't set.
      if (method_exists($translation, 'getTitle') && empty($translation
        ->getTitle())) {
        $title = $entity
          ->getTitle();
        $translation
          ->setTitle($title);
      }
    }
  }
}

/**
 * Form submission handler for node_form().
 *
 * Configure entity translation node object for entity_translation_unified_form.
 */
function entity_translation_unified_form_node_form_submit(array $form, FormStateInterface $form_state) {
  $language = \Drupal::languageManager()
    ->getCurrentLanguage();
  $langcode = $language
    ->getId();
  $other_languages = EtufHelper::getOtherEnabledLanguages();
  $form_object = $form_state
    ->getFormObject();
  $entity = NULL;
  if ($form_object instanceof EntityForm) {
    $entity = $form_object
      ->getEntity();
    $entity_type = $entity
      ->getEntityTypeId();
    $bundle = $entity
      ->bundle();
    $entityManager = \Drupal::service('entity_field.manager');
    $fields = $entityManager
      ->getFieldDefinitions($entity_type, $bundle);

    // Process the translated values.
    $values = $form_state
      ->getValues();
    if ($entity instanceof RevisionLogInterface) {
      $lastRevisionLogMessage[$langcode] = $entity
        ->getRevisionLogMessage();
    }
    $stateOtherLang = '';
    foreach ($other_languages as $other_langcode => $other_language) {
      if ($entity instanceof RevisionLogInterface) {
        $lastRevisionLogMessage[$other_langcode] = $entity->revision_log->value;
      }

      // Get the existing translation, or create one if it doesn't currently exist.
      $action = 'add';
      if ($entity
        ->hasTranslation($other_langcode)) {
        $action = 'update';
        $translation = $entity
          ->getTranslation($other_langcode);
      }
      else {
        $translation = $entity
          ->addTranslation($other_langcode);
      }
      foreach ($fields as $field_name => $field_definition) {
        $etuf_name = $field_name . '-etuf-' . $other_langcode;
        $field_type = $field_definition
          ->getType();

        // Copy the translated values from form_state to the entity translation.
        if (isset($values[$etuf_name])) {
          if ($field_type == 'metatag' && isset($values[$etuf_name])) {

            // Begin processing form for metatags into the expected format.
            $metatags_from_form = $values[$etuf_name];
            $metatags_reset_form = reset($metatags_from_form);
            $metatags_prep = [];
            foreach ($metatags_reset_form as $outer_key => $metatags_part) {
              if (is_array($metatags_part)) {
                foreach ($metatags_part as $key => $value) {

                  // Flatten metatags to key=>value.
                  $metatags_prep[$key] = $value;
                }
              }
            }

            // End of metatag transformation, now serialize.
            $metatags_serialized = serialize($metatags_prep);

            // Save the serialized metatags to the field.
            $translation
              ->set($field_name, $metatags_serialized);
          }
          elseif ($field_name == 'moderation_state') {

            // Handle moderation_state value.
            $moderationArray = reset($values[$etuf_name]);
            $stateOtherLang = $moderationArray['value'];
            $translation
              ->getTranslation($other_langcode)
              ->set($field_name, $stateOtherLang);
          }
          elseif ($field_name == 'created' && $field_type == 'created') {

            // Fix date/time bug #3117164.
            // Part 1/4 fix date/time bug #3117164, would otherwise be 1970, copy from source.
            $dateObj = $values[$etuf_name][0]['value'];
            $translation
              ->set($field_name, $dateObj
              ->getTimestamp());
          }
          elseif ($field_type == 'image') {

            // Special treatment for managed files, not sure why? (core bug workaround?).
            if (isset($values[$etuf_name][0]['fids'][0])) {
              $numberOfFiles = count($values[$etuf_name]);
              if ($numberOfFiles == 1) {

                // Just one file/image to fix, otherwise seems ok.
                if (!isset($values[$etuf_name][0]['target_id'])) {
                  $values[$etuf_name][0]['target_id'] = $values[$etuf_name][0]['fids'][0];
                  unset($values[$etuf_name][0]['fids']);
                }
              }
              elseif ($numberOfFiles > 1) {
                for ($i = 0; $i < $numberOfFiles; $i++) {
                  if (!isset($values[$etuf_name][$i]['target_id']) && isset($values[$etuf_name][$i]['fids'][0])) {
                    $values[$etuf_name][$i]['target_id'] = $values[$etuf_name][$i]['fids'][0];
                    unset($values[$etuf_name][$i]['fids']);
                  }
                }
              }
            }
            $translation
              ->set($field_name, $values[$etuf_name]);
          }
          elseif (isset($field_name) && !is_null($translation)) {

            // Default.
            $translation
              ->set($field_name, $values[$etuf_name]);
          }
          elseif ($field_name == 'created' && $field_type == 'created' && isset($values[$field_name])) {

            // Fix date/time bug #3117164.
            // Part 2/4 fix date/time bug #3117164, would otherwise be 1970, copy from source.
            $dateObj = $values[$field_name][0]['value'];
            if (!is_null($dateObj)) {
              $translation
                ->set($field_name, $dateObj
                ->getTimestamp());
            }
          }
          elseif (isset($translation) && $field_name == 'revision_timestamp') {

            // Part 3/4 fix date/time bug #3117164, would otherwise be NULL.
            // $values[$field_name] = \Drupal::time()->getCurrentTime();
            $values[$etuf_name] = \Drupal::time()
              ->getCurrentTime();
          }
          elseif (isset($translation) && $field_name == 'changed' && $field_type == 'changed') {

            // Part 4/4 fix date/time bug #3117164, would otherwise be NULL.
            $values[$etuf_name] = \Drupal::time()
              ->getCurrentTime();
          }
        }
      }

      // End of foreach field_definition.
      if (!is_null($translation)) {
        if (!empty($stateOtherLang)) {
          if ($entity instanceof RevisionLogInterface) {

            // Retrieve the most recent revision log message.
            $lastRevisionLogMessage[$other_langcode] = $translation
              ->getRevisionLogMessage();
          }

          // Set a new revision.
          $translation
            ->getTranslation($other_langcode)
            ->setNewRevision(TRUE);
          $entity
            ->getTranslation($langcode)
            ->set('moderation_state', $stateOtherLang);
          $translation
            ->getTranslation($other_langcode)
            ->set('moderation_state', $stateOtherLang);
          if ($translation instanceof RevisionLogInterface) {
            $current_uid = \Drupal::currentUser()
              ->id();
            $translation
              ->getTranslation($other_langcode)
              ->setRevisionCreationTime(\Drupal::time()
              ->getRequestTime());
            if (empty($lastRevisionLogMessage[$other_langcode])) {
              $revisionLogMsg = $lastRevisionLogMessage[$langcode];
            }
            else {
              $revisionLogMsg = $lastRevisionLogMessage[$other_langcode];
            }
            $translation
              ->getTranslation($other_langcode)
              ->setRevisionLogMessage($revisionLogMsg);
            $translation
              ->getTranslation($other_langcode)
              ->setRevisionUserId($current_uid);
          }

          // We must set this flag otherwise the translated revisions do not get the correct worfklow state.
          // Content Moderation is enabled.
          $translation
            ->setRevisionTranslationAffected(TRUE);
          $translation
            ->setChangedTime(time());
        }
        drupal_register_shutdown_function('_custom_shutdown', $translation, $other_langcode, $stateOtherLang, $langcode);
      }
      if (!isset($once_only)) {
        $once_only = TRUE;
        if (!empty($stateOtherLang)) {

          // Content Moderation is enabled.
          // We must set this flag otherwise the translated revisions do not get the correct worfklow state.
          $entity
            ->setRevisionTranslationAffected(TRUE);
          $entity
            ->setChangedTime(time());
        }
      }

      // Fill in title, if it isn't set.
      if (method_exists($translation, 'getTitle') && empty($translation
        ->getTitle())) {
        $title = $entity
          ->getTitle();
        $translation
          ->setTitle($title);
      }
    }
  }
}

/**
 * Helper function for doing stuff after shutdown function to ensure previous db transaction is committed.
 * Make sure the moderation state is processed correctly.
 * The main point of this function is to make or update an alias for the other language record if
 * it's not the same as the one that exists.
 */
function _custom_shutdown_menu($entity, $langcode) {
  $language = \Drupal::languageManager()
    ->getLanguage($langcode);
  $options = [
    'absolute' => TRUE,
    'language' => $language,
  ];
  $absolute_base_url = Url::fromRoute('<front>', [], $options)
    ->toString();
  $base_url = \Drupal::request()
    ->getBaseUrl();
  $pos_base = stripos($absolute_base_url, $base_url);
  $desired_base_url = substr($absolute_base_url, $pos_base);
  $base_url = $desired_base_url;
  if ($entity
    ->hasTranslation($langcode)) {
    $entity = $entity
      ->getTranslation($langcode);
  }
  $e_type_id = $entity
    ->getEntityTypeId();
  $path = \Drupal::service('path_alias.manager')
    ->getAliasByPath("/{$e_type_id}/" . $entity
    ->id(), $langcode);

  // Ensure base_url is used, to make this solution work for everyone.
  $path = $base_url . $path;
  $url = $entity
    ->toUrl('canonical', [], $options)
    ->toString();
  if (!is_string($url)) {
    $url = $path;
  }
  else {

    // Ensure base_url is used, to make this solution work for everyone.
    $url = $url;

    //$base_url . $url;
  }
  $debug = FALSE;
  EtufHelper::addToLog('path:' . $path, $debug);
  EtufHelper::addToLog('url:' . $url, $debug);

  // Because $path doesn't have this and we need to compare.
  $url = str_replace('/' . $langcode . '/', '/', $url);

  // Just in case, to compare path and url, give same treatment.
  $path = str_replace('/' . $langcode . '/', '/', $path);
  $test_alias = $path == "/{$e_type_id}/" . $entity
    ->id() ? TRUE : FALSE;
  $vid = 0;
  $latest_revision = etuf_latest_revision($entity
    ->id(), $vid, $langcode, $entity
    ->getEntityTypeId());

  // Ensure the alias gets updated.
  if ($test_alias || $url != $path) {
    if ($test_alias) {
      \Drupal::service('pathauto.generator')
        ->updateEntityAlias($latest_revision, 'insert', [
        'language' => $langcode,
      ]);
    }
    else {
      if ($url != $path) {
        \Drupal::service('pathauto.generator')
          ->updateEntityAlias($latest_revision, 'update', [
          'language' => $langcode,
        ]);
      }
    }
  }

  // Test plan with results.
  // New draft:.
  // select id, revision_id, langcode, path, alias from path_alias where path like '%node/3910%';
  // 9911 9911 en /node/3910 /example/english-title-1.
  // 9912 9912 fr /node/3910 /exemple/francais-titre-1.
  // Edit above draft changing title which is part of the path auto pattern:.
  // select id, revision_id, langcode, path, alias from path_alias where path like '%node/3910%';
  // 9911 9911 en /node/3910 /example/english-title-2.
  // 9912 9912 fr /node/3910 /exemple/francais-titre-2.
  // Conclusion: this code prevents duplicate alias entries and ensures all translations get their alias.
}

/**
 * Helper function for doing stuff after shutdown function to ensure previous db transaction is committed.
 * Make sure the moderation state is processed correctly.
 */
function _custom_shutdown($entity, $langcode, $moderation_state, $interfacelang) {
  $vid = 0;
  $latest_revision = etuf_latest_revision($entity
    ->id(), $vid, $langcode, $entity
    ->getEntityTypeId());
  if (!empty($moderation_state)) {
    $latest_is_valid = TRUE;
    if ($latest_revision == FALSE) {
      $latest_is_valid = FALSE;
    }
    if ($latest_is_valid) {
      $latest_revision
        ->setSyncing(TRUE);
      $latest_revision
        ->setRevisionTranslationAffected(TRUE);
      $latest_revision
        ->set('moderation_state', $moderation_state);
      $latest_revision
        ->save();
    }
  }
  drupal_register_shutdown_function('\\Drupal\\entity_translation_unified_form\\EtufHelper::postCreateOrUpdateAutoTranslate', $entity
    ->id(), $langcode);
  if ($latest_revision == FALSE) {
    drupal_register_shutdown_function('_custom_shutdown_menu', $latest_revision, $langcode);
  }
  else {
    drupal_register_shutdown_function('_custom_shutdown_menu', $entity, $langcode);
  }
}

/**
 * Register the theme_wrappers.
 *
 * Implements hook_theme().
 */
function entity_translation_unified_form_theme() {
  return [
    'entity_translation_unified_form__inline__field_wrapper' => [
      'render element' => 'element',
      'file' => 'entity_translation_unified_form.theme.inc',
    ],
    'entity_translation_unified_form__inline__wrapper' => [
      'render element' => 'element',
      'file' => 'entity_translation_unified_form.theme.inc',
    ],
    'entity_translation_unified_form__a11y_accordion_tabs__field_wrapper' => [
      'render element' => 'element',
      'file' => 'entity_translation_unified_form.theme.inc',
    ],
    'entity_translation_unified_form__a11y_accordion_tabs__wrapper' => [
      'render element' => 'element',
      'file' => 'entity_translation_unified_form.theme.inc',
    ],
  ];
}

/**
 * Retrieve the latest node revision of $lang.
 */
function etuf_latest_revision($id, &$vid, $lang, $entity_type = 'node') {
  $query = \Drupal::entityTypeManager()
    ->getStorage($entity_type)
    ->getQuery();
  $query
    ->latestRevision();
  if ($entity_type == 'node') {
    $query
      ->condition('nid', $id, '=');
  }
  if ($entity_type == 'taxonomy_term') {
    $query
      ->condition('tid', $id, '=');
  }
  if ($entity_type == 'paragraph') {
    $query
      ->condition('id', $id, '=');
  }
  if ($entity_type == 'user') {

    // Likely no moderation states for user entities anyway but just in case.
    $query
      ->condition('uid', $id, '=');
  }
  $latestRevisionResult = $query
    ->execute();
  if (count($latestRevisionResult)) {
    $node_revision_id = key($latestRevisionResult);
    $vid = $node_revision_id;
    $latestRevision = \Drupal::entityTypeManager()
      ->getStorage($entity_type)
      ->loadRevision($node_revision_id);
    if ($latestRevision
      ->hasTranslation($lang) && $latestRevision
      ->language()
      ->getId() != $lang) {
      $latestRevision = $latestRevision
        ->getTranslation($lang);
    }
    return $latestRevision;
  }
  return FALSE;
}

Functions

Namesort descending Description
entity_translation_unified_form_add_fields Add opposite-language ET fields to a form.
entity_translation_unified_form_build_field Create a field definition from the existing one. Checks about the fields should have been done before calling this
entity_translation_unified_form_bundle_display_mode Returns the display mode for a given bundle.
entity_translation_unified_form_bundle_enabled Returns true if ETUF is enabled for a given bundle.
entity_translation_unified_form_def_value Instanciate one value (for default_value)
entity_translation_unified_form_form_alter Add language fields to node forms.
entity_translation_unified_form_form_language_content_settings_form_alter Implements hook_form_form_language_content_settings_form_alter().
entity_translation_unified_form_form_node_type_form_alter Implements hook_form_FORM_ID_alter().
entity_translation_unified_form_form_node_type_form_process Add an "enable" checkbox to the node type's multilingual settings.
entity_translation_unified_form_form_node_type_form_submit Submit handler. Sets content type-specific variable that is used to determine whether or not the content type may used unified forms.
entity_translation_unified_form_get_language_display_options Returns the different display modes for the language part
entity_translation_unified_form_get_mode_options Gather the different modes from EntityTranslationUnifiedFormMode plugins, in an id => label array.
entity_translation_unified_form_get_mode_plugin Get a EntityTranslationUnifiedFormMode plugin instance by its id.
entity_translation_unified_form_language_display Returns the language display mode for a given bundle
entity_translation_unified_form_moderation_sync_disabled Returns true if moderation sync mode is disabled for a given bundle.
entity_translation_unified_form_module_implements_alter Place our form_alter at the end (after content_translation) to prevent bad interaction with this module (title problems)
entity_translation_unified_form_node_form_preview Form submission handler for node_form_preview().
entity_translation_unified_form_node_form_submit Form submission handler for node_form().
entity_translation_unified_form_node_insert_other_language_fields Add all enabled language fields for a single field.
entity_translation_unified_form_page_attachments Implements hook_page_attachments().
entity_translation_unified_form_preprocess_html Add a class only if the page is in add or edit mode.
entity_translation_unified_form_sbs_enabled Returns true if ETUF sbs is enabled for a given bundle.
entity_translation_unified_form_set_bundle_enabled Sets the configuration for a given bundle.
entity_translation_unified_form_set_moderation_sync_disabled Sets the configuration for a given bundle.
entity_translation_unified_form_set_sbs_enabled Sets the configuration for a given bundle.
entity_translation_unified_form_set_translate_labels_enabled Sets the configuration for a given bundle.
entity_translation_unified_form_theme Register the theme_wrappers.
entity_translation_unified_form_translate_labels_enabled Returns true if translate labels is enabled for a given bundle.
etuf_latest_revision Retrieve the latest node revision of $lang.
_custom_shutdown Helper function for doing stuff after shutdown function to ensure previous db transaction is committed. Make sure the moderation state is processed correctly.
_custom_shutdown_menu Helper function for doing stuff after shutdown function to ensure previous db transaction is committed. Make sure the moderation state is processed correctly. The main point of this function is to make or update an alias for the other language record…

Constants