l10n_server-2.x-dev/l10n_server/src/L10nHelper.php

l10n_server/src/L10nHelper.php
<?php

declare(strict_types=1);

namespace Drupal\l10n_server;

use Drupal\Component\Utility\Unicode;
use Drupal\l10n_server\Entity\L10nServerFile;
use Drupal\l10n_server\Entity\L10nServerLine;
use Drupal\l10n_server\Entity\L10nServerReleaseInterface;
use Drupal\l10n_server\Entity\L10nServerString;

/**
 * Service description.
 */
class L10nHelper {

  /**
   * Determine the branch for a release.
   *
   * @param \Drupal\l10n_server\Entity\L10nServerReleaseInterface $release
   *   The release object.
   *
   * @fixme this method might no longer be relevant.
   */
  public static function releaseSetBranch(L10nServerReleaseInterface &$release): void {
    // Set branch to everything before the last dot, and append an x. For
    // example, 6.1, 6.2, 6.x-dev, 6.0-beta1 all become 6.x. 8.7.13 becomes
    // 8.7.x. 6.x-1.0-beta1 becomes 6.x-1.x. 2.1.0-rc1 becomes 2.1.x.
    $release->branch = preg_replace('#\.[^.]*$#', '.x', $release->label());

    // Stupid hack for drupal core.
    if ($release->uri === 'drupal') {
      // Version has -extra removed, 6.0-beta1 becomes 6.0.
      $release->version = explode('-', $release->label())[0];

      // Major version is the first component before the dot (.).
      $major = explode('.', $release->branch)[0];
      if ($major >= 8) {
        // In D8 & later, start removing 'API compatibility' part of the path.
        $release->core = 'all';
      }
      else {
        $release->core = $major . '.x';
      }
    }
    else {
      // Modules are like: 6.x-1.0, 6.x-1.x-dev, 6.x-1.0-beta1, 2.0.0, 5.x-dev,
      // 2.1.x-dev, 2.1.0-rc1. If there is a core API compatibility component,
      // split it off. version here is the main version number, without the
      // -{extra} component, like -beta1 or -rc1.
      preg_match('#^(?:(?<core>(?:4\.0|4\.1|4\.2|4\.3|4\.4|4\.5|4\.6|4\.7|5|6|7|8|9)\.x)-)?(?<version>[0-9.x]*)(?:-.*)?$#', $release->getVersion(), $match);
      $release->core = $match['core'] ?: 'all';
      $release->version = $match['version'];
    }
  }

  /**
   * CVS revision saver callback for potx.
   *
   * We call it with a release id if $file is not given. And we ask for a file
   * ID (to save the string with), if $revision is not given.
   *
   * This is called:
   *  - before any file parsing with (array($pid, $rid), NULL)
   *  - just as a new file is found by potx with ($revision, $file)
   *  - just as a new string is found by our own callback with (NULL, $file)
   *
   * @param string|array $revision
   *   CVS revision information about $file. If not given, the recorded fid of
   *   $file will be returned in an array with ($pid, $rid, $fid).
   * @param string $file
   *   File location in package. If not given, $revision is taken as an array
   *   with project and release id to use to store the file list.
   *
   * @return array|null
   *   An array of data for a specific file or NULL.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public static function saveFile($revision = NULL, $file = NULL) {
    static $pid = 0;
    static $rid = 0;
    static $files = [];

    if (!isset($file)) {
      // We get the release number for the files.
      [$pid, $rid] = $revision;
    }
    elseif (!isset($revision)) {
      // We return data for a specific file.
      return [$pid, $rid, $files[$file]];
    }
    else {
      $existing_file = \Drupal::database()
        ->select('l10n_server_file', 'l')
        ->fields('l')
        ->condition('rid', $rid)
        ->condition('location', $file)
        ->execute()
        ->fetchObject();
      if ($existing_file) {
        if ($existing_file->revision != $revision) {
          // Changed revision on a file.
          /** @var \Drupal\l10n_server\Entity\L10nServerFileInterface $entity */
          $entity = \Drupal::entityTypeManager()
            ->getStorage('l10n_server_file')
            ->load($existing_file->fid);
          $entity->set('revision', $revision)->save();
        }
        $fid = $existing_file->fid;
      }
      else {
        if (!$pid || !$rid) {
          return;
        }
        // New file in this release.
        /** @var \Drupal\l10n_server\Entity\L10nServerFileInterface $entity */
        $entity = L10nServerFile::create([
          'pid' => $pid,
          'rid' => $rid,
          'location' => $file,
          'revision' => $revision,
        ]);
        $entity->save();
        $fid = $entity->id();
      }
      $files[$file] = $fid;
    }
  }

  /**
   * A counter we use for strings added. Each source strings is counted once.
   *
   * @param string $sid
   *   The string to count.
   * @param bool $reset
   *   Whether to reset the static cache.
   *
   * @return int|null
   *   A count integer or void.
   */
  public static function addedStringCounter($sid = NULL, $reset = FALSE) {
    static $sids = [];

    if ($reset) {
      $sids = [];
    }
    elseif (empty($sid)) {
      return count($sids);
    }
    else {
      $sids[$sid] = 1;
    }
  }

  /**
   * String saving callback for potx.
   *
   * @param string $value
   *   String value to store.
   * @param string $context
   *   From Drupal 7, separate contexts are supported. POTX_CONTEXT_NONE is
   *   the default, if the code does not specify a context otherwise.
   * @param string $file
   *   Name of file the string occurred in.
   * @param int $line
   *   Number of line the string was found.
   * @param int $string_type
   *   String type: POTX_STRING_INSTALLER, POTX_STRING_RUNTIME
   *   or POTX_STRING_BOTH.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   *
   * @todo More elegant plural handling.
   * @todo Find a way to properly use POTX constants before potx.inc is loaded.
   */
  public static function saveString($value = NULL, $context = NULL, $file = NULL, $line = 0, $string_type = 2 /*POTX_STRING_RUNTIME*/): void {
    static $files = [];

    // Strip all slashes from string.
    $value = stripcslashes($value);

    if (!isset($files[$file])) {
      // Get file ID for saving, locally cache.
      $files[$file] = self::saveFile(NULL, $file);
    }

    // The database uses a TEXT field for storage which has a maximum length of
    // 65,535 characters (bytes), so we need to make sure to refuse long
    // strings. It is not realistic to ever get close to this length for human
    // translation. strlen() counts bytes, so it is safe to use even with UTF
    // characters here.
    // See https://dev.mysql.com/doc/refman/5.6/en/string-type-syntax.html
    if (strlen($value) > 65000) {
      potx_status('error', t('Translatable source strings should be shorter than 64k characters.'), $file, $line);
      return;
    }

    // Value set but empty. Mark error on empty translatable string. Only trim
    // for empty string checking, since we should store leading/trailing
    // whitespace as it appears in the string otherwise.
    $check_empty = trim($value);
    if (empty($check_empty)) {
      potx_status('error', t('Empty string attempted to be localized. Please do not leave test code for localization in your source.'), $file, $line);
      return;
    }

    if (!Unicode::validateUtf8($value)) {
      potx_status('error', t('Invalid UTF-8 string attempted to be localized.'), $file, $line);
      return;
    }

    // If we have the file entry now, we can process adding the string.
    if (isset($files[$file])) {
      // Explode files array to pid, rid and fid.
      [$pid, $rid, $fid] = $files[$file];
      // Context cannot be null.
      $context = !is_null($context) ? $context : '';

      // A \0 separator in the string means we deal with a string with plural
      // variants. Unlike Drupal core, we store all in the same string, as it is
      // easier to handle later, and we don't need the individual string parts.
      $sid = \Drupal::database()
        ->select("l10n_server_string", 'l')
        ->fields('l', ['sid'])
        ->condition('hashkey', md5($value . $context))
        ->execute()
        ->fetchField();
      if (!$sid) {
        // String does not exist.
        $entity = L10nServerString::create([
          'value' => $value,
          'context' => $context,
          'hashkey' => md5($value . $context),
        ]);
        $entity->save();
        $sid = $entity->id();
      }
      $existing_fid = \Drupal::database()
        ->select('l10n_server_line', 'l')
        ->fields('l', ['fid'])
        ->condition('fid', $fid)
        ->condition('sid', $sid)
        ->condition('lineno', $line)
        ->condition('type', $string_type)
        ->execute()
        ->fetchField();
      if (!$existing_fid) {
        $entity = L10nServerLine::create([
          'pid' => $pid,
          'rid' => $rid,
          'fid' => $fid,
          'sid' => $sid,
          'lineno' => $line,
          'type' => $string_type,
        ]);
        $entity->save();
      }
      self::addedStringCounter($sid);
    }
  }

}

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

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