Passed
Pull Request — master (#61)
by Dmitriy
12:44
created

Translator::withCategory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2

1 Method

Rating   Name   Duplication   Size   Complexity  
A Translator::withLocale() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Translator;
6
7
use Psr\EventDispatcher\EventDispatcherInterface;
8
use Yiisoft\I18n\Locale;
9
use Yiisoft\Translator\Event\MissingTranslationCategoryEvent;
10
use Yiisoft\Translator\Event\MissingTranslationEvent;
11
12
/**
13
 * Translator translates a message into the specified language.
14
 */
15
final class Translator implements TranslatorInterface
16
{
17
    private string $defaultCategory = 'app';
18
    private string $locale;
19
    private ?string $fallbackLocale;
20
    private ?EventDispatcherInterface $eventDispatcher;
21
22
    /**
23
     * @var CategorySource[][] Array of category message sources indexed by category names.
24
     */
25
    private array $categorySources;
26
27
    /**
28
     * @param string $locale Default locale to use if locale is not specified explicitly.
29
     * @param string|null $fallbackLocale Locale to use if message for the locale specified was not found. Null for none.
30
     * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for translation events. Null for none.
31
     */
32 52
    public function __construct(
33
        string $locale,
34
        ?string $fallbackLocale = null,
35
        array $categorySources = [],
36
        ?EventDispatcherInterface $eventDispatcher = null
37
    ) {
38 52
        $this->locale = $locale;
39 52
        $this->fallbackLocale = $fallbackLocale;
40 52
        $this->eventDispatcher = $eventDispatcher;
41
42 52
        $this->addCategorySources($categorySources);
43
    }
44
45 50
    private function addCategorySource(CategorySource $category): void
46
    {
47 50
        if (isset($this->categorySources[$category->getName()])) {
48 14
            $this->categorySources[$category->getName()][] = $category;
49
        } else {
50 50
            $this->categorySources[$category->getName()] = [$category];
51
        }
52
    }
53
54
    /**
55
     * Add multiple categories.
56
     *
57
     * @param CategorySource[] $categories
58
     */
59 52
    private function addCategorySources(array $categories): void
60
    {
61 52
        foreach ($categories as $category) {
62 50
            $this->addCategorySource($category);
63
        }
64
    }
65
66 3
    public function setLocale(string $locale): void
67
    {
68 3
        $this->locale = $locale;
69
    }
70
71 3
    public function getLocale(): string
72
    {
73 3
        return $this->locale;
74
    }
75
76 51
    public function translate(
77
        string $id,
78
        array $parameters = [],
79
        string $category = null,
80
        string $locale = null
81
    ): string {
82 51
        $locale = $locale ?? $this->locale;
83
84 51
        $category = $category ?? $this->defaultCategory;
85
86 51
        if (empty($this->categorySources[$category])) {
87 3
            if ($this->eventDispatcher !== null) {
88 2
                $this->eventDispatcher->dispatch(new MissingTranslationCategoryEvent($category));
89
            }
90 3
            return $id;
91
        }
92
93 48
        return $this->translateUsingCategorySources($id, $parameters, $category, $locale);
94
    }
95
96 1
    public function withLocale(string $locale): self
97
    {
98 1
        $new = clone $this;
99 1
        $new->setLocale($locale);
100 1
        return $new;
101
    }
102
103 48
    private function translateUsingCategorySources(
104
        string $id,
105
        array $parameters,
106
        string $category,
107
        string $locale
108
    ): string {
109 48
        $sourceCategory = end($this->categorySources[$category]);
110
        do {
111 48
            $message = $sourceCategory->getMessage($id, $locale, $parameters);
112
113 48
            if ($message !== null) {
114 35
                return $sourceCategory->format($message, $parameters, $locale);
115
            }
116
117 31
            if ($this->eventDispatcher !== null) {
118 12
                $this->eventDispatcher->dispatch(new MissingTranslationEvent($sourceCategory->getName(), $locale, $id));
119
            }
120 31
        } while (($sourceCategory = prev($this->categorySources[$category])) !== false);
121
122 26
        $localeObject = new Locale($locale);
123 26
        $fallback = $localeObject->fallbackLocale();
124
125 26
        if ($fallback->asString() !== $localeObject->asString()) {
126 14
            return $this->translateUsingCategorySources($id, $parameters, $category, $fallback->asString());
127
        }
128
129 19
        if (!empty($this->fallbackLocale)) {
130 10
            $fallbackLocaleObject = (new Locale($this->fallbackLocale))->fallbackLocale();
131 10
            if ($fallbackLocaleObject->asString() !== $localeObject->asString()) {
132 9
                return $this->translateUsingCategorySources($id, $parameters, $category, $fallbackLocaleObject->asString());
133
            }
134
        }
135
136 13
        $categorySource = end($this->categorySources[$category]);
137 13
        return $categorySource->format($id, $parameters, $locale);
138
    }
139
}
140