at path:ROOT / clients / vendor / punic / punic / src / Plural.php
run:R W Run
DIR
2026-04-08 19:42:30
R W Run
DIR
2026-04-08 19:53:13
R W Run
126.16 KB
2026-04-08 19:35:40
R W Run
4.19 KB
2026-04-08 19:35:40
R W Run
8.96 KB
2026-04-08 19:35:41
R W Run
24.16 KB
2026-04-08 19:35:40
R W Run
2 KB
2026-04-08 19:35:42
R W Run
3.93 KB
2026-04-08 19:35:41
R W Run
12.53 KB
2026-04-08 19:35:40
R W Run
17.07 KB
2026-04-08 19:35:39
R W Run
2.3 KB
2026-04-08 19:35:42
R W Run
6.93 KB
2026-04-08 19:35:39
R W Run
20.49 KB
2026-04-08 19:35:40
R W Run
13.16 KB
2026-04-08 19:35:39
R W Run
error_log
📄Plural.php
1<?php
2
3namespace Punic;
4
5/**
6 * Plural helper stuff.
7 */
8class Plural
9{
10 /**
11 * Plural rule type: cardinal (eg 1, 2, 3, ...).
12 *
13 * @var string
14 */
15 const RULETYPE_CARDINAL = 'cardinal';
16
17 /**
18 * Plural rule type: ordinal (eg 1st, 2nd, 3rd, ...).
19 *
20 * @var string
21 */
22 const RULETYPE_ORDINAL = 'ordinal';
23
24 /**
25 * Return the list of applicable plural rule for a locale.
26 *
27 * @param string $locale The locale to use. If empty we'll use the default locale set in \Punic\Data
28 *
29 * @return array<string> Returns a list containing some the following values: 'zero', 'one', 'two', 'few', 'many', 'other' ('other' will be always there)
30 */
31 public static function getRules($locale = '')
32 {
33 $node = Data::getLanguageNode(Data::getGeneric('plurals'), $locale);
34
35 return array_merge(
36 array_keys($node),
37 array('other')
38 );
39 }
40
41 /**
42 * @deprecated Use getRuleOfType with a Plural::RULETYPE_CARDINAL type
43 *
44 * @param string|int|float $number
45 * @param string $locale
46 *
47 * @throws \Punic\Exception\BadArgumentType
48 * @throws \Exception
49 *
50 * @return string
51 */
52 public static function getRule($number, $locale = '')
53 {
54 return self::getRuleOfType($number, self::RULETYPE_CARDINAL);
55 }
56
57 /**
58 * Return the plural rule ('zero', 'one', 'two', 'few', 'many' or 'other') for a number and a locale.
59 *
60 * @param string|int|float $number The number to check the plural rule for for
61 * @param string $type The type of plural rules (one of the \Punic\Plural::RULETYPE_... constants)
62 * @param string $locale The locale to use. If empty we'll use the default locale set in \Punic\Data
63 *
64 * @throws \Punic\Exception\BadArgumentType Throws a \Punic\Exception\BadArgumentType if $number is not a valid number
65 * @throws \Punic\Exception\ValueNotInList Throws a \Punic\Exception\ValueNotInList if $type is not valid
66 * @throws \Exception Throws a \Exception if there were problems calculating the plural rule
67 *
68 * @return string Returns one of the following values: 'zero', 'one', 'two', 'few', 'many', 'other'
69 */
70 public static function getRuleOfType($number, $type, $locale = '')
71 {
72 if (is_int($number)) {
73 $intPartAbs = (string) abs($number);
74 $floatPart = '';
75 } elseif (is_float($number)) {
76 $s = (string) $number;
77 if (strpos($s, '.') === false) {
78 $intPart = $s;
79 $floatPart = '';
80 } else {
81 list($intPart, $floatPart) = explode('.', $s);
82 }
83 $intPartAbs = (string) abs((int) $intPart);
84 } elseif (is_string($number) && $number !== '') {
85 if (preg_match('/^[+|\\-]?\\d+\\.?$/', $number)) {
86 $v = (int) $number;
87 $intPartAbs = (string) abs($v);
88 $floatPart = '';
89 } elseif (preg_match('/^(\\d*)\\.(\\d+)$/', $number, $m)) {
90 list($intPart, $floatPart) = explode('.', $number);
91 $v = @(int) $intPart;
92 $intPartAbs = (string) abs($v);
93 } else {
94 throw new Exception\BadArgumentType($number, 'number');
95 }
96 } else {
97 throw new Exception\BadArgumentType($number, 'number');
98 }
99 // 'n' => '%1$s', // absolute value of the source number (integer and decimals).
100 $v1 = $intPartAbs.(strlen($floatPart) ? ".$floatPart" : '');
101 // 'i' => '%2$s', // integer digits of n
102 $v2 = $intPartAbs;
103 // 'v' => '%3$s', // number of visible fraction digits in n, with trailing zeros.
104 $v3 = strlen($floatPart);
105 // 'w' => '%4$s', // number of visible fraction digits in n, without trailing zeros.
106 $v4 = strlen(rtrim($floatPart, '0'));
107 // 'f' => '%5$s', // visible fractional digits in n, with trailing zeros.
108 $v5 = strlen($floatPart) ? (string) ((int) $floatPart) : '0';
109 // 't' => '%6$s', // visible fractional digits in n, without trailing zeros.
110 $v6 = trim($floatPart, '0');
111 if ($v6 === '') {
112 $v6 = '0';
113 }
114 $result = 'other';
115 $identifierMap = array(
116 self::RULETYPE_CARDINAL => 'plurals',
117 self::RULETYPE_ORDINAL => 'ordinals',
118 );
119 if (!isset($identifierMap[$type])) {
120 throw new Exception\ValueNotInList($type, array_keys($identifierMap));
121 }
122 $identifier = $identifierMap[$type];
123 $node = Data::getLanguageNode(Data::getGeneric($identifier), $locale);
124 foreach ($node as $rule => $formulaPattern) {
125 $formula = sprintf($formulaPattern, $v1, $v2, $v3, $v4, $v5, $v6);
126 $check = str_replace(array('static::inRange(', ' and ', ' or ', ', false, ', ', true, ', ', array('), ' , ', $formula);
127 if (preg_match('/[a-z]/', $check)) {
128 throw new \Exception('Bad formula!');
129 }
130 // fix for difference in modulo (%) in the definition and the one implemented in PHP for decimal numbers
131 while (preg_match('/(\\d+\\.\\d+) % (\\d+(\\.\\d+)?)/', $formula, $m)) {
132 list(, $decimalPart) = explode('.', $m[1], 2);
133 $decimals = strlen(rtrim($decimalPart, '0'));
134 if ($decimals > 0) {
135 $pow = (int) pow(10, $decimals);
136 $repl = '('.(string) ((int) ((float) $m[1] * $pow)).' % '.(string) ((int) ((float) ($m[2] * $pow))).') / '.$pow;
137 } else {
138 $repl = (string) ((int) $m[1]).' % '.$m[2];
139 }
140 $formula = str_replace($m[0], $repl, $formula);
141 }
142 $formulaResult = @eval("return ($formula) ? 'yes' : 'no';");
143 if ($formulaResult === 'yes') {
144 $result = $rule;
145 break;
146 } elseif ($formulaResult !== 'no') {
147 throw new \Exception('There was a problem in the formula '.$formulaPattern);
148 }
149 }
150
151 return $result;
152 }
153
154 /**
155 * @param int|string|array $value
156 * @param bool $mustBeIncluded
157 *
158 * @return bool
159 */
160 protected static function inRange($value, $mustBeIncluded)
161 {
162 if (is_int($value)) {
163 $isInt = true;
164 } elseif ((int) $value == $value) {
165 $isInt = true;
166 } else {
167 $isInt = false;
168 }
169 $rangeValues = (func_num_args() > 2) ? array_slice(func_get_args(), 2) : array();
170 $included = false;
171 foreach ($rangeValues as $rangeValue) {
172 if (is_array($rangeValue)) {
173 if ($isInt && ($value >= $rangeValue[0]) && ($value <= $rangeValue[1])) {
174 $included = true;
175 break;
176 }
177 } elseif ($value == $rangeValue) {
178 $included = true;
179 break;
180 }
181 }
182
183 return $included == $mustBeIncluded;
184 }
185}
186