Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.59% covered (warning)
88.59%
132 / 149
94.59% covered (success)
94.59%
35 / 37
CRAP
0.00% covered (danger)
0.00%
0 / 1
Localization
88.59% covered (warning)
88.59%
132 / 149
94.59% covered (success)
94.59%
35 / 37
58.33
0.00% covered (danger)
0.00%
0 / 1
 getId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromLanguage
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 fromJson
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 loadFromLanguage
95.92% covered (success)
95.92%
47 / 49
0.00% covered (danger)
0.00%
0 / 1
9
 importLocale
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 setCountry
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getTimezone
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTimezone
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setLanguage
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getCurrency
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setCurrency
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getCurrencyFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setCurrencyFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDatetime
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDatetime
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDecimal
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDecimal
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getThousands
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setThousands
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAngle
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setAngle
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getTemperature
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTemperature
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getSpeed
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSpeed
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getWeight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setWeight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLength
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setLength
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getArea
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setArea
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getVolume
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPrecision
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPrecision
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setVolume
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toArray
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 jsonSerialize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
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 */
13declare(strict_types=1);
14
15namespace phpOMS\Localization;
16
17use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
18use phpOMS\Utils\Converter\AngleType;
19use phpOMS\Utils\Converter\TemperatureType;
20
21/**
22 * Localization class.
23 *
24 * @package phpOMS\Localization
25 * @license OMS License 2.0
26 * @link    https://jingga.app
27 * @since   1.0.0
28 */
29class Localization implements \JsonSerializable
30{
31    /**
32     * Definition path.
33     *
34     * @var string
35     * @since 1.0.0
36     */
37    private const DEFINITIONS_PATH = __DIR__ . '/../Localization/Defaults/Definitions/';
38
39    /**
40     * Country ID.
41     *
42     * @var string
43     * @since 1.0.0
44     */
45    public string $country = ISO3166TwoEnum::_XXX;
46
47    /**
48     * Timezone.
49     *
50     * @var string
51     * @since 1.0.0
52     */
53    public string $timezone = 'America/New_York';
54
55    /**
56     * Language ISO code.
57     *
58     * @var string
59     * @since 1.0.0
60     */
61    public string $language = ISO639x1Enum::_EN;
62
63    /**
64     * Currency.
65     *
66     * @var string
67     * @since 1.0.0
68     */
69    public string $currency = ISO4217CharEnum::_USD;
70
71    /**
72     * Currency format.
73     *
74     * @var string
75     * @since 1.0.0
76     */
77    public string $currencyFormat = '0';
78
79    /**
80     * Number format.
81     *
82     * @var string
83     * @since 1.0.0
84     */
85    public string $decimal = '.';
86
87    /**
88     * Number format.
89     *
90     * @var string
91     * @since 1.0.0
92     */
93    public string $thousands = ',';
94
95    /**
96     * Angle type.
97     *
98     * @var string
99     * @since 1.0.0
100     */
101    public string $angle = AngleType::DEGREE;
102
103    /**
104     * Temperature type.
105     *
106     * @var string
107     * @since 1.0.0
108     */
109    public string $temperature = TemperatureType::CELSIUS;
110
111    /**
112     * Precision.
113     *
114     * @var array<string, int>
115     * @since 1.0.0
116     */
117    public array $precision = [];
118
119    /**
120     * Time format.
121     *
122     * @var array<string, string>
123     * @since 1.0.0
124     */
125    public array $datetime = [];
126
127    /**
128     * Weight.
129     *
130     * @var array<string, string>
131     * @since 1.0.0
132     */
133    public array $weight = [];
134
135    /**
136     * Speed.
137     *
138     * @var array<string, string>
139     * @since 1.0.0
140     */
141    public array $speed = [];
142
143    /**
144     * Length.
145     *
146     * @var array<string, string>
147     * @since 1.0.0
148     */
149    public array $length = [];
150
151    /**
152     * Area.
153     *
154     * @var array<string, string>
155     * @since 1.0.0
156     */
157    public array $area = [];
158
159    /**
160     * Volume.
161     *
162     * @var array<string, string>
163     * @since 1.0.0
164     */
165    public array $volume = [];
166
167    /**
168     * Country id.
169     *
170     * @var int
171     * @since 1.0.0
172     */
173    public int $id = 0;
174
175    /**
176     * Get id
177     *
178     * @return int
179     *
180     * @since 1.0.0
181     */
182    public function getId() : int
183    {
184        return $this->id;
185    }
186
187    /**
188     * Create localization from language code
189     *
190     * @param string $langCode    Language code
191     * @param string $countryCode Country code
192     *
193     * @return Localization
194     *
195     * @since 1.0.0
196     */
197    public static function fromLanguage(string $langCode, string $countryCode = '*') : self
198    {
199        $l11n = new self();
200        $l11n->loadFromLanguage($langCode, $countryCode);
201
202        return $l11n;
203    }
204
205    /**
206     * Create localization from json
207     *
208     * @param array $json Json serialization
209     *
210     * @return Localization
211     *
212     * @since 1.0.0
213     */
214    public static function fromJson(array $json) : self
215    {
216        $l11n = new self();
217        $l11n->setCountry($json['country']);
218        $l11n->setTimezone($json['timezone'] ?? 'America/New_York');
219        $l11n->setLanguage($json['language']);
220        $l11n->setCurrency(\is_string($json['currency']) ? $json['currency'] : ($json['currency']['code'] ?? ISO4217Enum::_USD));
221        $l11n->setCurrencyFormat(isset($json['currencyformat']) && \is_string($json['currencyformat']) ? $json['currencyformat'] : ($json['currency']['format'] ?? '1'));
222        $l11n->setDecimal($json['decimal']);
223        $l11n->setThousands($json['thousand']);
224        $l11n->setAngle($json['angle']);
225        $l11n->setTemperature($json['temperature']);
226        $l11n->setDatetime($json['datetime']);
227        $l11n->setWeight($json['weight']);
228        $l11n->setSpeed($json['speed']);
229        $l11n->setLength($json['length']);
230        $l11n->setArea($json['area']);
231        $l11n->setVolume($json['volume']);
232        $l11n->setPrecision($json['precision']);
233
234        return $l11n;
235    }
236
237    /**
238     * Load localization from language code
239     *
240     * @param string $langCode    Language code
241     * @param string $countryCode Country code
242     *
243     * @return void
244     *
245     * @throws InvalidEnumValue This exception is thrown if the language is invalid
246     *
247     * @since 1.0.0
248     */
249    public function loadFromLanguage(string $langCode, string $countryCode = '*') : void
250    {
251        $langCode    = \strtolower($langCode);
252        $countryCode = \strtoupper($countryCode);
253
254        if ($countryCode !== '*'
255            && !\is_file(self::DEFINITIONS_PATH . $langCode . '_' . $countryCode . '.json')
256        ) {
257            $countryCode = '';
258        }
259
260        $files = \glob(self::DEFINITIONS_PATH . $langCode . '_' . $countryCode . '*');
261        if ($files === false) {
262            $files = []; // @codeCoverageIgnore
263        }
264
265        foreach ($files as $file) {
266            $fileContent = \file_get_contents($file);
267            if ($fileContent === false) {
268                break; // @codeCoverageIgnore
269            }
270
271            $json = \json_decode($fileContent, true);
272            if (!\is_array($json)) {
273                return;
274            }
275
276            $this->language    = $json['language'] ?? 'en';
277            $this->country     = $json['country'] ?? 'US';
278            $this->currency    = $json['currency']['code'] ?? ISO4217Enum::_USD;
279            $this->thousands   = $json['thousand'] ?? ',';
280            $this->decimal     = $json['decimal'] ?? '.';
281            $this->angle       = $json['angle'] ?? AngleType::DEGREE;
282            $this->temperature = $json['temperature'] ?? TemperatureType::CELSIUS;
283            $this->weight      = $json['weight'] ?? [];
284            $this->speed       = $json['speed'] ?? [];
285            $this->length      = $json['length'] ?? [];
286            $this->area        = $json['area'] ?? [];
287            $this->volume      = $json['volume'] ?? [];
288            $this->precision   = $json['precision'] ?? [];
289            $this->timezone    = $json['timezone'] ?? 'America/New_York';
290            $this->datetime    = $json['datetime'] ?? [];
291
292            return;
293        }
294
295        $fileContent = \file_get_contents(self::DEFINITIONS_PATH . 'en_US.json');
296        if ($fileContent === false) {
297            return; // @codeCoverageIgnore
298        }
299
300        $json = \json_decode($fileContent, true);
301        if (!\is_array($json)) {
302            return;
303        }
304
305        $this->language    = $json['language'] ?? 'en';
306        $this->country     = $json['country'] ?? 'US';
307        $this->currency    = $json['currency']['code'] ?? ISO4217Enum::_USD;
308        $this->thousands   = $json['thousand'] ?? ',';
309        $this->decimal     = $json['decimal'] ?? '.';
310        $this->angle       = $json['angle'] ?? AngleType::DEGREE;
311        $this->temperature = $json['temperature'] ?? TemperatureType::CELSIUS;
312        $this->weight      = $json['weight'] ?? [];
313        $this->speed       = $json['speed'] ?? [];
314        $this->length      = $json['length'] ?? [];
315        $this->area        = $json['area'] ?? [];
316        $this->volume      = $json['volume'] ?? [];
317        $this->precision   = $json['precision'] ?? [];
318        $this->timezone    = $json['timezone'] ?? 'America/New_York';
319        $this->datetime    = $json['datetime'] ?? [];
320    }
321
322    /**
323     * Load localization from locale
324     *
325     * @param array{language?:string, country?:string, currency?:array{code?:string}, thousand?:string, angle?:string, temperatur?:string, weight?:array, speed?:array, length?:array, area?:array, volume?:array, precision?:array, timezone?:string, datetime?:array} $locale Locale data
326     *
327     * @return void
328     *
329     * @since 1.0.0
330     */
331    public function importLocale(array $locale) : void
332    {
333        $this->setLanguage($locale['language'] ?? 'en');
334        $this->setCountry($locale['country'] ?? 'US');
335        $this->setCurrency($locale['currency']['code'] ?? ISO4217Enum::_USD);
336        $this->setThousands($locale['thousand'] ?? ',');
337        $this->setDecimal($locale['decimal'] ?? '.');
338        $this->setAngle($locale['angle'] ?? AngleType::DEGREE);
339        $this->setTemperature($locale['temperature'] ?? TemperatureType::CELSIUS);
340        $this->setWeight($locale['weight'] ?? []);
341        $this->setSpeed($locale['speed'] ?? []);
342        $this->setLength($locale['length'] ?? []);
343        $this->setArea($locale['area'] ?? []);
344        $this->setVolume($locale['volume'] ?? []);
345        $this->setPrecision($locale['precision'] ?? []);
346        $this->setTimezone($locale['timezone'] ?? 'America/New_York');
347        $this->setDatetime($locale['datetime'] ?? []);
348    }
349
350    /**
351     * Set country name
352     *
353     * @param string $country Contry name
354     *
355     * @return void
356     *
357     * @since 1.0.0
358     */
359    public function setCountry(string $country) : void
360    {
361        if (!ISO3166TwoEnum::isValidValue($country)) {
362            throw new InvalidEnumValue($country);
363        }
364
365        $this->country = $country;
366    }
367
368    /**
369     * Get timezone
370     *
371     * @return string
372     *
373     * @since 1.0.0
374     */
375    public function getTimezone() : string
376    {
377        return $this->timezone;
378    }
379
380    /**
381     * Set timezone
382     *
383     * @param string $timezone Timezone
384     *
385     * @return void
386     *
387     * @throws InvalidEnumValue This exception is thrown if the timezone is invalid
388     *
389     * @since 1.0.0
390     */
391    public function setTimezone(string $timezone) : void
392    {
393        if (!TimeZoneEnumArray::isValidValue($timezone)) {
394            throw new InvalidEnumValue($timezone);
395        }
396
397        $this->timezone = $timezone;
398    }
399
400    /**
401     * Set language code
402     *
403     * @param string $language Language code
404     *
405     * @return void
406     *
407     * @throws InvalidEnumValue This exception is thrown if the language is invalid
408     *
409     * @since 1.0.0
410     */
411    public function setLanguage(string $language) : void
412    {
413        $language = \strtolower($language);
414
415        if (!ISO639x1Enum::isValidValue($language)) {
416            throw new InvalidEnumValue($language);
417        }
418
419        $this->language = $language;
420    }
421
422    /**
423     * Get currency
424     *
425     * @return string
426     *
427     * @since 1.0.0
428     */
429    public function getCurrency() : string
430    {
431        return $this->currency;
432    }
433
434    /**
435     * Set currency code
436     *
437     * @param string $currency Currency code
438     *
439     * @return void
440     *
441     * @throws InvalidEnumValue This exception is thrown if the currency is invalid
442     *
443     * @since 1.0.0
444     */
445    public function setCurrency(string $currency) : void
446    {
447        if (!ISO4217CharEnum::isValidValue($currency)) {
448            throw new InvalidEnumValue($currency);
449        }
450
451        $this->currency = $currency;
452    }
453
454    /**
455     * Get currency format
456     *
457     * @return string
458     *
459     * @since 1.0.0
460     */
461    public function getCurrencyFormat() : string
462    {
463        return $this->currencyFormat;
464    }
465
466    /**
467     * Set currency format
468     *
469     * @param string $format Currency format
470     *
471     * @return void
472     *
473     * @since 1.0.0
474     */
475    public function setCurrencyFormat(string $format) : void
476    {
477        $this->currencyFormat = $format;
478    }
479
480    /**
481     * get datetime format
482     *
483     * @return array<string, string>
484     *
485     * @since 1.0.0
486     */
487    public function getDatetime() : array
488    {
489        return $this->datetime;
490    }
491
492    /**
493     * Set datetime format
494     *
495     * @param array<string, string> $datetime Datetime format
496     *
497     * @return void
498     *
499     * @since 1.0.0
500     */
501    public function setDatetime(array $datetime) : void
502    {
503        $this->datetime = $datetime;
504    }
505
506    /**
507     * Set decimal char
508     *
509     * @return string
510     *
511     * @since 1.0.0
512     */
513    public function getDecimal() : string
514    {
515        return $this->decimal;
516    }
517
518    /**
519     * Get decimal char
520     *
521     * @param string $decimal Decimal char
522     *
523     * @return void
524     *
525     * @since 1.0.0
526     */
527    public function setDecimal(string $decimal) : void
528    {
529        $this->decimal = $decimal;
530    }
531
532    /**
533     * Get thousands char
534     *
535     * @return string
536     *
537     * @since 1.0.0
538     */
539    public function getThousands() : string
540    {
541        return $this->thousands;
542    }
543
544    /**
545     * Set thousands char
546     *
547     * @param string $thousands Thousands char
548     *
549     * @return void
550     *
551     * @since 1.0.0
552     */
553    public function setThousands(string $thousands) : void
554    {
555        $this->thousands = $thousands;
556    }
557
558    /**
559     * Get angle type
560     *
561     * @return string
562     *
563     * @since 1.0.0
564     */
565    public function getAngle() : string
566    {
567        return $this->angle;
568    }
569
570    /**
571     * Set angle type
572     *
573     * @param string $angle Angle
574     *
575     * @return void
576     *
577     * @throws InvalidEnumValue This exception is thrown if the angle is invalid
578     *
579     * @since 1.0.0
580     */
581    public function setAngle(string $angle) : void
582    {
583        if (!AngleType::isValidValue($angle)) {
584            throw new InvalidEnumValue($angle);
585        }
586
587        $this->angle = $angle;
588    }
589
590    /**
591     * Get temperature type
592     *
593     * @return string
594     *
595     * @since 1.0.0
596     */
597    public function getTemperature() : string
598    {
599        return $this->temperature;
600    }
601
602    /**
603     * Set temperature string
604     *
605     * @param string $temperature Temperature
606     *
607     * @return void
608     *
609     * @throws InvalidEnumValue
610     *
611     * @since 1.0.0
612     */
613    public function setTemperature(string $temperature) : void
614    {
615        if (!TemperatureType::isValidValue($temperature)) {
616            throw new InvalidEnumValue($temperature);
617        }
618
619        $this->temperature = $temperature;
620    }
621
622    /**
623     * Get speed type
624     *
625     * @return array<string, string>
626     *
627     * @since 1.0.0
628     */
629    public function getSpeed() : array
630    {
631        return $this->speed;
632    }
633
634    /**
635     * Set speed type
636     *
637     * @param array<string, string> $speed Speed
638     *
639     * @return void
640     *
641     * @since 1.0.0
642     */
643    public function setSpeed(array $speed) : void
644    {
645        $this->speed = $speed;
646    }
647
648    /**
649     * Get weight type
650     *
651     * @return array<string, string>
652     *
653     * @since 1.0.0
654     */
655    public function getWeight() : array
656    {
657        return $this->weight;
658    }
659
660    /**
661     * Set weight type
662     *
663     * @param array<string, string> $weight Weight type
664     *
665     * @return void
666     *
667     * @since 1.0.0
668     */
669    public function setWeight(array $weight) : void
670    {
671        $this->weight = $weight;
672    }
673
674    /**
675     * Get length type
676     *
677     * @return array<string, string>
678     *
679     * @since 1.0.0
680     */
681    public function getLength() : array
682    {
683        return $this->length;
684    }
685
686    /**
687     * Set length type
688     *
689     * @param array<string, string> $length Length type
690     *
691     * @return void
692     *
693     * @since 1.0.0
694     */
695    public function setLength(array $length) : void
696    {
697        $this->length = $length;
698    }
699
700    /**
701     * Get area type
702     *
703     * @return array<string, string>
704     *
705     * @since 1.0.0
706     */
707    public function getArea() : array
708    {
709        return $this->area;
710    }
711
712    /**
713     * Set area type
714     *
715     * @param array<string, string> $area Area type
716     *
717     * @return void
718     *
719     * @since 1.0.0
720     */
721    public function setArea(array $area) : void
722    {
723        $this->area = $area;
724    }
725
726    /**
727     * Get volume type
728     *
729     * @return array<string, string>
730     *
731     * @since 1.0.0
732     */
733    public function getVolume() : array
734    {
735        return $this->volume;
736    }
737
738    /**
739     * Get precision type
740     *
741     * @return array<string, int>
742     *
743     * @since 1.0.0
744     */
745    public function getPrecision() : array
746    {
747        return $this->precision;
748    }
749
750    /**
751     * Set precision type
752     *
753     * @param array<string, int> $precision Precision type
754     *
755     * @return void
756     *
757     * @since 1.0.0
758     */
759    public function setPrecision(array $precision) : void
760    {
761        $this->precision = $precision;
762    }
763
764    /**
765     * Set volume type
766     *
767     * @param array<string, string> $volume Volume type
768     *
769     * @return void
770     *
771     * @since 1.0.0
772     */
773    public function setVolume(array $volume) : void
774    {
775        $this->volume = $volume;
776    }
777
778    /**
779     * {@inheritdoc}
780     */
781    public function toArray() : array
782    {
783        return [
784            'id'             => $this->id,
785            'country'        => $this->country,
786            'timezone'       => $this->timezone,
787            'language'       => $this->language,
788            'currency'       => $this->currency,
789            'currencyformat' => $this->currencyFormat,
790            'decimal'        => $this->decimal,
791            'thousand'       => $this->thousands,
792            'angle'          => $this->angle,
793            'temperature'    => $this->temperature,
794            'datetime'       => $this->datetime,
795            'weight'         => $this->weight,
796            'speed'          => $this->speed,
797            'length'         => $this->length,
798            'area'           => $this->area,
799            'volume'         => $this->volume,
800            'precision'      => $this->precision,
801        ];
802    }
803
804    /**
805     * {@inheritdoc}
806     */
807    public function jsonSerialize() : mixed
808    {
809        return $this->toArray();
810    }
811}