Completed
Push — master ( 34d6d1...dadac3 )
by Peter
02:46
created

Translator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Foo\Translate;
6
7
class Translator implements ITranslator
8
{
9
    const DEFAULT_LANGUAGE = 'DEFAULT_LANGUAGE';
10
11
    /** @var Loader */
12
    protected $loader;
13
14
    /** @var string */
15
    protected $lang;
16
17
    /** @var array */
18
    protected $translations = [];
19
20
    /**
21
     * Translator constructor.
22
     *
23
     * @param Loader $loader
24
     */
25 16
    public function __construct(Loader $loader)
26
    {
27 16
        $this->loader = $loader;
28 16
    }
29
30
    /**
31
     * @param string
32
     *
33
     * @return array
34
     */
35 14
    public function getTranslations(string $lang): array
36
    {
37 14
        if (!array_key_exists($lang, $this->translations)) {
38 1
            $this->translations[$lang] = $this->loader->loadTranslations($lang);
39
        }
40
41 14
        if (empty($this->translations[$lang])) {
42 1
            throw new Exception("{{language is missing: $lang}}");
43
        }
44
45 13
        return $this->translations[$lang];
46
    }
47
48
49
    /**
50
     * @param array  $translations
51
     * @param string $key
52
     * @param string $lang
53
     */
54 14
    public function setTranslations(array $translations, string $key = null, string $lang = null)
55
    {
56 14
        if (null === $lang && null === $key) {
57 14
            $this->translations = $translations;
58
59 14
            return;
60
        } elseif (null === $lang) {
61
            $lang = 'en';
62
        }
63
64
        if (null === $key) {
65
            $this->translations[$lang] = $translations;
66
67
            return;
68
        }
69
70
        $this->translations[$lang][$key] = $translations;
71
    }
72
73
    /**
74
     * @return string
75
     */
76 14
    public function getLang(): string
77
    {
78 14
        if (null === $this->lang) {
79
            $this->lang = getenv(static::DEFAULT_LANGUAGE);
80
        }
81
82 14
        return $this->lang;
83
    }
84
85
    /**
86
     * @param string $lang
87
     *
88
     * @return Translator
89
     */
90 14
    public function setLang(string $lang): Translator
91
    {
92 14
        $this->lang = $lang;
93
94 14
        return $this;
95
    }
96
97
    /**
98
     * @param string $key
99
     * @param array  ...$args
100
     *
101
     * @return string
102
     */
103 5
    public function translate(string $key, ...$args): string
104
    {
105 5
        return $this->translateByArgs($key, $args);
106
    }
107
108
    /**
109
     * @param string $key
110
     * @param array  $args
111
     *
112
     * @return string
113
     */
114 14
    public function translateByArgs(string $key, array $args = []): string
115
    {
116
        try {
117 14
            $translation = $this->findTranslation($key);
118 11
            $args        = $this->translateArguments($args);
119 11
            $translated  = $this->execute($translation, $args, $key);
120 4
        } catch (Exception $e) {
121 4
            return $e->getMessage();
122
        }
123
124 10
        return $translated;
125
    }
126
127
    /**
128
     * @param string $key
129
     *
130
     * @return string
131
     */
132 14
    private function findTranslation(string $key): string
133
    {
134 14
        $pathParts = explode(':', $key);
135
136 14
        $translations = $this->getTranslations($this->getLang());
137 13
        foreach ($pathParts as $pathPart) {
138 13
            if (!array_key_exists($pathPart, $translations)) {
139 1
                throw new Exception("{{translation is missing: $key}}");
140
            }
141
142 13
            $translations = &$translations[$pathPart];
143
        }
144
145 12
        if (!is_string($translations)) {
146 1
            throw new Exception("{{translation is ambiguous: $key}}");
147
        }
148
149 11
        return $translations;
150
    }
151
152
    /**
153
     * @param array $args
154
     *
155
     * @return array
156
     */
157 11
    private function translateArguments(array $args): array
158
    {
159 11
        foreach ($args as $argKey => $argValue) {
160 6
            if (!is_string($argValue)) {
161 6
                continue;
162
            }
163
164 6
            if (!preg_match('/{{(.+)}}/Ums', $argValue, $match)) {
165 4
                continue;
166
            }
167
168 2
            $args[$argKey] = $this->translateByArgs($match[1]);
169
        }
170
171 11
        return $args;
172
    }
173
174
    /**
175
     * @param string $translation
176
     * @param array  $args
177
     * @param string $key
178
     *
179
     * @return string
180
     */
181 11
    private function execute(string $translation, array $args, string $key): string
182
    {
183 11
        $result = @vsprintf($translation, $args);
184
185 11
        if (!is_string($result)) {
186 1
            throw new Exception("{{translation argument list failure: $key}}");
187
        }
188
189 10
        return $result;
190
    }
191
}