parent
49623698ff
commit
0698191e66
|
@ -13,7 +13,6 @@ use Drupal\Component\Utility\Settings;
|
|||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Config\ConfigException;
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Component\Gettext\PoHeader;
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -481,14 +480,9 @@ function update_prepare_d8_language() {
|
|||
$prefixes = array();
|
||||
$domains = array();
|
||||
foreach ($languages as $language) {
|
||||
$header = new PoHeader($language->language);
|
||||
$language->formula = str_replace('$n', 'n', $language->formula);
|
||||
$plural_forms = 'nplurals=' . $language->plurals . '; plural=' . $language->formula . ';';
|
||||
$parsed = $header->parsePluralForms($plural_forms);
|
||||
list($nplurals, $formula) = $parsed;
|
||||
$plurals[$language->language] = array(
|
||||
'plurals' => $nplurals,
|
||||
'formula' => $formula,
|
||||
'plurals' => $language->plurals,
|
||||
'formula' => $language->formula,
|
||||
);
|
||||
$javascript[$language->language] = $language->javascript;
|
||||
$prefixes[$language->language] = $language->prefix;
|
||||
|
|
|
@ -189,14 +189,10 @@ class PoHeader {
|
|||
* The Plural-Forms entry value.
|
||||
*
|
||||
* @return
|
||||
* An indexed array of parsed plural formula data. Containing:
|
||||
* - 'nplurals': The number of plural forms defined by the plural formula.
|
||||
* - 'plurals': Array of plural positions keyed by plural value.
|
||||
*
|
||||
* @throws Exception
|
||||
* An array containing the number of plural forms and the converted version
|
||||
* of the formula that can be evaluated with PHP later.
|
||||
*/
|
||||
function parsePluralForms($pluralforms) {
|
||||
$plurals = array();
|
||||
// First, delete all whitespace.
|
||||
$pluralforms = strtr($pluralforms, array(" " => "", "\t" => ""));
|
||||
|
||||
|
@ -218,31 +214,14 @@ class PoHeader {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
// If the number of plurals is zero, we return a default result.
|
||||
if ($nplurals == 0) {
|
||||
return array($nplurals, array('default' => 0));
|
||||
}
|
||||
// Get PHP version of the plural formula.
|
||||
$plural = $this->parseArithmetic($plural);
|
||||
|
||||
// Calculate possible plural positions of different plural values. All known
|
||||
// plural formula's are repetitive above 100.
|
||||
// For data compression we store the last position the array value
|
||||
// changes and store it as default.
|
||||
$element_stack = $this->parseArithmetic($plural);
|
||||
$default = 0;
|
||||
if ($element_stack !== FALSE) {
|
||||
for ($i = 0; $i <= 199; $i++) {
|
||||
$plurals[$i] = $this->evaluatePlural($element_stack, $i);
|
||||
}
|
||||
$default = $plurals[$i - 1];
|
||||
$plurals = array_filter($plurals, function ($value) use ($default) {
|
||||
return ($value != $default);
|
||||
});
|
||||
$plurals['default'] = $default;
|
||||
|
||||
return array($nplurals, $plurals);
|
||||
if ($plural !== FALSE) {
|
||||
return array($nplurals, $plural);
|
||||
}
|
||||
else {
|
||||
throw new \Exception('The plural formula could not be parsed.');
|
||||
throw new Exception('The plural formula could not be parsed.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,7 +247,7 @@ class PoHeader {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses and sanitizes an arithmetic formula into a plural element stack.
|
||||
* Parses and sanitizes an arithmetic formula into a PHP expression.
|
||||
*
|
||||
* While parsing, we ensure, that the operators have the right
|
||||
* precedence and associativity.
|
||||
|
@ -277,7 +256,7 @@ class PoHeader {
|
|||
* A string containing the arithmetic formula.
|
||||
*
|
||||
* @return
|
||||
* A stack of values and operations to be evaluated.
|
||||
* A version of the formula to evaluate with PHP later.
|
||||
*/
|
||||
private function parseArithmetic($string) {
|
||||
// Operator precedence table.
|
||||
|
@ -340,9 +319,8 @@ class PoHeader {
|
|||
$element_stack[] = $topop;
|
||||
$topop = array_pop($operator_stack);
|
||||
}
|
||||
$return = $element_stack;
|
||||
|
||||
// Now validate stack.
|
||||
// Now extract formula from stack.
|
||||
$previous_size = count($element_stack) + 1;
|
||||
while (count($element_stack) < $previous_size) {
|
||||
$previous_size = count($element_stack);
|
||||
|
@ -366,7 +344,12 @@ class PoHeader {
|
|||
}
|
||||
|
||||
// If only one element is left, the number of operators is appropriate.
|
||||
return count($element_stack) == 1 ? $return : FALSE;
|
||||
if (count($element_stack) == 1) {
|
||||
return $element_stack[0];
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -434,136 +417,4 @@ class PoHeader {
|
|||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param array $element_stack
|
||||
* Array of plural formula values and operators create by parseArithmetic().
|
||||
* @param integer $n
|
||||
* The @count number for which we are determining the right plural position.
|
||||
*
|
||||
* @return integer
|
||||
* Number of the plural string to be used for the given plural value.
|
||||
*
|
||||
* @see parseArithmetic()
|
||||
* @throws Exception
|
||||
*/
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,15 +98,11 @@ class LocalePluralFormatTest extends WebTestBase {
|
|||
1 => 0,
|
||||
0 => 1,
|
||||
5 => 1,
|
||||
123 => 1,
|
||||
235 => 1,
|
||||
),
|
||||
'fr' => array(
|
||||
1 => 0,
|
||||
0 => 0,
|
||||
5 => 1,
|
||||
123 => 1,
|
||||
235 => 1,
|
||||
),
|
||||
'hr' => array(
|
||||
1 => 0,
|
||||
|
@ -114,8 +110,6 @@ class LocalePluralFormatTest extends WebTestBase {
|
|||
0 => 2,
|
||||
2 => 1,
|
||||
8 => 2,
|
||||
123 => 1,
|
||||
235 => 2,
|
||||
),
|
||||
'hu' => array(
|
||||
1 => -1,
|
||||
|
|
|
@ -363,12 +363,9 @@ function locale_get_plural($count, $langcode = NULL) {
|
|||
// $count and statically cache the result for the combination of language
|
||||
// and count, since the result will always be identical.
|
||||
if (!empty($plural_formulas[$langcode])) {
|
||||
// Plural formulas are stored as an array for 0-199. 100 is the highest
|
||||
// modulo used but storing 0-99 is not enough because below 100 we often
|
||||
// find exceptions (1, 2, etc).
|
||||
$index = $count > 199 ? 100 + ($count % 100) : $count;
|
||||
$plural_indexes[$langcode][$count] = isset($plural_formulas[$langcode]['formula'][$index]) ? $plural_formulas[$langcode]['formula'][$index] : $plural_formulas[$langcode]['formula']['default'];
|
||||
|
||||
// $n is used inside the expression in the eval().
|
||||
$n = $count;
|
||||
$plural_indexes[$langcode][$count] = @eval('return intval(' . $plural_formulas[$langcode]['formula'] . ');');
|
||||
}
|
||||
// In case there is no plural formula for English (no imported translation
|
||||
// for English), use a default formula.
|
||||
|
|
Loading…
Reference in New Issue