Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
84.93% |
62 / 73 |
|
63.64% |
7 / 11 |
CRAP | |
0.00% |
0 / 1 |
L11nManager | |
84.93% |
62 / 73 |
|
63.64% |
7 / 11 |
35.50 | |
0.00% |
0 / 1 |
isLanguageLoaded | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
loadLanguage | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
loadLanguageFile | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
loadLanguageFromFile | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getModuleLanguage | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
4 | |||
getText | |
62.50% |
5 / 8 |
|
0.00% |
0 / 1 |
4.84 | |||
getHtml | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getNumeric | |
58.33% |
7 / 12 |
|
0.00% |
0 / 1 |
2.29 | |||
getPercentage | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getCurrency | |
91.67% |
22 / 24 |
|
0.00% |
0 / 1 |
9.05 | |||
getDateTime | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Localization |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Localization; |
16 | |
17 | use phpOMS\Autoloader; |
18 | use phpOMS\Log\FileLogger; |
19 | use phpOMS\Module\ModuleAbstract; |
20 | use phpOMS\Stdlib\Base\FloatInt; |
21 | |
22 | /** |
23 | * Localization class. |
24 | * |
25 | * @package phpOMS\Localization |
26 | * @license OMS License 2.0 |
27 | * @link https://jingga.app |
28 | * @since 1.0.0 |
29 | */ |
30 | final class L11nManager |
31 | { |
32 | /** |
33 | * Language. |
34 | * |
35 | * @var array<string, array<int|string, array<string, string>>> |
36 | * @since 1.0.0 |
37 | */ |
38 | private array $language = []; |
39 | |
40 | /** |
41 | * Verify if language is loaded. |
42 | * |
43 | * @param string $language Language iso code |
44 | * |
45 | * @return bool |
46 | * |
47 | * @since 1.0.0 |
48 | */ |
49 | public function isLanguageLoaded(string $language) : bool |
50 | { |
51 | return isset($this->language[$language]); |
52 | } |
53 | |
54 | /** |
55 | * Load language. |
56 | * |
57 | * One module can only be loaded once. Once the module got loaded it's not |
58 | * possible to load more language files later on. |
59 | * |
60 | * @param string $language Language iso code |
61 | * @param string $from Module name |
62 | * @param array<string, array<string, string>> $translation Language files content |
63 | * |
64 | * @return void |
65 | * |
66 | * @since 1.0.0 |
67 | */ |
68 | public function loadLanguage(string $language, string $from, array $translation) : void |
69 | { |
70 | if (!isset($translation[$from])) { |
71 | return; |
72 | } |
73 | |
74 | $this->language[$language][$from] = isset($this->language[$language][$from]) |
75 | ? $translation[$from] + $this->language[$language][$from] |
76 | : $translation[$from]; |
77 | } |
78 | |
79 | /** |
80 | * Load language file which contains multiple languages. |
81 | * |
82 | * @param string $from Module name |
83 | * @param string $file File to import language from |
84 | * |
85 | * @return void |
86 | * |
87 | * @since 1.0.0 |
88 | */ |
89 | public function loadLanguageFile(string $from, string $file) : void |
90 | { |
91 | if (!\is_file($file)) { |
92 | return; |
93 | } |
94 | |
95 | /** @noinspection PhpIncludeInspection */ |
96 | $lang = include $file; |
97 | |
98 | foreach ($lang as $code => $translation) { |
99 | $this->loadLanguage($code, $from, $translation); |
100 | } |
101 | } |
102 | |
103 | /** |
104 | * Load language from file. |
105 | * |
106 | * One module can only be loaded once. Once the module got loaded it's not |
107 | * possible to load more language files later on. |
108 | * |
109 | * @param string $language Language iso code |
110 | * @param string $from Module name |
111 | * @param string $file File to import language from |
112 | * |
113 | * @return void |
114 | * |
115 | * @since 1.0.0 |
116 | */ |
117 | public function loadLanguageFromFile(string $language, string $from, string $file) : void |
118 | { |
119 | if (!\is_file($file)) { |
120 | return; |
121 | } |
122 | |
123 | /** @noinspection PhpIncludeInspection */ |
124 | $lang = include $file; |
125 | $this->loadLanguage($language, $from, $lang); |
126 | } |
127 | |
128 | /** |
129 | * Get application language. |
130 | * |
131 | * @param string $language Language iso code |
132 | * @param string $module Module name |
133 | * |
134 | * @return array<int|string, array<string, string>>|array<string, string> |
135 | * |
136 | * @since 1.0.0 |
137 | */ |
138 | public function getModuleLanguage(string $language, string $module = null) : array |
139 | { |
140 | if ($module === null && isset($this->language[$language])) { |
141 | return $this->language[$language]; |
142 | } elseif (isset($this->language[$language], $this->language[$language][$module])) { |
143 | return $this->language[$language][$module]; |
144 | } |
145 | |
146 | return []; |
147 | } |
148 | |
149 | /** |
150 | * Get translation. |
151 | * |
152 | * @param string $code Language code |
153 | * @param string $module Module name |
154 | * @param string $theme Theme |
155 | * @param string $translation Text |
156 | * |
157 | * @return string In case the language element couldn't be found 'ERROR' will be returned |
158 | * |
159 | * @since 1.0.0 |
160 | */ |
161 | public function getText(string $code, string $module, string $theme, string $translation) : string |
162 | { |
163 | if (isset($this->language[$code][$module][$translation])) { |
164 | return $this->language[$code][$module][$translation]; |
165 | } |
166 | |
167 | try { |
168 | /** @var ModuleAbstract $class */ |
169 | $class = '\Modules\\' . $module . '\\Controller\\Controller'; |
170 | |
171 | /** @var string $class */ |
172 | if (!Autoloader::exists($class)) { |
173 | return 'ERROR-' . $translation; |
174 | } |
175 | |
176 | $this->loadLanguage($code, $module, $class::getLocalization($code, $theme)); |
177 | } catch (\Throwable $_) { |
178 | // @codeCoverageIgnoreStart |
179 | FileLogger::getInstance()->warning(FileLogger::MSG_FULL, [ |
180 | 'message' => 'Undefined translation for \'' . $code . '/' . $module . '/' . $translation . '\'.', |
181 | ]); |
182 | // @codeCoverageIgnoreEnd |
183 | } |
184 | |
185 | return $this->language[$code][$module][$translation] ?? 'ERROR-' . $translation; |
186 | } |
187 | |
188 | /** |
189 | * Get translation html escaped. |
190 | * |
191 | * @param string $code Language code |
192 | * @param string $module Module name |
193 | * @param string $theme Theme |
194 | * @param string $translation Text |
195 | * |
196 | * @return string In case the language element couldn't be found 'ERROR' will be returned |
197 | * |
198 | * @since 1.0.0 |
199 | */ |
200 | public function getHtml(string $code, string $module, string $theme, string $translation) : string |
201 | { |
202 | return \htmlspecialchars($this->getText($code, $module, $theme, $translation)); |
203 | } |
204 | |
205 | /** |
206 | * Print a numeric value |
207 | * |
208 | * @param Localization $l11n Localization |
209 | * @param int|float|FloatInt $numeric Numeric value to print |
210 | * @param null|string $format Format type to use |
211 | * |
212 | * @return string |
213 | * |
214 | * @since 1.0.0 |
215 | */ |
216 | public function getNumeric(Localization $l11n, int | float | FloatInt $numeric, string $format = null) : string |
217 | { |
218 | if (!($numeric instanceof FloatInt)) { |
219 | return \number_format( |
220 | $numeric, |
221 | $l11n->getPrecision()[$format ?? 'medium'], |
222 | $l11n->getDecimal(), |
223 | $l11n->getThousands() |
224 | ); |
225 | } |
226 | |
227 | $numeric->setLocalization( |
228 | $l11n->getThousands(), |
229 | $l11n->getDecimal() |
230 | ); |
231 | |
232 | return $numeric->getAmount($l11n->getPrecision()[$format ?? 'medium']); |
233 | } |
234 | |
235 | /** |
236 | * Print a percentage value |
237 | * |
238 | * @param Localization $l11n Localization |
239 | * @param float $percentage Percentage value to print |
240 | * @param null|string $format Format type to use |
241 | * |
242 | * @return string |
243 | * |
244 | * @since 1.0.0 |
245 | */ |
246 | public function getPercentage(Localization $l11n, float $percentage, string $format = null) : string |
247 | { |
248 | return \number_format( |
249 | $percentage, $l11n->getPrecision()[$format ?? 'medium'], |
250 | $l11n->getDecimal(), |
251 | $l11n->getThousands() |
252 | ) . '%'; |
253 | } |
254 | |
255 | /** |
256 | * Print a currency |
257 | * |
258 | * @param Localization $l11n Localization |
259 | * @param int|float|FloatInt|Money $currency Currency value to print |
260 | * @param null|string $symbol Currency name/symbol |
261 | * @param null|string $format Format type to use |
262 | * @param int $divide Divide currency by divisor |
263 | * |
264 | * @return string |
265 | * |
266 | * @since 1.0.0 |
267 | */ |
268 | public function getCurrency( |
269 | Localization $l11n, |
270 | int | float | Money | FloatInt $currency, |
271 | string $symbol = null, |
272 | string $format = null, |
273 | int $divide = 1 |
274 | ) : string |
275 | { |
276 | $language = $l11n->language; |
277 | $symbol ??= $l11n->getCurrency(); |
278 | |
279 | if (\is_float($currency)) { |
280 | $currency = (int) ($currency * \pow(10, Money::MAX_DECIMALS)); |
281 | } |
282 | |
283 | if ($divide > 1 && !empty($symbol)) { |
284 | if ($divide === 1000) { |
285 | $symbol = $this->getHtml($language, '0', '0', 'CurrencyK') . $symbol; |
286 | } elseif ($divide === 1000000) { |
287 | $symbol = $this->getHtml($language, '0', '0', 'CurrencyM') . $symbol; |
288 | } elseif ($divide === 1000000000) { |
289 | $symbol = $this->getHtml($language, '0', '0', 'CurrencyB') . $symbol; |
290 | } |
291 | } |
292 | |
293 | $money = null; |
294 | if ($currency instanceof Money) { |
295 | $money = $currency; |
296 | } elseif ($currency instanceof FloatInt) { |
297 | $money = new Money((int) ($currency->value / $divide)); |
298 | } else { |
299 | $money = new Money((int) ($currency / $divide)); |
300 | } |
301 | |
302 | $money->setLocalization( |
303 | $l11n->getThousands(), |
304 | $l11n->getDecimal(), |
305 | $symbol, |
306 | (int) $l11n->getCurrencyFormat() |
307 | ); |
308 | |
309 | return $money->getCurrency($l11n->getPrecision()[$format ?? 'medium']); |
310 | } |
311 | |
312 | /** |
313 | * Print a datetime |
314 | * |
315 | * @param Localization $l11n Localization |
316 | * @param null|\DateTimeInterface $datetime DateTime to print |
317 | * @param string $format Format type to use |
318 | * |
319 | * @return string |
320 | * |
321 | * @since 1.0.0 |
322 | */ |
323 | public function getDateTime(Localization $l11n, \DateTimeInterface $datetime = null, string $format = null) : string |
324 | { |
325 | return $datetime === null |
326 | ? '' |
327 | : $datetime->format($l11n->getDateTime()[$format ?? 'medium']); |
328 | } |
329 | } |