simple_tmgmt-1.0.x-dev/src/SimpleTmgmt.php

src/SimpleTmgmt.php
<?php

namespace Drupal\simple_tmgmt;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Link;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\tmgmt\Entity\Job;
use Drupal\tmgmt\Entity\JobItem;
use Drupal\tmgmt\Entity\Translator;
use Drupal\tmgmt\JobInterface;
use Drupal\tmgmt\JobItemInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\tmgmt\TranslatorInterface;

/**
 * Class SimpleTmgmt.
 */
class SimpleTmgmt implements SimpleTmgmtInterface {

  use StringTranslationTrait;

  // @todo make use of a workflow or configure Machine translation providers
  //   For now, just hold a list of machine based translators.
  const MACHINE_TRANSLATORS = ['simple_tmgmt_deepl', 'tmgmt_deepl', 'google', 'microsoft'];

  /**
   * Drupal\Core\Mail\MailManagerInterface definition.
   *
   * @var \Drupal\Core\Mail\MailManagerInterface
   */
  protected $pluginManagerMail;

  /**
   * Drupal\Core\Session\AccountProxyInterface definition.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * Drupal\Core\Language\LanguageManagerInterface definition.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * Drupal\Core\Render\RendererInterface definition.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * Drupal\Core\Config\ConfigFactoryInterface definition.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * SimpleTmgmt constructor.
   *
   * @param \Drupal\Core\Mail\MailManagerInterface $plugin_manager_mail
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   * @param \Drupal\Core\Render\RendererInterface $renderer
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   */
  public function __construct(
    MailManagerInterface $plugin_manager_mail,
    AccountProxyInterface $current_user,
    LanguageManagerInterface $language_manager,
    RendererInterface $renderer,
    ConfigFactoryInterface $config_factory
  ) {
    $this->pluginManagerMail = $plugin_manager_mail;
    $this->currentUser = $current_user;
    $this->languageManager = $language_manager;
    $this->renderer = $renderer;
    $this->configFactory = $config_factory;
  }

  /**
   * Unset providers that could be used as a dependency of other providers.
   */
  public static function translatorsToDisable() {
    // @todo to be handled/configured by each provider.
    // return ['deepl_pro', 'file_exchange'];
    return [];
  }

  /**
   * {@inheritdoc}.
   */
  public function getActiveTranslators() {
    // @todo could be refined with unsupported / custom filter.
    $result = [];
    $translators = Translator::loadMultiple();
    foreach ($translators as $translator) {
      if (
        $translator->checkAvailable()->getSuccess() &&
        !in_array($translator->id(), SimpleTmgmt::translatorsToDisable())
      ) {
        $result[] = $translator;
      }
    }
    return $result;
  }

  /**
   * {@inheritdoc}.
   */
  public function isTranslationSupported(TranslatorInterface $translator, LanguageInterface $sourceLanguage, $targetLangCode) {
    // If the provider doesn't have remote language support at all, presume that
    // it is not a remote translator, has there is not method related to
    // machine based translations.
    if (empty($translator->getSupportedRemoteLanguages())) {
      TRUE;
    }
    return array_key_exists($targetLangCode, $translator->getSupportedTargetLanguages($sourceLanguage->getId()));
  }

  /**
   * {@inheritdoc}.
   */
  public function isMachineTranslator($translator) {
    return in_array($translator, static::MACHINE_TRANSLATORS);
  }

  /**
   * {@inheritdoc}.
   */
  public function isManualTranslator($translator) {
    return !in_array($translator, static::MACHINE_TRANSLATORS);
  }

  /**
   * {@inheritDoc}.
   */
  public function sendJobCreateMail(array $content, $to) {
    if ($content['has_delivery_date']) {
      $subject = $this->t('@node_title | @source_language to @target_language | @words words | @delivery_date', [
        '@node_title' => $content['node_title'],
        '@source_language' => $content['source_language'],
        '@target_language' => $content['target_language'],
        '@words' => $content['words'],
        '@delivery_date' => $content['delivery_date'],
        '@job_link' => $content['job_link'],
      ]);
    }
    else {
      $subject = $this->t('@node_title | @source_language to @target_language | @words words', [
        '@node_title' => $content['node_title'],
        '@source_language' => $content['source_language'],
        '@target_language' => $content['target_language'],
        '@words' => $content['words'],
        '@job_link' => $content['job_link'],
      ]);
    }
    $attachments = [];
    $attachments[] = (object) [
      'filename' => $content['file_name'],
      'uri' => $content['file_uri'],
      // @todo get filemime as it can vary.
      'filemime' => 'application/xliff+xml',
    ];
    return $this->sendMail($to, $subject, 'mail__job_create', $content, $attachments);
  }

  /**
   * {@inheritDoc}.
   */
  public function sendJobErrorMail(array $content, $to) {
    $subject = $this->t('Translation request @error_code error for @translator', [
      '@error_code' => $content['error_code'],
      '@translator' => $content['translator'],
    ]);
    return $this->sendMail($to, $subject, 'mail__job_error', $content);
  }

  /**
   * Sends html mail with optional attachments.
   *
   * @param string $to
   * @param string $subject
   * @param string $theme
   * @param array $content
   * @param array $attachments
   *
   * @return array
   */
  private function sendMail($to, $subject, $theme, array $content, array $attachments = []) {
    $body = [
      '#theme' => $theme,
      '#content' => $content,
    ];
    $fromMail = $this->currentUser->getEmail();
    $langCode = $this->languageManager->getCurrentLanguage()->getId();
    $sender = '"' . $this->currentUser->getDisplayName() . '" <' . $fromMail . '>';
    $params = [
      'headers' => [
        'From' => $sender,
      ],
      'subject' => $subject,
      'from' => $sender,
      'body' => $this->renderer->render($body),
      'options' => [],
      'files' => $attachments,
    ];
    return $this->pluginManagerMail->mail(
      'simple_tmgmt',
      'job_create',
      $to,
      $langCode,
      $params,
      $fromMail,
      TRUE
    );
  }

  /**
   * Creates a Drupal State key for an entity translation.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   * @param $langCode
   *
   * @return string
   */
  public static function getStateKey(EntityInterface $entity, $langCode) {
    $stateKeyElements = [
      'simple_tmgmt',
      $entity->getEntityTypeId(),
      $entity->id(),
      $langCode,
    ];
    return implode('_', $stateKeyElements);
  }

  /**
   * {@inheritdoc}
   */
  public function getJobCreateUrl(ContentEntityInterface $entity, $langcode, $default_provider) {
    $result = Url::fromRoute('simple_tmgmt.job_create', [
      'entity_type_id' => $entity->getEntityTypeId(),
      'entity_id' => $entity->id(),
      'langcode' => $langcode,
      'default_provider' => $default_provider,
    ]);
    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function setTranslationFormUrl(FormStateInterface $form_state) {
    /** @var \Drupal\tmgmt\JobInterface $job */
    $job = \Drupal::routeMatch()->getParameter('tmgmt_job');
    if ($job instanceof JobInterface) {
      $jobItems = $job->getItems();
      if (!empty($jobItems)) {
        reset($jobItems);
        /** @var \Drupal\tmgmt\JobItemInterface $jobItem */
        $jobItemKey = key($jobItems);
        $jobItem = $jobItems[$jobItemKey];
        if (!empty($jobItem->getSourceUrl())) {
          $options = $jobItem->getSourceUrl()->getOptions();
          if (array_key_exists('entity_type', $options) && array_key_exists('entity', $options)) {
            // @var \Drupal\Core\Entity\ContentEntityInterface $entity
            $entity = $options['entity'];
            $translationFormUrl = Url::fromRoute('entity.' . $options['entity_type'] . '.content_translation_overview', [
              $options['entity_type'] => $entity->id(),
            ]);
            if ($translationFormUrl->isRouted()) {
              $form_state->set('job_to_delete', $job);
              $form_state->set('job_item_to_delete', $jobItem);
              $form_state->set('translation_form_url', $translationFormUrl);
            }
          }
        }
      }
    }
  }

  /**
   * {@inheritdoc}.
   */
  public function getHelpLinkMarkup() {
    // @todo make the help link display configurable.
    $config = $this->configFactory->get('simple_tmgmt.settings');
    $helpLinkLabel = $config->get('help_link_label');
    $helpUrl = $config->get('help_link_url');
    if ($helpUrl) {
      $helpLinkUrl = Url::fromUri($helpUrl);
    }
    else {
      $helpLinkUrl = Url::fromRoute('help.page', ['name' => 'simple_tmgmt']);
    }
    $helpLink = Link::fromTextAndUrl($helpLinkLabel, $helpLinkUrl)
      ->toRenderable();
    return $this->renderer->render($helpLink);
  }

  /**
   * {@inheritdoc}.
   */
  public function getJobFormDisabledActions() {
    return $this->getFormDisabledActions('disabled_actions_job_form');
  }

  /**
   * {@inheritdoc}.
   */
  public function getJobItemFormDisabledActions() {
    return $this->getFormDisabledActions('disabled_actions_job_item_form');
  }

  /**
   * Returns the disabled form actions from the configuration.
   *
   * @param $config_key
   *
   * @return array
   */
  private function getFormDisabledActions($config_key) {
    $result = [];
    $config = $this->configFactory->get('simple_tmgmt.settings');
    $actions = $config->get($config_key);
    if (is_array($actions)) {
      foreach ($actions as $action => $value) {
        if ((string) $value === "0") {
          $result[] = $action;
        }
      }
    }
    return $result;
  }

  /**
   * {@inheritdoc}.
   */
  public function transformTranslationLink($link) {
    $result = $link;
    $dom = new \DOMDocument();
    $dom->loadHTML($link);

    try {
      $aElement = $dom->getElementsByTagName('a')->item(0);
      if ($aElement !== NULL) {
        $jobItemHref = $aElement->getAttribute('href');
        if (strpos($jobItemHref, '/admin/tmgmt/items/') !== FALSE) {
          // Some setup can have an absolute href here, make it relative.
          $jobItemHref = strstr($jobItemHref, '/admin/tmgmt/items/');
          $jobItemUrl = Url::fromUri('internal:' . $jobItemHref);
          if ($jobItemUrl->isRouted() && $jobItemUrl->getRouteName() === 'entity.tmgmt_job_item.canonical') {
            $jobItemId = $jobItemUrl->getRouteParameters()['tmgmt_job_item'];
            $jobItem = JobItem::load($jobItemId);
            if ($jobItem instanceof JobItemInterface) {
              $jobId = $jobItem->getJobId();
              $jobUrl = Url::fromRoute('entity.tmgmt_job.canonical', [
                'tmgmt_job' => $jobId,
              ]);
              $job = Job::load($jobId);
              if ($job instanceof JobInterface) {
                $jobItemState = $jobItem->get('state')->getValue();
                $jobState = $job->get('state')->getValue();
                if (is_array($jobItemState) && is_array($jobState)) {
                  $jobItemStateValue = (int) $jobItemState[0]['value'];
                  $jobStateValue = (int) $jobState[0]['value'];
                  switch ($jobItemStateValue) {
                    // Replaces the link from 'items' to 'jobs' if the translation
                    // Job item / Job are pending (Job item / Job state = 'active').
                    // It means in this case that we want to upload the xliff file
                    // and not do the translation manually.
                    case JobItemInterface::STATE_ACTIVE:
                      if ($jobStateValue === JobInterface::STATE_ACTIVE) {
                        $options = $jobItemUrl->getOptions();
                        $jobHref = $jobUrl->toString();
                        // Replace the destination as well so we can redirect to the
                        // original items afterwards for translation review.
                        if (
                          array_key_exists('query', $options) &&
                          array_key_exists('destination', $options['query'])
                        ) {
                          $jobItemHrefParts = explode('?', $jobItemHref);
                          if (is_string($jobItemHrefParts[0])) {
                            $options['query']['destination'] = $jobItemHrefParts[0];
                            $jobUrl->setOptions($options);
                            $jobHref = $jobUrl->toString();
                          }
                        }
                        // Replace the href.
                        $aElement->setAttribute('href', $jobHref);
                        // $aElement->setAttribute('target', '_blank');
                        // Replace the alt / title from the image.
                        $config = $this->configFactory->get('simple_tmgmt.settings');
                        $pendingTranslationLabel = $config->get('pending_manual_translation_label');
                        $xpath = new \DOMXPath($dom);
                        $imgElement = $xpath->query('//a/img')->item(0);
                        if ($imgElement instanceof \DOMElement) {
                          $imgElement->setAttribute('alt', $pendingTranslationLabel);
                          $imgElement->setAttribute('title', $pendingTranslationLabel);
                        }
                        // @todo other markup elements can be removed from the dom.
                        //   as we presume here a simple link.
                        $result = $dom->saveHTML($aElement);
                      }
                      break;

                    // Just open in a new tab in this case.
                    case JobItemInterface::STATE_REVIEW:
                      // $aElement->setAttribute('target', '_blank');.
                      // @todo other markup elements can be removed from the dom.
                      //   as we presume here a simple link.
                      $result = $dom->saveHTML($aElement);
                      break;

                    // If the Job Item is inactive and the translator plugin unknown
                    // it leads to an exception by default.
                    // Remove the link then as this is delegated to the
                    // Change the link to continue the Job.
                    case JobItemInterface::STATE_INACTIVE:
                      $xpath = new \DOMXPath($dom);
                      $node = $xpath->query('//a/text()')->item(0);
                      if ($node) {
                        // The provider cannot be set back as it is undefined
                        // in the inactive state.
                        // So redirecting in all cases to the node translation form.
                        if (!empty($jobItemUrl)) {
                          $jobUrl->setOptions($jobItemUrl->getOptions());
                        }
                        $link = Link::fromTextAndUrl($this->t('Continue'), $jobUrl)->toRenderable();
                        $result = $this->renderer->render($link);
                      }
                      break;
                  }
                }
              }
            }
          }
        }
      }
    }
    catch (\Exception $exception) {
      \Drupal::logger('simple_tmgmt')->error($exception->getMessage());
    }
    return $result;
  }

}

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

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