1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Charcoal\Translator; |
4
|
|
|
|
5
|
|
|
// From 'symfony/translation' |
6
|
|
|
use Symfony\Component\Translation\Translator as SymfonyTranslator; |
7
|
|
|
|
8
|
|
|
// From 'charcoal-translator' |
9
|
|
|
use Charcoal\Translator\LocalesManager; |
10
|
|
|
use Charcoal\Translator\Translation; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Charcoal Translator. |
14
|
|
|
* |
15
|
|
|
* Extends the Symfony translator to allow returned values in a "Translation" oject, |
16
|
|
|
* containing localizations for all locales. |
17
|
|
|
*/ |
18
|
|
|
class Translator extends SymfonyTranslator |
19
|
|
|
{ |
20
|
|
|
/** |
21
|
|
|
* The locales manager. |
22
|
|
|
* |
23
|
|
|
* @var LocalesManager |
24
|
|
|
*/ |
25
|
|
|
private $manager; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* The loaded domains. |
29
|
|
|
* |
30
|
|
|
* @var string[] |
31
|
|
|
*/ |
32
|
|
|
private $domains = [ 'messages' ]; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @param array $data Constructor data. |
36
|
|
|
*/ |
37
|
|
|
public function __construct(array $data) |
38
|
|
|
{ |
39
|
|
|
$this->setManager($data['manager']); |
40
|
|
|
|
41
|
|
|
$defaults = [ |
42
|
|
|
'locale' => $this->manager->currentLocale(), |
43
|
|
|
'message_selector' => null, |
44
|
|
|
'cache_dir' => null, |
45
|
|
|
'debug' => false |
46
|
|
|
]; |
47
|
|
|
$data = array_merge($defaults, $data); |
48
|
|
|
|
49
|
|
|
// If symfony-config is not installed, DON'T use cache. |
50
|
|
|
if (!class_exists('\Symfony\Component\Config\ConfigCacheFactory')) { |
51
|
|
|
$data['cache_dir'] = null; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
parent::__construct( |
55
|
|
|
$data['locale'], |
56
|
|
|
$data['message_selector'], |
57
|
|
|
$data['cache_dir'], |
58
|
|
|
$data['debug'] |
59
|
|
|
); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Adds a resource. |
64
|
|
|
* |
65
|
|
|
* @see SymfonyTranslator::addResource() Keep track of the translation domains. |
66
|
|
|
* @param string $format The name of the loader (@see addLoader()). |
67
|
|
|
* @param mixed $resource The resource name. |
68
|
|
|
* @param string $locale The locale. |
69
|
|
|
* @param string|null $domain The domain. |
70
|
|
|
* @return void |
71
|
|
|
*/ |
72
|
|
|
public function addResource($format, $resource, $locale, $domain = null) |
73
|
|
|
{ |
74
|
|
|
if (null !== $domain) { |
75
|
|
|
$this->domains[] = $domain; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
parent::addResource($format, $resource, $locale, $domain); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Retrieve the loaded domains. |
83
|
|
|
* |
84
|
|
|
* @return string[] |
85
|
|
|
*/ |
86
|
|
|
public function availableDomains() |
87
|
|
|
{ |
88
|
|
|
return $this->domains; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Retrieve a translation object from a (mixed) message. |
93
|
|
|
* |
94
|
|
|
* @uses SymfonyTranslator::trans() |
95
|
|
|
* @param mixed $val The string or translation-object to retrieve. |
96
|
|
|
* @param array $parameters An array of parameters for the message. |
97
|
|
|
* @param string|null $domain The domain for the message or NULL to use the default. |
98
|
|
|
* @return Translation|null The translation object or NULL if the value is not translatable. |
99
|
|
|
*/ |
100
|
|
View Code Duplication |
public function translation($val, array $parameters = [], $domain = null) |
|
|
|
|
101
|
|
|
{ |
102
|
|
|
if ($this->isValidTranslation($val) === false) { |
103
|
|
|
return null; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
$translation = new Translation($val, $this->manager); |
107
|
|
|
foreach ($this->availableLocales() as $lang) { |
108
|
|
|
if (!isset($translation[$lang]) || $translation[$lang] == $val) { |
109
|
|
|
$translation[$lang] = $this->trans((string)$translation, $parameters, $domain, $lang); |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
return $translation; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Translates the given (mixed) message. |
118
|
|
|
* |
119
|
|
|
* @uses SymfonyTranslator::trans() |
120
|
|
|
* @uses Translator::translation() |
121
|
|
|
* @param mixed $val The string or translation-object to retrieve. |
122
|
|
|
* @param array $parameters An array of parameters for the message. |
123
|
|
|
* @param string|null $domain The domain for the message or NULL to use the default. |
124
|
|
|
* @param string|null $locale The locale or NULL to use the default. |
125
|
|
|
* @return string The translated string |
126
|
|
|
*/ |
127
|
|
View Code Duplication |
public function translate($val, array $parameters = [], $domain = null, $locale = null) |
|
|
|
|
128
|
|
|
{ |
129
|
|
|
if ($val instanceof Translation) { |
130
|
|
|
return strtr($val[$locale], $parameters); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
if (is_object($val) && method_exists($val, '__toString')) { |
134
|
|
|
$val = (string)$val; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
if (is_string($val)) { |
138
|
|
|
return $this->trans($val, $parameters, $domain, $locale); |
139
|
|
|
} else { |
140
|
|
|
$translation = $this->translation($val, $parameters, $domain); |
141
|
|
|
return $translation[$locale]; |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Retrieve a translation object from a (mixed) message by choosing a translation according to a number. |
147
|
|
|
* |
148
|
|
|
* @uses SymfonyTranslator::transChoice() |
149
|
|
|
* @param mixed $val The string or translation-object to retrieve. |
150
|
|
|
* @param integer $number The number to use to find the indice of the message. |
151
|
|
|
* @param array $parameters An array of parameters for the message. |
152
|
|
|
* @param string|null $domain The domain for the message or NULL to use the default. |
153
|
|
|
* @return Translation|null The translation object or NULL if the value is not translatable. |
154
|
|
|
*/ |
155
|
|
View Code Duplication |
public function translationChoice($val, $number, array $parameters = [], $domain = null) |
|
|
|
|
156
|
|
|
{ |
157
|
|
|
if ($this->isValidTranslation($val) === false) { |
158
|
|
|
return null; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
$translation = new Translation($val, $this->manager); |
162
|
|
|
foreach ($this->availableLocales() as $lang) { |
163
|
|
|
if (!isset($translation[$lang]) || $translation[$lang] == $val) { |
164
|
|
|
$translation[$lang] = $this->transChoice((string)$translation, $number, $parameters, $domain, $lang); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
return $translation; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Translates the given (mixed) choice message by choosing a translation according to a number. |
173
|
|
|
* |
174
|
|
|
* @uses SymfonyTranslator::transChoice() |
175
|
|
|
* @uses Translator::translationChoice() |
176
|
|
|
* @param mixed $val The string or translation-object to retrieve. |
177
|
|
|
* @param integer $number The number to use to find the indice of the message. |
178
|
|
|
* @param array $parameters An array of parameters for the message. |
179
|
|
|
* @param string|null $domain The domain for the message or NULL to use the default. |
180
|
|
|
* @param string|null $locale The locale or NULL to use the default. |
181
|
|
|
* @return string The translated string |
182
|
|
|
*/ |
183
|
|
View Code Duplication |
public function translateChoice($val, $number, array $parameters = [], $domain = null, $locale = null) |
|
|
|
|
184
|
|
|
{ |
185
|
|
|
if ($val instanceof Translation) { |
186
|
|
|
return strtr($val[$locale], $parameters); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
if (is_object($val) && method_exists($val, '__toString')) { |
190
|
|
|
$val = (string)$val; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
if (is_string($val)) { |
194
|
|
|
return $this->transChoice($val, $number, $parameters, $domain, $locale); |
195
|
|
|
} else { |
196
|
|
|
$translation = $this->translationChoice($val, $number, $parameters, $domain); |
197
|
|
|
return $translation[$locale]; |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Retrieve the available locales information. |
203
|
|
|
* |
204
|
|
|
* @return array |
205
|
|
|
*/ |
206
|
|
|
public function locales() |
207
|
|
|
{ |
208
|
|
|
return $this->manager->locales(); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Retrieve the available locales (language codes). |
213
|
|
|
* |
214
|
|
|
* @return string[] |
215
|
|
|
*/ |
216
|
|
|
public function availableLocales() |
217
|
|
|
{ |
218
|
|
|
return $this->manager->availableLocales(); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Sets the current locale. |
223
|
|
|
* |
224
|
|
|
* @see SymfonyTranslator::setLocale() Ensure that the method also changes the locales manager's language. |
225
|
|
|
* @param string $locale The locale. |
226
|
|
|
* @return void |
227
|
|
|
*/ |
228
|
|
|
public function setLocale($locale) |
229
|
|
|
{ |
230
|
|
|
parent::setLocale($locale); |
231
|
|
|
|
232
|
|
|
$this->manager->setCurrentLocale($locale); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Set the locales manager. |
237
|
|
|
* |
238
|
|
|
* @param LocalesManager $manager The locales manager. |
239
|
|
|
* @return void |
240
|
|
|
*/ |
241
|
|
|
private function setManager(LocalesManager $manager) |
242
|
|
|
{ |
243
|
|
|
$this->manager = $manager; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Determine if the value is translatable. |
248
|
|
|
* |
249
|
|
|
* @param mixed $val The value to be checked. |
250
|
|
|
* @return boolean |
251
|
|
|
*/ |
252
|
|
|
private function isValidTranslation($val) |
253
|
|
|
{ |
254
|
|
|
if (empty($val) && !is_numeric($val)) { |
255
|
|
|
return false; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
if (is_string($val)) { |
259
|
|
|
return !empty(trim($val)); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
if ($val instanceof Translation) { |
263
|
|
|
return true; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
if (is_array($val)) { |
267
|
|
|
return !!array_filter( |
268
|
|
|
$val, |
269
|
|
|
function ($v, $k) { |
270
|
|
|
if (is_string($k) && strlen($k) > 0) { |
271
|
|
|
if (is_string($v) && strlen($v) > 0) { |
272
|
|
|
return true; |
273
|
|
|
} |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
return false; |
277
|
|
|
}, |
278
|
|
|
ARRAY_FILTER_USE_BOTH |
279
|
|
|
); |
280
|
|
|
} |
281
|
|
|
return false; |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.