You are here

function _potx_parse_twig_file in Translation template extractor 8

Same name and namespace in other branches
  1. 6.3 potx.inc \_potx_parse_twig_file()
  2. 7.3 potx.inc \_potx_parse_twig_file()
  3. 7.2 potx.inc \_potx_parse_twig_file()

Parse a Twig template for translatables. Drupal 8+.

2 calls to _potx_parse_twig_file()
_potx_process_file in ./potx.inc
Process a file and put extracted information to the given parameters.
_potx_process_inline_templates in ./potx.inc
Process Twig inline templates inside PHP files. Drupal 8+.

File

./potx.inc, line 1960
Extraction API used by the web and command line interface.

Code

function _potx_parse_twig_file($code, $file, $save_callback) {

  // Extract front-matter data, and save text in certain ones.
  $keys_to_save = [
    'label',
  ];

  // Implementation copied from core's \Drupal\help_topics\FrontMatter class.
  $fm_separator = '---';
  $fm_regexp = '/\\A(' . $fm_separator . '(.*?)?\\R' . $fm_separator . ')(\\R.*)?\\Z/s';

  // Check for front matter data.
  $len = strlen($fm_separator);
  $matches = [];
  if (substr($code, 0, $len + 1) === $fm_separator . "\n" || substr($code, 0, $len + 2) === $fm_separator . "\r\n") {
    preg_match($fm_regexp, $code, $matches);
    $matches = array_map('trim', $matches);
  }
  if (!empty($matches[1])) {

    // Set the extracted source code.
    $code = $matches[3];
    try {
      $metadata = Yaml::parse($matches[2]);
      foreach ($metadata as $key => $content) {
        if (in_array($key, $keys_to_save, TRUE)) {
          $save_callback(_potx_format_quoted_string('"' . trim($content) . '"'), POTX_CONTEXT_NONE, $file, 1);
          break;
        }
      }
    } catch (ParseException $e) {
      potx_status('error', t("YAML parsing error on file @path: @error", [
        '@path' => $file,
        '@error' => $e
          ->getMessage(),
      ]), $file);
    }
  }
  if (Environment::MAJOR_VERSION < 2) {
    $twig_lexer = new Lexer(new Environment());
  }
  else {

    // For D9 and superior the environment needs a loader.
    $twigLoader = new FilesystemLoader();
    $twig_lexer = new Lexer(new Environment($twigLoader));
  }
  try {
    $source = new Source($code, $file);
    $stream = $twig_lexer
      ->tokenize($source);
  } catch (SyntaxError $e) {
    potx_status('error', t("Twig parsing error on file @path: @error", [
      '@path' => $file,
      '@error' => $e
        ->getMessage(),
    ]), $file);
    return;
  }
  while (!$stream
    ->isEOF()) {
    $token = $stream
      ->next();

    // Capture strings translated with the t or trans filter.
    if ($token
      ->test(Twig_Token::NAME_TYPE)) {
      $token = $stream
        ->next();
      if ($token
        ->test(Twig_Token::OPERATOR_TYPE, '=')) {
        $token = $stream
          ->next();
        if ($token
          ->test(Twig_Token::STRING_TYPE)) {
          _potx_process_twig_t_filter($token, $stream, $file, $save_callback);
        }
      }
    }
    elseif ($token
      ->test(Twig_Token::VAR_START_TYPE)) {
      $token = $stream
        ->next();
      if ($token
        ->test(Twig_Token::NAME_TYPE)) {
        continue;
      }
      $string = $token
        ->getValue();
      $line = $token
        ->getLine();
      $has_t = FALSE;
      $chained = FALSE;
      $is_concat = FALSE;
      if ($stream
        ->test(Twig_Token::PUNCTUATION_TYPE, '.')) {
        $is_concat = TRUE;
      }
      while (!$stream
        ->isEOF() && ($token = $stream
        ->next()) && !$token
        ->test(Twig_Token::VAR_END_TYPE)) {
        if ($token
          ->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
          if ($stream
            ->test([
            't',
            'trans',
          ])) {
            $has_t = TRUE;
          }
          else {
            $chained = TRUE;
          }
        }
      }
      if ($has_t) {
        if (!$chained && !$is_concat) {
          $save_callback(_potx_format_quoted_string('"' . trim($string) . '"'), POTX_CONTEXT_NONE, $file, $line);
        }
        else {
          $message = t('Uses of the t filter in Twig templates should start with a single literal string, and should not be chained.');

          // TODO: Fill in specific URL for Twig documentation once it exists.
          potx_status('error', $message, $file, NULL, NULL, 'https://drupal.org/developing/api/localization');
        }
      }
    }
    elseif ($token
      ->test(Twig_Token::BLOCK_START_TYPE)) {
      $token = $stream
        ->next();
      if ($token
        ->test('trans')) {
        _potx_process_twig_trans_tag($stream, $file, $save_callback);
      }
    }
    elseif ($token
      ->test(Twig_Token::STRING_TYPE)) {
      _potx_process_twig_t_filter($token, $stream, $file, $save_callback);
    }
  }
}