1 | <?php |
||
2 | |||
3 | namespace ICanBoogie\CLDR\Supplemental; |
||
4 | |||
5 | use ArrayObject; |
||
6 | use ICanBoogie\CLDR\Supplemental\Plurals\Rule; |
||
7 | use ICanBoogie\CLDR\Supplemental\Plurals\Samples; |
||
8 | |||
9 | use function array_keys; |
||
10 | use function array_shift; |
||
11 | use function explode; |
||
12 | use function is_null; |
||
13 | use function strlen; |
||
14 | use function strpos; |
||
15 | use function substr; |
||
16 | use function trim; |
||
17 | |||
18 | /** |
||
19 | * Representation of plurals |
||
20 | * |
||
21 | * @extends ArrayObject<string, array<string, string>> |
||
22 | * Where _key_ is a locale and _value_ a rule. |
||
23 | */ |
||
24 | final class Plurals extends ArrayObject |
||
25 | { |
||
26 | public const COUNT_ZERO = 'zero'; |
||
27 | public const COUNT_ONE = 'one'; |
||
28 | public const COUNT_TWO = 'two'; |
||
29 | public const COUNT_FEW = 'few'; |
||
30 | public const COUNT_MANY = 'many'; |
||
31 | public const COUNT_OTHER = 'other'; |
||
32 | |||
33 | /** |
||
34 | * @private |
||
35 | */ |
||
36 | public const RULE_COUNT_PREFIX = 'pluralRule-count-'; |
||
37 | |||
38 | /** |
||
39 | * @var array<string, array<self::COUNT_*, Rule>> |
||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||
40 | * Where _key_ is a locale code and _value_ an array where _key_ is a rule count. |
||
41 | */ |
||
42 | private array $rules = []; |
||
43 | |||
44 | /** |
||
45 | * @var array<string, array<self::COUNT_*, Samples>> |
||
0 ignored issues
–
show
|
|||
46 | * Where _key_ is a locale code and _value_ an array where _key_ is a rule count. |
||
47 | */ |
||
48 | private array $samples = []; |
||
49 | |||
50 | /** |
||
51 | * @param float|int|numeric-string $number |
||
0 ignored issues
–
show
|
|||
52 | * |
||
53 | * @return self::COUNT_* |
||
54 | */ |
||
55 | public function rule_for(float|int|string $number, string $language): string |
||
56 | { |
||
57 | $rules = $this->rule_instances_for($language); |
||
58 | |||
59 | foreach ($rules as $count => $rule) { |
||
60 | if ($rule->validate($number)) { |
||
61 | return $count; |
||
62 | } |
||
63 | } |
||
64 | |||
65 | return self::COUNT_OTHER; |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * @return array<self::COUNT_*> |
||
0 ignored issues
–
show
|
|||
70 | */ |
||
71 | public function rules_for(string $locale): array |
||
72 | { |
||
73 | return array_keys($this->rule_instances_for($locale)); |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * @return array<self::COUNT_*, Samples> |
||
0 ignored issues
–
show
|
|||
78 | */ |
||
79 | public function samples_for(string $locale): array |
||
80 | { |
||
81 | return $this->samples[$locale] ??= $this->create_samples_for($locale); |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * @return array<self::COUNT_*, Rule> |
||
0 ignored issues
–
show
|
|||
86 | */ |
||
87 | private function rule_instances_for(string $language): array |
||
88 | { |
||
89 | return $this->rules[$language] ??= $this->create_rules_for($language); |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * @return array<self::COUNT_*, Rule> |
||
0 ignored issues
–
show
|
|||
94 | */ |
||
95 | private function create_rules_for(string $language): array |
||
96 | { |
||
97 | $rules = []; |
||
98 | $prefix_length = strlen(self::RULE_COUNT_PREFIX); |
||
99 | |||
100 | /** @phpstan-ignore-next-line */ |
||
101 | foreach ($this[$language] as $count => $rule_string) { |
||
102 | $count = substr($count, $prefix_length); |
||
103 | $rules[$count] = Rule::from($this->extract_rule($rule_string)); |
||
104 | } |
||
105 | |||
106 | /** @var array<self::COUNT_*, Rule> */ |
||
107 | return $rules; |
||
108 | } |
||
109 | |||
110 | private function extract_rule(string $rule_string): string |
||
111 | { |
||
112 | $rule = explode('@', $rule_string, 2); |
||
113 | $rule = array_shift($rule); |
||
114 | |||
115 | return trim($rule); |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * @return array<self::COUNT_*, Samples> |
||
0 ignored issues
–
show
|
|||
120 | */ |
||
121 | private function create_samples_for(string $locale): array |
||
122 | { |
||
123 | $samples = []; |
||
124 | $prefix_length = strlen(self::RULE_COUNT_PREFIX); |
||
125 | $rules = $this[$locale]; |
||
126 | |||
127 | assert(!is_null($rules)); |
||
128 | |||
129 | foreach ($rules as $count => $rule_string) { |
||
130 | $count = substr($count, $prefix_length); |
||
131 | $samples[$count] = Samples::from($this->extract_samples($rule_string)); |
||
132 | } |
||
133 | |||
134 | /** @var array<self::COUNT_*, Samples> */ |
||
135 | return $samples; |
||
136 | } |
||
137 | |||
138 | private function extract_samples(string $rule_string): string |
||
139 | { |
||
140 | $pos = strpos($rule_string, '@'); |
||
141 | |||
142 | if ($pos === false) { |
||
143 | return ""; |
||
144 | } |
||
145 | |||
146 | return substr($rule_string, $pos); |
||
147 | } |
||
148 | } |
||
149 |