tmgmt_xtm-8.x-5.x-dev/src/Plugin/tmgmt/Translator/Helper.php

src/Plugin/tmgmt/Translator/Helper.php
<?php

namespace Drupal\tmgmt_xtm\Plugin\tmgmt\Translator;

use Drupal\tmgmt\Entity\Job;
use Drupal\tmgmt\Entity\Translator;

/**
 * Provides utility functions for the XTM translator plugin.
 *
 * The Helper class contains methods and constants that assist in the
 * manipulation and processing of data for the XTM translation service.
 *
 * @package Drupal\tmgmt_xtm\Plugin\tmgmt\Translator
 */
class Helper {
  /**
   * The maximum length allowed for a project name.
   */
  const PROJECT_NAME_LENGTH = 90;

  /**
   * Available project modes.
   *
   * @var array
   */
  private $projectModes = [
    0 => 'Single file - translation returned at the end of the project',
    1 => 'Multiple files - translation returned when each file is complete',
    2 => 'Multiple files - translation returned when all files are complete',
  ];

  /**
   * Read a file from the ZIP archive.
   *
   * @param string $filePath
   *   path to ZIP file.
   *
   * @return string
   *   ZIP content.
   */
  public function readZipArchive($filePath) {
    $zip = @fopen('zip://' . $filePath, 'r');
    if (!$zip) {
      return '';
    }
    $content = '';
    while (!feof($zip)) {
      $content .= fread($zip, 2);
    }
    fclose($zip);

    return $content;
  }

  /**
   * Return all available project modes (with translations).
   *
   * @return array
   *   An array of project modes containing project mode id with description
   */
  public function getProjectModes() {
    $out = [];
    foreach ($this->projectModes as $value) {
      $out[] = t($value);
    }

    return $out;
  }

  /**
   * Returns XTM formatted language code for given tmgmt lang code.
   *
   * @param string $lang
   *   Tmgmt language code to be converted to XTM format.
   * @param \Drupal\tmgmt\Entity\Translator $translator
   *   Translator needs to have remote_language_mappings configured.
   *
   * @return mixed
   *   XTM lang code if given lang was found in translators language mappings,
   *   empty string otherwise
   */
  public function mapLanguageToXTMFormat($lang, Translator $translator) {
    $pluginWrapper = $translator->getSetting('plugin_wrapper');
    return $pluginWrapper['remote_languages_mappings'][$lang] ?? '';
  }

  /**
   * Gets an array of XTM language codes.
   *
   * @return array
   *   An associative array where the keys are language codes and the values
   *   are the corresponding language names.
   */
  public function getXtmLanguage() {
    return json_decode(file_get_contents(__DIR__ . "/countryList.json"), TRUE);
  }

  /**
   * Cleans a label by removing unwanted characters and decoding HTML entities.
   *
   * @param string $label
   *   The label to be cleaned.
   *
   * @return string
   *   The cleaned label.
   */
  public function clearLabel($label) {
    $label = str_replace("&#039;", "'", $label);
    $pattern = [
      '"',
      "*",
      "$",
      "#",
      "^",
      "@",
      "!",
      "?",
      "~",
      "\\",
      "/",
      "&",
      ":",
      ";",
      "<",
      ">",
      "{",
      "}",
      "|",
    ];
    return trim(urldecode(strip_tags(str_replace($pattern, "", html_entity_decode($label)))));
  }

  /**
   * Trims the project name if it exceeds the maximum length.
   *
   * @param string $str
   *   The project name to be trimmed.
   *
   * @return string
   *   The trimmed project name with "..." appended if it was shortened,
   *   otherwise returns the original name.
   */
  public function cutProjectName($str) {
    return strlen($str) > self::PROJECT_NAME_LENGTH ? substr($str, 0, self::PROJECT_NAME_LENGTH) . "..." : $str;
  }

  /**
   * Cleans and sanitizes a file name by removing special characters.
   *
   * @param string $label
   *   The file name to be cleaned.
   *
   * @return string
   *   The sanitized file name with special characters removed and spaces normalized.
   */
  public function clearFileName($label) {
    return trim(preg_replace('/ +/', ' ', preg_replace(
      '/[^A-Za-z0-9 ]/',
      ' ',
      urldecode(preg_replace("/&#?[a-z0-9]+;/i", "", strip_tags($label)))
    )));
  }

  /**
   * Creates a single XML file for a given translation job.
   *
   * @param \Drupal\tmgmt\Entity\Job $job
   *   The translation job entity for which the XML file is to be created.
   *
   * @return array
   *   An array containing the file name, the XML content, and any external descriptors.
   */
  public function createSingleXMLFile(Job $job) {
    $xml = new \SimpleXMLElement('<xtm-drupal-jobs></xtm-drupal-jobs>');
    $data = \Drupal::service('tmgmt.data')->filterTranslatable($this->getJobData($job));
    $data = $this->reorderItems($data);
    foreach ($data as $id => $text) {
      $str = $this->stripInvalidXml($text['#text']);
      $xml->addChild('xtm-drupal-job', htmlspecialchars($str))->addAttribute('id', $id);
    }

    return [
      [
        'fileName'            => $this->filterFileName($job->label(), $job->id()),
        'fileMTOM'            => $xml->asXML(),
        'externalDescriptors' => [],
      ],
    ];
  }

  /**
   * Creates multiple XML files for the given translation job.
   *
   * Each XML file contains a translatable text from the job, organized by its ID.
   *
   * @param \Drupal\tmgmt\Entity\Job $job
   *   The translation job entity.
   *
   * @return array
   *   An array of files where each file contains:
   *   - fileName: The name of the file generated.
   *   - fileMTOM: The XML content of the file.
   *   - externalDescriptors: Additional descriptors, empty in this case.
   */
  public function createMultipleXMLFiles(Job $job) {
    $files = [];
    $data = \Drupal::service('tmgmt.data')->filterTranslatable($this->getJobData($job));

    $data = $this->reorderItems($data);

    foreach ($data as $id => $text) {
      $xml = new \SimpleXMLElement('<xtm-drupal-jobs></xtm-drupal-jobs>');
      $xml->addChild('xtm-drupal-job', htmlspecialchars($text['#text']))->addAttribute('id', $id);

      $files[] = [
        'fileName'            => $this->filterFileName($job->label(), $id),
        'fileMTOM'            => $xml->asXML(),
        'externalDescriptors' => [],
      ];
    }

    return $files;
  }

  /**
   * Strips invalid XML characters from a given string.
   *
   * @param string $value
   *   The input string from which invalid XML characters will be removed.
   *
   * @return string
   *   The sanitized string with invalid XML characters replaced by spaces.
   */
  protected function stripInvalidXml($value) {
    $ret = "";
    if (empty($value)) {
      return $ret;
    }

    $length = strlen($value);
    for ($i = 0; $i < $length; $i++) {
      $current = ord($value[$i]);
      if (($current == 0x9) ||
        ($current == 0xA) ||
        ($current == 0xD) ||
        (($current >= 0x20) && ($current <= 0xD7FF)) ||
        (($current >= 0xE000) && ($current <= 0xFFFD)) ||
        (($current >= 0x10000) && ($current <= 0x10FFFF))
      ) {
        $ret .= chr($current);
      }
      else {
        $ret .= " ";
      }
    }
    return $ret;
  }

  /**
   * Reorders the items in the given data array, prioritizing node titles.
   *
   * The method reorders the items so that any key containing 'node_title'
   * appears first, followed by the remaining items in their original order.
   *
   * @param array $data
   *   An associative array of translatable data items.
   *
   * @return array
   *   The reordered data array with 'node_title' items prioritized.
   */
  protected function reorderItems($data) {
    $out = [];

    foreach ($data as $key => $value) {
      if (preg_match('/node_title/i', $key)) {
        $out[$key] = $value;
        unset($data[$key]);
      }
    }

    return $out += $data;
  }

  /**
   * Create filtered name of MTOM file.
   *
   * @param string $label
   *   The main label for file.
   * @param string $id
   *   File name suffix.
   *
   * @return string
   *   Cleared label and id combined into XML filename
   */
  protected function filterFileName($label, $id) {
    $name = $this->clearFileName($label);
    return str_replace(['@name', '@id'], [$name, $id], '@name_[@id].xml');
  }

  /**
   * Retrieves the data for all active or inactive job items in a translation job.
   *
   * @param \Drupal\tmgmt\Entity\Job $job
   *   The translation job entity from which to retrieve the job items' data.
   *
   * @return array
   *   An associative array where the keys are the job item IDs and the values
   *   are the data arrays for each job item. Each data array contains the translatable
   *   content and may include a '#label' entry if the data label was not initially set.
   */
  protected function getJobData(Job $job) {
    $data = [];
    $jobItems = $job->getItems();
    if ($job->isContinuous()) {
      // We want to send only the files from the last job item.
      $jobItems = [array_key_last($jobItems) => end($jobItems)];
    }
    foreach ($jobItems as $tjiid => $jobItem) {
      /** @var \Drupal\tmgmt\Entity\JobItem $jobItem */
      if ($jobItem->isActive() || $jobItem->isInactive()) {
        $data[$tjiid] = $jobItem->getData();
        // If not set, use the job item label as the data label.
        if (!isset($data[$tjiid]['#label'])) {
          $data[$tjiid]['#label'] = $jobItem->getSourceLabel();
        }
      }
    }

    return $data;
  }

}

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

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