You are here

protected function PoHeader::evaluatePlural in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Component/Gettext/PoHeader.php \Drupal\Component\Gettext\PoHeader::evaluatePlural()

Evaluate the plural element stack using a plural value.

Using an element stack, which represents a plural formula, we calculate which plural string should be used for a given plural value.

An example of plural formula parting and evaluation: Plural formula: 'n!=1' This formula is parsed by parseArithmetic() to a stack (array) of elements: array( 0 => '$n', 1 => '1', 2 => '!=', ); The evaluatePlural() method evaluates the $element_stack using the plural value $n. Before the actual evaluation, the '$n' in the array is replaced by the value of $n. For example: $n = 2 results in: array( 0 => '2', 1 => '1', 2 => '!=', ); The stack is processed until only one element is (the result) is left. In every iteration the top elements of the stack, up until the first operator, are evaluated. After evaluation the arguments and the operator itself are removed and replaced by the evaluation result. This is typically 2 arguments and 1 element for the operator. Because the operator is '!=' the example stack is evaluated as: $f = (int) 2 != 1; The resulting stack is: array( 0 => 1, ); With only one element left in the stack (the final result) the loop is terminated and the result is returned.

Parameters

array $element_stack: Array of plural formula values and operators create by parseArithmetic().

int $n: The @count number for which we are determining the right plural position.

Return value

int Number of the plural string to be used for the given plural value.

Throws

\Exception

See also

parseArithmetic()

1 call to PoHeader::evaluatePlural()
PoHeader::parsePluralForms in core/lib/Drupal/Component/Gettext/PoHeader.php
Parses a Plural-Forms entry from a Gettext Portable Object file header.

File

core/lib/Drupal/Component/Gettext/PoHeader.php, line 481

Class

PoHeader
Gettext PO header handler.

Namespace

Drupal\Component\Gettext

Code

protected function evaluatePlural($element_stack, $n) {
  $count = count($element_stack);
  $limit = $count;

  // Replace the '$n' value in the formula by the plural value.
  for ($i = 0; $i < $count; $i++) {
    if ($element_stack[$i] === '$n') {
      $element_stack[$i] = $n;
    }
  }

  // We process the stack until only one element is (the result) is left.
  // We limit the number of evaluation cycles to prevent an endless loop in
  // case the stack contains an error.
  while (isset($element_stack[1])) {
    for ($i = 2; $i < $count; $i++) {

      // There's no point in checking non-symbols. Also, switch(TRUE) would
      // match any case and so it would break.
      if (is_bool($element_stack[$i]) || is_numeric($element_stack[$i])) {
        continue;
      }
      $f = NULL;
      $length = 3;
      $delta = 2;
      switch ($element_stack[$i]) {
        case '==':
          $f = $element_stack[$i - 2] == $element_stack[$i - 1];
          break;
        case '!=':
          $f = $element_stack[$i - 2] != $element_stack[$i - 1];
          break;
        case '<=':
          $f = $element_stack[$i - 2] <= $element_stack[$i - 1];
          break;
        case '>=':
          $f = $element_stack[$i - 2] >= $element_stack[$i - 1];
          break;
        case '<':
          $f = $element_stack[$i - 2] < $element_stack[$i - 1];
          break;
        case '>':
          $f = $element_stack[$i - 2] > $element_stack[$i - 1];
          break;
        case '+':
          $f = $element_stack[$i - 2] + $element_stack[$i - 1];
          break;
        case '-':
          $f = $element_stack[$i - 2] - $element_stack[$i - 1];
          break;
        case '*':
          $f = $element_stack[$i - 2] * $element_stack[$i - 1];
          break;
        case '/':
          $f = $element_stack[$i - 2] / $element_stack[$i - 1];
          break;
        case '%':
          $f = $element_stack[$i - 2] % $element_stack[$i - 1];
          break;
        case '&&':
          $f = $element_stack[$i - 2] && $element_stack[$i - 1];
          break;
        case '||':
          $f = $element_stack[$i - 2] || $element_stack[$i - 1];
          break;
        case ':':
          $f = $element_stack[$i - 3] ? $element_stack[$i - 2] : $element_stack[$i - 1];

          // This operator has 3 preceding elements, instead of the default 2.
          $length = 5;
          $delta = 3;
          break;
      }

      // If the element is an operator we remove the processed elements and
      // store the result.
      if (isset($f)) {
        array_splice($element_stack, $i - $delta, $length, $f);
        break;
      }
    }
  }
  if (!$limit) {
    throw new \Exception('The plural formula could not be evaluated.');
  }
  return (int) $element_stack[0];
}