You are here

lingotek.module in Lingotek Translation 8

lingotek.module

Implements Drupal-related hooks for the Lingotek Translation module.

File

lingotek.module
View source
<?php

/**
 * @file lingotek.module
 * 
 * Implements Drupal-related hooks for the Lingotek Translation module.
 */
use Drupal\content_translation\ContentTranslationManagerInterface;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\lingotek\Exception\LingotekApiException;
use Drupal\lingotek\Lingotek;

/**
 * Implements hook_toolbar().
 */
function lingotek_toolbar() {
  $items = array();
  $items['translation'] = array(
    '#type' => 'toolbar_item',
    '#attached' => array(
      'library' => array(
        'lingotek/lingotek.icons',
      ),
    ),
  );
  return $items;
}

/**
 * Implements hook_module_implements_alter().
 */
function lingotek_module_implements_alter(&$implementations, $hook) {

  // Make sure lingotek_entity_presave() comes last.
  switch ($hook) {

    // Move our hook_entity_type_alter() implementation to the end of the list.
    case 'entity_presave':
      $group = $implementations['lingotek'];
      unset($implementations['lingotek']);
      $implementations['lingotek'] = $group;
      break;
  }
}

/**
 * Implements hook_entity_presave().
 */
function lingotek_entity_presave(EntityInterface $entity) {
  $configuration_service = \Drupal::service('lingotek.configuration');
  if ($entity instanceof ContentEntityInterface && $configuration_service
    ->isEnabled($entity
    ->getEntityTypeId(), $entity
    ->bundle())) {
    $translation_service = \Drupal::service('lingotek.content_translation');
    $translation_service
      ->updateEntityHash($entity);
  }
}

/**
 * Implements hook_entity_insert().
 */
function lingotek_entity_insert(EntityInterface $entity) {

  /** @var \Drupal\lingotek\LingotekConfigurationServiceInterface $configuration_service */
  $configuration_service = \Drupal::service('lingotek.configuration');
  if ($entity instanceof \Drupal\Core\Config\Entity\ConfigEntityInterface) {
    if (\Drupal::isConfigSyncing()) {

      // We don't want to react to configuration imports.
      return;
    }

    /** @var \Drupal\lingotek\LingotekConfigTranslationServiceInterface $translation_service */
    $translation_service = \Drupal::service('lingotek.config_translation');
    $entity_type_id = $entity
      ->getEntityTypeId();
    if ($entity instanceof \Drupal\field\Entity\FieldConfig) {
      $entity_type_id = $entity
        ->getTargetEntityTypeId() . '_fields';
    }
    if ($translation_service
      ->isEnabled($entity_type_id)) {
      $profile = $configuration_service
        ->getConfigEntityProfile($entity);
      $has_autoupload = $profile
        ->hasAutomaticUpload();
      $source_status = $translation_service
        ->getSourceStatus($entity);
      $entity_has_changed = $translation_service
        ->hasEntityChanged($entity);
      if ($has_autoupload) {

        // New entity with auto-upload
        if ($source_status == NULL || $source_status == Lingotek::STATUS_UNTRACKED) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          try {
            $document_id = $translation_service
              ->uploadDocument($entity);
            $translation_service
              ->setTargetStatuses($entity, Lingotek::STATUS_REQUEST);
          } catch (LingotekApiException $exception) {
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
            drupal_set_message(t('The upload for @entity_type %title failed. Please try again.', array(
              '@entity_type' => $entity
                ->getEntityTypeId(),
              '%title' => $entity
                ->label(),
            )), 'error');
          }
        }
      }
      elseif (!$has_autoupload) {
        if ($entity_has_changed) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          $translation_service
            ->markTranslationsAsDirty($entity);
          $translation_service
            ->setTargetStatuses($entity, Lingotek::STATUS_REQUEST);
        }
      }
    }
  }
  elseif ($entity instanceof ContentEntityInterface) {
    if ($configuration_service
      ->isEnabled($entity
      ->getEntityTypeId(), $entity
      ->bundle())) {
      $profile = $configuration_service
        ->getEntityProfile($entity);
      $has_autoupload = $profile
        ->hasAutomaticUpload();

      /** @var \Drupal\lingotek\LingotekContentTranslationServiceInterface $translation_service */
      $translation_service = \Drupal::service('lingotek.content_translation');
      $source_status = $translation_service
        ->getSourceStatus($entity);

      // Entity inserts are always changes.
      $entity_has_changed = TRUE;
      if ($has_autoupload) {

        // New entity with auto-upload
        if ($source_status == NULL || $source_status == Lingotek::STATUS_UNTRACKED) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          try {
            $document_id = $translation_service
              ->uploadDocument($entity);
            $translation_service
              ->setTargetStatuses($entity, Lingotek::STATUS_REQUEST);
            drupal_set_message(t('<em>@title</em> sent to Lingotek successfully.', array(
              '@title' => $entity
                ->label(),
            )));
          } catch (LingotekApiException $exception) {
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
            drupal_set_message(t('The upload for @entity_type %title failed. Please try again.', array(
              '@entity_type' => $entity
                ->getEntityTypeId(),
              '%title' => $entity
                ->label(),
            )), 'error');
          }
        }
        elseif ($entity_has_changed) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          try {
            $response = $translation_service
              ->updateDocument($entity);
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_IMPORTING);
            $translation_service
              ->markTranslationsAsDirty($entity);
            $translation_service
              ->setTargetStatuses($entity, Lingotek::STATUS_PENDING);
            drupal_set_message(t('<em>@title</em> was updated and sent to Lingotek successfully.', array(
              '@title' => $entity
                ->label(),
            )));
          } catch (LingotekApiException $exception) {
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
            drupal_set_message(t('The update for @entity_type %title failed. Please try again.', array(
              '@entity_type' => $entity
                ->getEntityTypeId(),
              '%title' => $entity
                ->label(),
            )), 'error');
          }
        }
      }
      elseif (!$has_autoupload) {
        if ($entity_has_changed) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          $translation_service
            ->markTranslationsAsDirty($entity);
          $translation_service
            ->setTargetStatuses($entity, Lingotek::STATUS_REQUEST);
        }
      }
    }
  }
}

/**
 * Implements hook_entity_update().
 */
function lingotek_entity_update(EntityInterface $entity) {

  // If it's new, has been already processed.
  if (isset($entity->lingotek_processed) && $entity->lingotek_processed) {
    return;
  }

  /** @var \Drupal\lingotek\LingotekConfigurationServiceInterface $configuration_service */
  $configuration_service = \Drupal::service('lingotek.configuration');
  if ($entity instanceof \Drupal\Core\Config\Entity\ConfigEntityInterface) {
    if (\Drupal::isConfigSyncing()) {

      // We don't want to react to configuration imports.
      return;
    }

    /** @var \Drupal\lingotek\LingotekConfigTranslationServiceInterface $translation_service */
    $translation_service = \Drupal::service('lingotek.config_translation');
    $entity_type_id = $entity
      ->getEntityTypeId();
    if ($entity instanceof \Drupal\field\Entity\FieldConfig) {
      $entity_type_id = $entity
        ->getTargetEntityTypeId() . '_fields';
    }
    if ($translation_service
      ->isEnabled($entity_type_id)) {
      $profile = $configuration_service
        ->getConfigEntityProfile($entity);
      $has_autoupload = $profile
        ->hasAutomaticUpload();
      $source_status = $translation_service
        ->getSourceStatus($entity);
      $entity_has_changed = $translation_service
        ->hasEntityChanged($entity);
      if ($has_autoupload) {

        // Updated entity with auto-upload
        $translation_service
          ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
        try {
          $document_id = $translation_service
            ->updateDocument($entity);
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_IMPORTING);
          $translation_service
            ->markTranslationsAsDirty($entity);
        } catch (LingotekApiException $exception) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
          drupal_set_message(t('The update for @entity_type %title failed. Please try again.', array(
            '@entity_type' => $entity
              ->getEntityTypeId(),
            '%title' => $entity
              ->label(),
          )), 'error');
        }
      }
      elseif (!$has_autoupload) {
        if ($entity_has_changed) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          $translation_service
            ->markTranslationsAsDirty($entity);
        }
      }
    }
  }
  elseif ($entity instanceof ContentEntityInterface) {
    if ($configuration_service
      ->isEnabled($entity
      ->getEntityTypeId(), $entity
      ->bundle())) {
      $profile = $configuration_service
        ->getEntityProfile($entity);
      $has_autoupload = $profile
        ->hasAutomaticUpload();

      /** @var \Drupal\lingotek\LingotekContentTranslationServiceInterface $translation_service */
      $translation_service = \Drupal::service('lingotek.content_translation');
      $source_status = $translation_service
        ->getSourceStatus($entity);
      $entity_has_changed = $translation_service
        ->hasEntityChanged($entity);
      if ($has_autoupload) {

        // New entity with auto-upload
        if ($source_status == NULL || $source_status == Lingotek::STATUS_UNTRACKED) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          try {
            $document_id = $translation_service
              ->uploadDocument($entity);
            drupal_set_message(t('<em>@title</em> sent to Lingotek successfully.', array(
              '@title' => $entity
                ->label(),
            )));
          } catch (LingotekApiException $exception) {
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
            drupal_set_message(t('The upload for @entity_type %title failed. Please try again.', array(
              '@entity_type' => $entity
                ->getEntityTypeId(),
              '%title' => $entity
                ->label(),
            )), 'error');
          }
        }
        elseif ($entity_has_changed) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          try {
            $response = $translation_service
              ->updateDocument($entity);
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_IMPORTING);
            $translation_service
              ->markTranslationsAsDirty($entity);
            drupal_set_message(t('<em>@title</em> was updated and sent to Lingotek successfully.', array(
              '@title' => $entity
                ->label(),
            )));
          } catch (LingotekApiException $exception) {
            $translation_service
              ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
            drupal_set_message(t('The update for @entity_type %title failed. Please try again.', array(
              '@entity_type' => $entity
                ->getEntityTypeId(),
              '%title' => $entity
                ->label(),
            )), 'error');
          }
        }
      }
      elseif (!$has_autoupload) {
        if ($entity_has_changed) {
          $translation_service
            ->setSourceStatus($entity, Lingotek::STATUS_EDITED);
          $translation_service
            ->markTranslationsAsDirty($entity);
        }
      }
    }
  }
}

/**
 * Implements hook_entity_delete().
 */
function lingotek_entity_delete(EntityInterface $entity) {

  // Only act on content entities.
  if (!$entity instanceof ContentEntityInterface) {
    return;
  }
  if (\Drupal::isConfigSyncing()) {

    // We don't want to react to configuration imports.
    return;
  }

  /** @var \Drupal\lingotek\LingotekContentTranslationServiceInterface $translation_service */
  $translation_service = \Drupal::service('lingotek.content_translation');

  // Delete the TMS document if it hasn't been disassociated
  if ($translation_service
    ->getDocumentId($entity)) {
    try {
      $response = $translation_service
        ->deleteDocument($entity);
    } catch (LingotekApiException $exception) {
      drupal_set_message(t('Failed deleting @entity_type %title. Please try again.', array(
        '@entity_type' => $entity
          ->getEntityTypeId(),
        '%title' => $entity
          ->label(),
      )), 'error');
    }
  }
}

/**
 * Implements hook_form_alter().
 */
function lingotek_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form_object = $form_state
    ->getFormObject();
  if ($form_object instanceof ContentEntityFormInterface) {

    // If it is a delete form, return.
    if ('delete' === $form_object
      ->getOperation()) {
      return;
    }
    $entity = $form_object
      ->getEntity();

    /** @var ContentTranslationManagerInterface $content_translation_manager */
    $content_translation_manager = \Drupal::service('content_translation.manager');

    /** @var \Drupal\lingotek\LingotekConfigurationServiceInterface $lingotek_config */
    $lingotek_config = \Drupal::service('lingotek.configuration');

    // If content translation is not enabled and lingotek configured, don't add
    // the form element.
    if (!$content_translation_manager
      ->isEnabled($entity
      ->getEntityTypeId(), $entity
      ->bundle()) || !$lingotek_config
      ->isEnabled($entity
      ->getEntityTypeId(), $entity
      ->bundle())) {
      return;
    }
    $default_profile = $lingotek_config
      ->getEntityProfile($entity);
    $profile_options = $lingotek_config
      ->getProfileOptions();
    $current_user = \Drupal::currentUser();
    $can_assign_profile = $current_user
      ->hasPermission('assign lingotek translation profiles') || $current_user
      ->hasPermission('administer lingotek');
    $form['lingotek_translation_management'] = array(
      '#type' => 'details',
      '#title' => t('Translation Management'),
      '#description' => t('The Lingotek Translation module was developed to help you translate your site. The module integrates the Lingotek translation management system directly into Drupal, so that your users can leverage the power of Lingotek\'s translation tools and services without ever having to leave the comfort of your Drupal environment.'),
      '#group' => 'advanced',
      '#weight' => 50,
      '#access' => $can_assign_profile,
    );
    $form['lingotek_translation_management']['lingotek_translation_profile'] = array(
      '#type' => 'select',
      '#title' => t('Translation Profile'),
      '#options' => $profile_options,
      '#default_value' => $default_profile
        ->id(),
      '#access' => $can_assign_profile,
    );
    foreach (array_keys($form['actions']) as $action) {
      if ($action != 'preview' && $action != 'lingotek_metadata' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {

        // We need to act before the node itself is saved.
        $submit_actions = $form['actions'][$action]['#submit'];
        array_unshift($submit_actions, 'lingotek_form_content_entity_form_submit');
        $form['actions'][$action]['#submit'] = $submit_actions;
      }
    }
  }
}

/**
 * @param array $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 */
function lingotek_form_content_entity_form_submit(array $form, FormStateInterface $form_state) {
  $form_values = $form_state
    ->getValues();

  /** @var \Drupal\lingotek\LingotekContentTranslationServiceInterface $translation_service */
  $translation_service = \Drupal::service('lingotek.content_translation');

  /** @var \Drupal\lingotek\LingotekConfigurationServiceInterface $lingotek_config */
  $lingotek_config = \Drupal::service('lingotek.configuration');

  /** @var ContentEntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /** @var ContentEntityInterface $entity */
  $entity = $entity_form
    ->getEntity();
  if ($entity_form
    ->getOperation() !== 'lingotek_metadata') {
    $profile_id = $form_values['lingotek_translation_profile'];
    $lingotek_config
      ->setProfile($entity, $profile_id, FALSE);
  }
}

/**
 * Implements hook_contextual_links_view_alter().
 */
function lingotek_contextual_links_view_alter(&$element, $items) {

  // TODO
}

/**
 * Implements hook_entity_type_alter().
 */
function lingotek_entity_type_alter(array &$entity_types) {

  // Provide defaults for lingotek translation info.

  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  foreach ($entity_types as $entity_type) {
    if ($entity_type
      ->isTranslatable()) {
      if (!$entity_type
        ->hasHandlerClass('lingotek')) {
        $entity_type
          ->setHandlerClass('lingotek', 'Drupal\\lingotek\\LingotekContentTranslationHandler');
      }
    }
  }
}

/**
 * Implements hook_entity_base_field_info().
 */
function lingotek_entity_base_field_info(EntityTypeInterface $entity_type) {

  // Taken from content_translation.

  /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */
  $manager = \Drupal::service('content_translation.manager');

  /** @var \Drupal\lingotek\LingotekConfigurationServiceInterface $lingotek_config */
  $lingotek_config = \Drupal::service('lingotek.configuration');
  $entity_type_id = $entity_type
    ->id();
  if ($manager
    ->isEnabled($entity_type_id) && $lingotek_config
    ->isEnabled($entity_type_id)) {
    $definitions = \Drupal::entityManager()
      ->getHandler($entity_type_id, 'lingotek')
      ->getFieldDefinitions();
    $installed_storage_definitions = \Drupal::entityManager()
      ->getLastInstalledFieldStorageDefinitions($entity_type_id);

    // We return metadata storage fields whenever content translation is enabled
    // or it was enabled before, so that we keep translation metadata around
    // when translation is disabled.
    // @todo Re-evaluate this approach and consider removing field storage
    //   definitions and the related field data if the entity type has no bundle
    //   enabled for translation, once base field purging is supported.
    //   See https://www.drupal.org/node/2282119.
    if ($manager
      ->isEnabled($entity_type_id) || array_intersect_key($definitions, $installed_storage_definitions)) {
      return $definitions;
    }
  }
}

/**
 * Implements hook_entity_translation_insert().
 */
function lingotek_entity_translation_insert(ContentEntityInterface $translation) {

  /** @var \Drupal\lingotek\LingotekConfigurationServiceInterface $lingotek_config */
  $lingotek_config = \Drupal::service('lingotek.configuration');

  /** @var \Drupal\lingotek\LingotekContentTranslationServiceInterface $translation_service */
  $translation_service = \Drupal::service('lingotek.content_translation');
  if ($lingotek_config
    ->isEnabled($translation
    ->getEntityTypeId(), $translation
    ->bundle())) {
    $status = $translation_service
      ->getTargetStatus($translation, $translation
      ->language()
      ->getId());

    // As untracked is a default, we save it anyway.
    if ($status === Lingotek::STATUS_REQUEST || $status === Lingotek::STATUS_UNTRACKED) {
      $translation = $translation_service
        ->setTargetStatus($translation, $translation
        ->language()
        ->getId(), Lingotek::STATUS_UNTRACKED, FALSE);
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function lingotek_form_language_admin_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  \Drupal::service('lingotek.language_form')
    ->form($form, $form_state);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function lingotek_form_language_admin_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  \Drupal::service('lingotek.language_form')
    ->form($form, $form_state);
}