Completed
Push — master ( d04d10...34d6d1 )
by Peter
02:14
created

Translator::translateArguments()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

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