entity_translation_unified_form-2.0.x-dev/entity_translation_unified_form.module

entity_translation_unified_form.module
<?php

/**
 * @file
 * Provides unified entity translation form functionality.
 */

use Drupal\Core\Url;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\Core\Access\AccessResultForbidden;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\entity_translation_unified_form\EtufHelper;
use Drupal\Component\Utility\NestedArray;
use Drupal\content_translation\BundleTranslationSettingsInterface;

define('ENTITY_TRANSLATION_UNIFIED_FORM_ENABLED', 4);
/**
 * @file
 * Places entity translated fields inline in a single form.
 */

/**
 * Implements hook_module_implements_alter().
 *
 * This ensures the form_alter hook runs at the end.
 */
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)) {
    // For css.
    $variables['attributes']['class'][] = 'etuf-sbs';
    // For sync js.
    $variables['attributes']['class'][] = 'sync';
  }
}

/**
 * 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_route = \Drupal::routeMatch()->getRouteName();
  $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)) {
    $is_valid = \Drupal::service('path.validator')->isValid($current_path);
    if (!$is_valid) {
      return new AccessResultForbidden();
    }
    $entity_type_id = 'node';
    $bundle = '';
    if (strpos($current_path, '/edit') > 4) {
      // Get the node object.
      $node = \Drupal::routeMatch()->getParameter($entity_type_id);
      $bundle = $node->bundle();
    }
    else {
      // Get the bundle.
      $array_of_segments = explode('/', $current_path);
      $bundle = end($array_of_segments);
    }
    // Get the CSS for the current theme.
    $theme = \Drupal::service('theme.manager')->getActiveTheme()->getName();
    $base_theme = '';
    if (property_exists(\Drupal::service('theme_handler')->listInfo()[$theme], 'base_theme')) {
      $base_theme = \Drupal::service('theme_handler')->listInfo()[$theme]->base_theme;
    }
    if (!empty($base_theme)) {
      if ($base_theme == 'claro') {
        $theme = 'claro';
      }
    }
    if (!empty($base_theme)) {
      if ($base_theme == 'business') {
        $theme = 'business';
      }
    }
    $path_to_etuf = \Drupal::service('extension.path.resolver')->getPath('module', 'entity_translation_unified_form');
    if (entity_translation_unified_form_sbs_enabled($entity_type_id, $bundle)) {
      if (file_exists($path_to_etuf . "/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';
      }
      if (version_compare(\Drupal::VERSION, '10.1', '>=')) {
        if (file_exists($path_to_etuf . "/css/ten-one-sbs-$theme.css")) {
          $page['#attached']['library'][] = 'entity_translation_unified_form/ten-one-sbs-' . $theme;
        }
      }
      $other_languages = EtufHelper::getOtherEnabledLanguages();
      foreach ($other_languages as $other_langcode => $other_language) {
        $page['#attached']['drupalSettings']['other_langs'][] = $other_langcode;
      }
    }
    else {
      if (version_compare(\Drupal::VERSION, '10.1', '>=')) {
        if (file_exists($path_to_etuf . "/css/ten-one-inline-$theme.css")) {
          $page['#attached']['library'][] = 'entity_translation_unified_form/ten-one-inline-' . $theme;
        }
      }
    }
    if (entity_translation_unified_form_moderation_sync_disabled($entity_type_id, $bundle) != TRUE) {
      $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;
      }
    }
    if ($current_route == 'entity.node.preview') {
      $page['#attached']['library'][] = 'entity_translation_unified_form/etuf_preview';
    }
  }
}

/**
 * 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_UNIFIED_FORM_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_translate_labels'] = [
    '#title' => t('Translate fields labels and descriptions in each language'),
    '#type' => 'checkbox',
    '#default_value' => FALSE,
    '#states' => $states,
  ];
  if (!empty($bundle)) {
    $form['workflow']['entity_translation_unified_form']['entity_translation_unified_form_translate_labels']['#default_value'] = entity_translation_unified_form_translate_labels_enabled($entity_type_id, $bundle);
    $form['workflow']['entity_translation_unified_form']['entity_translation_unified_form_translate_labels']['#states'] = [
      'visible' => [
        'and' => [
          ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]'
          => ['checked' => TRUE],
          ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_theme]"]'
          => ['value' => 'EntityTranslationUnifiedFormInlineMode'],
          ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]'
          => ['checked' => TRUE],
        ],
      ],
    ];
  }
  $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,
  ];
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name != 'node.type_add') {
    // Save only button option for content types on the node type edit or node
    // type add form.
    $form['workflow']['entity_translation_unified_form']['entity_translation_unified_form_save_only_button'] = [
      '#title' => t('Apply "Save only" button for this bundle'),
      '#type' => 'checkbox',
      '#default_value' => entity_translation_unified_form_save_only_button($entity_type_id, $bundle),
    ];
  }
  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 = FALSE;
  if (isset($form_state->getValues()['entity_translation_unified_form_translate_labels'])) {
    $enabled = $form_state->getValues()['entity_translation_unified_form_translate_labels'];
  }
  entity_translation_unified_form_set_translate_labels_enabled($entity_type_id, $bundle, $enabled);
  $enabled = $form_state->getValues()['entity_translation_unified_form_save_only_button'];
  entity_translation_unified_form_set_save_only_button_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;
}

/**
 * Sets the configuration for a given bundle.
 */
function entity_translation_unified_form_set_save_only_button_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_save_only_button'] = $enabled;
    $content_translation_manager->setBundleTranslationSettings($entity_type_id, $bundle, $settings);
  }
}

/**
 * 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'),
  ];
}

/**
 * Gathers the different modes from EntityTranslationUnifiedFormMode plugins.
 *
 * Returns an array with mode IDs as keys and labels as values.
 */
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');

  $bundle_info_service = \Drupal::service('entity_type.bundle.info');
  foreach ($form['#labels'] as $entity_type_id => $label) {
    $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' => [
              'and' => [
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                  'checked' => TRUE,
                ],
                ':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' => [
              'and' => [
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]' => [
                  'checked' => TRUE,
                ],
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_theme]"]' => [
                  'value' => 'EntityTranslationUnifiedFormInlineMode',
                ],
                ':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' => [
              'and' => [
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_enable]"]' => [
                  'checked' => TRUE,
                ],
                ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][settings][content_translation][entity_translation_unified_form_theme]"]' => [
                  'value' => 'EntityTranslationUnifiedFormInlineMode',
                ],
                ':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' => [
                'and' => [
                  ':input[name="settings[' . $entity_type_id . '][' . $bundle . '][translatable]"]' => [
                    'checked' => TRUE,
                  ],
                  ':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,
                ],
              ],
            ],
          ];
          // Save only button option for content types.
          $form['settings'][$entity_type_id][$bundle]['settings']['content_translation']['entity_translation_unified_form_save_only_button'] = [
            '#title' => t('Apply "Save only" button for this bundle'),
            '#type' => 'checkbox',
            '#default_value' => entity_translation_unified_form_save_only_button($entity_type_id, $bundle),
          ];
        }
      }
    }
  }
}

/**
 * Perform alterations before an entity form is included in the IEF widget.
 *
 * This hook can be implemented by themes.
 *
 * @param array $entity_form
 *   Nested array of form elements that comprise the entity form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state of the parent form.
 */
function entity_translation_unified_form_inline_entity_form_entity_form_alter(array &$entity_form, FormStateInterface &$form_state) {

  $entity = $entity_form['#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)) {
    // Add entity translation form elements for unified language node form.
    $entityManager = \Drupal::service('entity_field.manager');
    $fields = $entityManager->getFieldDefinitions($entity_type_id, $bundle);

    $mode_plugin_id = entity_translation_unified_form_bundle_display_mode($entity_type_id, $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_id, $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.
      $form_display = EntityFormDisplay::collectRenderDisplay($entity, 'default');
      foreach ($fields as $field_name => $field_definition) {
        entity_translation_unified_form_node_insert_other_language_fields($entity_form, $form_state, $entity, $field_definition, $mode_plugin, $form_display);
      }

      // Place our submit callback right before submitCleanFormState
      $submit_key = -1;
      foreach($entity_form['#ief_element_submit'] as $key => $values) {
        if(is_array($values) && count($values) > 1 && $values[1] == 'submitCleanFormState') {
          $submit_key = $key;
          break;
        }
      }
      array_splice($entity_form['#ief_element_submit'], $submit_key, 0, 'entity_translation_unified_form_inline_entity_form_submit');
    }
  }
}

/**
 * Form submission handler for node_form().
 *
 * Configure entity translation node object for entity_translation_unified_form.
 */
function entity_translation_unified_form_inline_entity_form_submit(array $form, FormStateInterface $form_state) {

  if(isset($form['#entity'])) {
    $entity = $form['#entity'];
    $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();
    $other_languages = EtufHelper::getOtherEnabledLanguages();
    foreach ($other_languages as $other_langcode => $other_language) {
      // Get the existing translation, or create one if it doesn't currently exist.
      if ($entity->hasTranslation($other_langcode)) {
        $translation = $entity->getTranslation($other_langcode);
      }
      else {
        $translation = $entity->addTranslation($other_langcode);
      }

      foreach ($fields as $field_name => $field_definition) {
        $etuf_name = EtufHelper::getEtufFieldName($field_name, $other_langcode);

        $path = array_merge($form['#parents'], [$etuf_name]);
        $key_exists = NULL;
        $field_values = NestedArray::getValue($values, $path, $key_exists);

        if ($key_exists) {
          $translation->set($field_name, $field_values);
        }
      }
    }
  }
}

/**
 * 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;
  }
  if (stripos($form_id, 'layout_builder') > 0) {
    // Do not modify the layout_builder form.
    return;
  }
  if (stripos($form_id, 'revisions') > 0) {
    // Do not interfere with the revisions tab either.
    return;
  }
  if (stripos($form_id, 'scheduled_transitions') > 0) {
    // Do not modify the scheduled transitions form.
    return;
  }
  if (stripos($form_id, 'node_type_add_form') > 0) {
    // Do not modify the scheduled transitions form.
    return;
  }
  if (stripos($form_id, '_book_outline_form') > 0) {
    // Do not modify the book outline form.
    return;
  }

  $entity = $form_object->getEntity();
  $entity_type_id = $entity->getEntityTypeId();
  $bundle = $entity->bundle();
  // Retrieve "Save only" button enable flag from configuration setting.
  $save_only_button_enable = FALSE;
  $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_save_only_button'])) {
      $save_only_button_enable = $settings['entity_translation_unified_form_save_only_button'];
    }
  }
  if (isset($save_only_button_enable)) {
    if ($save_only_button_enable) {
      $form['actions']['saveonly'] = [
        '#type'   => 'submit',
        '#value'  => t('Save only'),
        '#weight' => 10,
        '#submit' => [
          '::submitForm',
          '::save',
          'entity_translation_unified_form_entity_translation_unified_page_submit_save_only',
        ],
      ];
    }
  }

  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 (isset($form['actions']['saveonly'])) {
      $keypp = array_search('::save', $form['actions']['saveonly']['#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');
      }
      if (isset($form['actions']['saveonly'])) {
        array_splice($form['actions']['saveonly']['#submit'], $keypp, 0, 'entity_translation_unified_form_node_form_submit');
      }

      // 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.
      $form_display = EntityFormDisplay::collectRenderDisplay($entity, 'default');
      foreach ($fields as $field_name => $field_definition) {
        entity_translation_unified_form_node_insert_other_language_fields($form, $form_state, $entity, $field_definition, $mode_plugin, $form_display);
      }
      $other_languages = EtufHelper::getOtherEnabledLanguages();
      // Handle other language menu link translation load title into new field.
      foreach ($other_languages as $other_langcode => $other_language) {
        if (isset($form['menu']['enabled']['#default_value'])) {
          if ($form['menu']['enabled']['#default_value']) {
            $form['menu']['link']['title']['#weight'] = -1;
            $form['menu']['link']['link-title-etuf-' . $other_langcode] = [
              '#type' => 'textfield',
              '#title' => t('Menu link title') . ' ' . $other_langcode,
              '#default_value' => '',
              '#weight' => 0,
              '#maxlength' => 255,
              '#required' => TRUE,
            ];
            $ml_uuid = $form['menu']['link']['id'];
            if (empty($ml_uuid) || !isset($ml_uuid)) {
              continue;
            }
            if (is_array($ml_uuid) && isset($ml_uuid['#value'])) {
              $ml_uuid = $ml_uuid['#value'];
            }
            $storage = \Drupal::entityTypeManager()->getStorage('menu_link_content');
            $uuid = str_replace('menu_link_content:', '', $ml_uuid);
            $menu_link = $storage->loadByProperties(['uuid' => $uuid]);
            if (is_array($menu_link)) {
              $menu_link = reset($menu_link);
              if ($menu_link && $menu_link->hasTranslation($other_langcode)) {
                $menu_link = $menu_link->getTranslation($other_langcode);
                $title = '';
                if (!empty($menu_link->label())) {
                  // Truncate to no more than 255 chars.
                  $title = substr($menu_link->label(), 0, 254);
                }
                $form['menu']['link']['link-title-etuf-' . $other_langcode]['#default_value'] = $title;
              }
              elseif ($menu_link) {
                $translation = $entity->getTranslation($other_langcode);
                // Truncate to no more than 255 chars.
                $title = substr($translation->getTitle(), 0, 254);
                $form['menu']['link']['link-title-etuf-' . $other_langcode]['#default_value'] = $title;
              }
            }
          }
        }
      }
    }
  }
}

/**
 * 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'])) {
    // Date only needs date object.
    return $val['date'];
  }
  if (count($val) == 1) {
    return current($val);
  }
  // This probably wont work in all cases.
  return $val;
}

/**
 * Creates a field definition from the existing one.
 *
 * Checks on 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, &$form_display) {
  $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);
  }

  // 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 = 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, $entity, $field_definition, $mode_plugin, &$form_display) {
  $language_manager = \Drupal::languageManager();
  $language = $language_manager->getCurrentLanguage();

  if ($entity instanceof EntityInterface) {
    $entity_type = $entity->getEntityTypeId();
    $bundle = $entity->bundle();

    $field_name = $field_definition->getName();

    $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, $form_display);
        // Build and attach the translated field.
        if (!empty($field_form)) {
          $field_form['widget']['#field_name'] = EtufHelper::getEtufFieldName($field_name, $other_langcode);

          // Update the parents array.
          if (!is_array($field_form['widget']['#parents'])) {
            $field_form['widget']['#parents'] = [];
            $field_form['widget']['#parents'][] = $field_form['widget']['#field_name'];
          }
          else {
            array_splice($field_form['widget']['#parents'], -1, 1, $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) {
  $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.
      if ($entity->hasTranslation($other_langcode)) {
        $translation = $entity->getTranslation($other_langcode);
      }
      else {
        $translation = $entity->addTranslation($other_langcode);
      }
      $translation->setRevisionTranslationAffected(TRUE);

      foreach ($fields as $field_name => $field_definition) {
        $etuf_name = EtufHelper::getEtufFieldName($field_name, $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' || $field_type == 'file') {
            // 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.
      if ($entity->hasTranslation($other_langcode)) {
        $translation = $entity->getTranslation($other_langcode);

        // Handle other language menu link translation save title.
        if (isset($form['menu']['enabled']['#default_value'])) {
          if ($form['menu']['enabled']['#default_value']) {
            $ml_uuid = $form['menu']['link']['id']['#value'];
            if (is_string($ml_uuid) && !empty($ml_uuid)) {
              $storage = \Drupal::entityTypeManager()->getStorage('menu_link_content');
              $uuid = str_replace('menu_link_content:', '', $ml_uuid);
              $menu_link = $storage->loadByProperties(['uuid' => $uuid]);
              if (is_array($menu_link)) {
                $menu_link = reset($menu_link);
                $menu_values = $form_state->getValue('menu');
                $menu_title_other_lang = $menu_values['link-title-etuf-' . $other_langcode];
                if ($menu_link && $menu_link->hasTranslation($other_langcode)) {
                  $menu_link = $menu_link->getTranslation($other_langcode);
                  $menu_link->set('title', $menu_title_other_lang);
                  if (!empty($menu_title_other_lang)) {
                    $menu_link->save();
                  }
                }
                elseif ($menu_link) {
                  $menu_link->addTranslation($other_langcode);
                  $menu_link->set('title', $menu_title_other_lang);
                  if (!empty($menu_title_other_lang)) {
                    $menu_link->save();
                  }
                }
              }
            }
            // No longer need the form element, remove it to avoid undefined
            // notices.
          }
        }
      }
      else {
        $translation = $entity->addTranslation($other_langcode);
      }

      foreach ($fields as $field_name => $field_definition) {
        $etuf_name = EtufHelper::getEtufFieldName($field_name, $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' || $field_type == 'file') {
            // 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('entity_translation_unified_form_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);
      }

    }
  }
}

/**
 * Ensures the previous database transaction is committed after shutdown.
 *
 * This function makes sure the moderation state is processed correctly.
 * The main purpose is to create or update an alias for the other language
 * record if it's different from the existing one.
 */
function entity_translation_unified_form_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.
    // $base_url . $url;.
    $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 = entity_translation_unified_form_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]);
    }
    elseif ($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.
}

/**
 * Ensures the previous database transaction is committed after shutdown.
 *
 * This function makes sure the moderation state is processed correctly.
 */
function entity_translation_unified_form_custom_shutdown($entity, $langcode, $moderation_state, $interfacelang) {
  $vid = 0;
  $latest_revision = entity_translation_unified_form_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('entity_translation_unified_form_custom_shutdown_menu', $latest_revision, $langcode);
  }
  else {
    drupal_register_shutdown_function('entity_translation_unified_form_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 entity_translation_unified_form_etuf_latest_revision($id, &$vid, $lang, $entity_type = 'node') {
  $query = \Drupal::entityTypeManager()->getStorage($entity_type)->getQuery();
  $query->latestRevision()
    ->accessCheck(TRUE);
  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;
}

/**
 * Returns true if save only button is enable for a given bundle.
 */
function entity_translation_unified_form_save_only_button($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_save_only_button']);
  }

  return FALSE;
}

/**
 * Form submit handler for save only.
 */
function entity_translation_unified_form_entity_translation_unified_page_submit_save_only(array $form, FormStateInterface $form_state) {
  $entity = $form_state->getFormObject()->getEntity();
  $node_id = $entity->id();
  $current_url = \Drupal::request()->getUri();
  $destination = '/edit\?destination=/';
  if (preg_match($destination, $current_url)) {
    \Drupal::request()->query->remove('destination');
  }
  $form_state->setRedirectUrl(Url::fromRoute('entity.node.edit_form', ['node' => $node_id]));
}

/**
 * Implements hook_library_info_alter().
 *
 * Remove node/node.preview.js which installs dialog on almost all links.
 * However it is not necessary for some links like language switch.
 */
function entity_translation_unified_form_library_info_alter(&$libraries, $extension) {
  if ($extension === 'node' && isset($libraries['drupal.node.preview'])) {
    // Remove the JS file in the core preview library.
    $libraries['drupal.node.preview']['js'] = [];
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc