1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* The MIT License |
5
|
|
|
* |
6
|
|
|
* Copyright 2016 Alejandro Peña Florentín ([email protected]). |
7
|
|
|
* |
8
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
9
|
|
|
* of this software and associated documentation files (the "Software"), to deal |
10
|
|
|
* in the Software without restriction, including without limitation the rights |
11
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12
|
|
|
* copies of the Software, and to permit persons to whom the Software is |
13
|
|
|
* furnished to do so, subject to the following conditions: |
14
|
|
|
* |
15
|
|
|
* The above copyright notice and this permission notice shall be included in |
16
|
|
|
* all copies or substantial portions of the Software. |
17
|
|
|
* |
18
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24
|
|
|
* THE SOFTWARE. |
25
|
|
|
*/ |
26
|
|
|
|
27
|
|
|
namespace Tight\Modules\Localize; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Localize module for translations |
31
|
|
|
* |
32
|
|
|
* @author Alejandro Peña Florentín ([email protected]) |
33
|
|
|
*/ |
34
|
|
|
class Localize extends \Tight\Modules\AbstractModule |
35
|
|
|
{ |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var string Resource file type |
39
|
|
|
*/ |
40
|
|
|
private $resourceFileType; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var string Current locale |
44
|
|
|
*/ |
45
|
|
|
private $locale; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var array Associative array for the current locale |
49
|
|
|
*/ |
50
|
|
|
private $values; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Constructor |
54
|
|
|
* |
55
|
|
|
* @param array|\Tight\Modules\Localize\LocalizeConfig $config |
56
|
|
|
* @throws \InvalidArgumentException If $config is not an array or an object |
57
|
|
|
* of \Tight\Modules\Localize\LocalizeConfig class |
58
|
|
|
*/ |
59
|
|
|
public function __construct($config = []) { |
60
|
|
|
if (is_array($config)) { |
61
|
|
|
$config = new \Tight\Modules\Localize\LocalizeConfig($config); |
62
|
|
|
} else if (!$config instanceof \Tight\Modules\Localize\LocalizeConfig) { |
63
|
|
|
throw new \InvalidArgumentException("Argument 1 passed to " . get_class($this) . " must be an array or an instance of Tight\Modules\Localize\LocalizeConfig"); |
64
|
|
|
} |
65
|
|
|
parent::__construct("LocalizeModule", "v1.2"); |
66
|
|
|
$this->setConfig($config); |
67
|
|
|
$this->checkDependences(); |
68
|
|
|
$this->setResourceFileType($this->getConfig()->resourceFileType); |
69
|
|
|
$this->setLocale($this->getConfig()->defaultLocale); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Sets the resource file type |
74
|
|
|
* @param string $resourceFileType Resource file type |
75
|
|
|
* @return \Tight\Modules\Localize\Localize Fluent setter |
76
|
|
|
*/ |
77
|
|
|
public function setResourceFileType($resourceFileType) { |
78
|
|
|
$this->resourceFileType = $resourceFileType; |
79
|
|
|
$this->reloadConfig(); |
80
|
|
|
return $this; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Gets the current resource file type |
85
|
|
|
* @return string Resource file type |
86
|
|
|
* @see \Tight\Modules\Localize\LocalizeConfig::FILETYPE_INI |
87
|
|
|
* @see \Tight\Modules\Localize\LocalizeConfig::FILETYPE_JSON |
88
|
|
|
* @see \Tight\Modules\Localize\LocalizeConfig::FILETYPE_XML |
89
|
|
|
*/ |
90
|
|
|
public function getResourceFileType() { |
91
|
|
|
return $this->resourceFileType; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Gets all the defined values for the current locale |
96
|
|
|
* @return array Associative array of values |
97
|
|
|
*/ |
98
|
|
|
public function getValues() { |
99
|
|
|
return $this->values; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Reloads the class with the new locale |
104
|
|
|
*/ |
105
|
|
|
public function reloadConfig() { |
106
|
|
|
if (null == $this->locale) { |
107
|
|
|
$this->locale = $this->getConfig()->defaultLocale; |
108
|
|
|
} |
109
|
|
|
$values = null; |
110
|
|
|
switch ($this->resourceFileType) { |
111
|
|
|
case LocalizeConfig::FILETYPE_JSON: |
112
|
|
|
$values = $this->getValuesFromJson(); |
113
|
|
|
break; |
114
|
|
|
case LocalizeConfig::FILETYPE_XML: |
115
|
|
|
$values = $this->getValuesFromXml(); |
116
|
|
|
break; |
117
|
|
|
} |
118
|
|
|
$this->values = $values; |
|
|
|
|
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Checks the dependences for the class |
123
|
|
|
* @throws \Tight\Exception\ModuleException If resource directory cant be |
124
|
|
|
* found |
125
|
|
|
*/ |
126
|
|
|
private function checkDependences() { |
127
|
|
|
if (!is_dir($this->getConfig()->resourceFolder)) { |
128
|
|
|
throw new \Tight\Exception\ModuleException("Resource directory not found"); |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Sets a new locale |
134
|
|
|
* @param string $locale New defined locale |
135
|
|
|
* @throws \Tight\Exception\ModuleException If resource default resource file |
136
|
|
|
* cant be found |
137
|
|
|
*/ |
138
|
|
|
public function setLocale($locale) { |
139
|
|
|
$this->locale = $locale; |
140
|
|
|
$this->reloadConfig(); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Gets the available locales |
145
|
|
|
* @return array Available locales |
146
|
|
|
*/ |
147
|
|
|
public function getLocales() { |
148
|
|
|
$output = []; |
149
|
|
|
switch ($this->resourceFileType) { |
150
|
|
|
case LocalizeConfig::FILETYPE_JSON: |
151
|
|
|
$output = $this->getLocalesFromJson(); |
152
|
|
|
break; |
153
|
|
|
case LocalizeConfig::FILETYPE_XML: |
154
|
|
|
$output = $this->getLocalesFromXml(); |
155
|
|
|
break; |
156
|
|
|
case LocalizeConfig::FILETYPE_INI: |
157
|
|
|
break; |
158
|
|
|
} |
159
|
|
|
return $output; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
private function getLocalesFromJson() { |
163
|
|
|
$output = []; |
164
|
|
|
$directory = $this->getConfig()->resourceFolder; |
165
|
|
|
$fileName = $this->getConfig()->resourceFileName; |
166
|
|
|
$dir = opendir($directory); |
167
|
|
|
$files = []; |
168
|
|
|
while ($entry = readdir($dir)) { |
169
|
|
|
if (strpos($entry, $fileName) !== false) { |
170
|
|
|
$files[] = $entry; |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
foreach ($files as $element) { |
174
|
|
|
$file = \Tight\Utils::getSlicedFile($directory . $element); |
175
|
|
|
//Removes extension |
176
|
|
|
$name = $file["name"]; |
177
|
|
|
$explode = explode($this->getConfig()->langSeparator, $name); |
178
|
|
|
// Get the locale of the defined file type |
179
|
|
|
if ($file["ext"] == $this->getConfig()->resourceFileType) { |
180
|
|
|
if (count($explode) > 1) { |
181
|
|
|
$output[] = $explode[count($explode) - 1]; |
182
|
|
|
} else { |
183
|
|
|
$output[] = $this->getConfig()->defaultLocale; |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
return $output; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Gets the json values from the json file |
192
|
|
|
* @return array String values |
193
|
|
|
* @throws \Tight\Exception\ModuleException If json file cant be found |
194
|
|
|
*/ |
195
|
|
|
private function getValuesFromJson() { |
196
|
|
|
$output = []; |
|
|
|
|
197
|
|
|
$folder = \Tight\Utils::addTrailingSlash($this->getConfig()->resourceFolder); |
198
|
|
|
$fileName = $this->getConfig()->resourceFileName . $this->getConfig()->langSeparator . $this->locale . "." . $this->getConfig()->resourceFileType; |
199
|
|
|
$file = $folder . $fileName; |
200
|
|
|
if (is_file($file)) { |
201
|
|
|
$output = json_decode(file_get_contents($file), JSON_FORCE_OBJECT); |
202
|
|
|
} else { |
203
|
|
|
$fileName = $this->getConfig()->resourceFileName . "." . $this->getConfig()->resourceFileType; |
204
|
|
|
$file = $folder . $fileName; |
205
|
|
View Code Duplication |
if (is_file($file)) { |
|
|
|
|
206
|
|
|
$output = json_decode(file_get_contents($file), JSON_FORCE_OBJECT); |
207
|
|
|
} else { |
208
|
|
|
throw new \Tight\Exception\ModuleException("Resource file <strong>" . $file . "</strong> not found"); |
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
return $output; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Gets the locales from the xml resource file |
216
|
|
|
* @return array Array of locales |
217
|
|
|
*/ |
218
|
|
|
private function getLocalesFromXml() { |
219
|
|
|
$output = []; |
220
|
|
|
$resources = $this->getXmlResources(); |
221
|
|
|
$size = count($resources->values); |
222
|
|
|
for ($index = 0; $index < $size; $index++) { |
223
|
|
|
$output[] = $resources->values[$index]['lang']->__toString(); |
224
|
|
|
} |
225
|
|
|
return $output; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Gets the xml resource read from the xml resource file |
230
|
|
|
* @return \SimpleXMLElement XML values for the current locale |
|
|
|
|
231
|
|
|
* @throws \Tight\Exception\ModuleException If xml values resource file cant be found |
232
|
|
|
*/ |
233
|
|
|
private function getXmlResources() { |
234
|
|
|
$output = null; |
235
|
|
|
if ($this->resourceFileType === LocalizeConfig::FILETYPE_XML) { |
236
|
|
|
$file = \Tight\Utils::addTrailingSlash($this->getConfig()->resourceFolder) . $this->getConfig()->resourceFileName . "." . $this->resourceFileType; |
237
|
|
View Code Duplication |
if (is_file($file)) { |
|
|
|
|
238
|
|
|
$xmlContent = file_get_contents($file); |
239
|
|
|
$output = new \SimpleXMLElement($xmlContent); |
240
|
|
|
} else { |
241
|
|
|
throw new \Tight\Exception\ModuleException("Resource file <strong>" . $file . "</strong> does not exists"); |
242
|
|
|
} |
243
|
|
|
} |
244
|
|
|
return $output; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* Gets the values from xml resource file |
249
|
|
|
* @return array Array of values |
250
|
|
|
* @throws \Tight\Exception\ModuleException If the current locale cant be |
251
|
|
|
* found in the xml resource file |
252
|
|
|
*/ |
253
|
|
|
private function getValuesFromXml() { |
254
|
|
|
$output = []; |
|
|
|
|
255
|
|
|
$resources = $this->getXmlResources(); |
256
|
|
|
$locale = null; |
257
|
|
|
$size = count($resources->values); |
258
|
|
|
$index = 0; |
259
|
|
|
while ($index < $size && $locale == null) { |
260
|
|
|
if ($resources->values[$index]['lang'] == $this->locale) { |
261
|
|
|
$locale = $resources->values[$index]; |
262
|
|
|
} |
263
|
|
|
$index++; |
264
|
|
|
} |
265
|
|
|
if (null == $locale) { |
266
|
|
|
$fileName = $this->getConfig()->resourceFileName . "." . $this->getConfig()->resourceFileType; |
267
|
|
|
throw new \Tight\Exception\ModuleException("Locale <strong>" . $this->locale . "</strong> not found at resource file <strong>" . $fileName . "</strong>"); |
268
|
|
|
} |
269
|
|
|
return $this->parseXmlStringValues($locale); |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* Parses a \SimpleXmlElement object to get its values |
274
|
|
|
* @param \SimpleXMLElement $xml XML object |
275
|
|
|
* @return array Values |
276
|
|
|
*/ |
277
|
|
|
private function parseXmlStringValues(\SimpleXMLElement $xml) { |
278
|
|
|
$output = []; |
279
|
|
|
if ($xml->count() > 0) { |
280
|
|
|
$children = $xml->children(); |
281
|
|
|
for ($index = 0; $index < count($children); $index++) { |
|
|
|
|
282
|
|
|
// If xml tag is <array>, parse without merge |
283
|
|
|
if ($children[$index]->getName() === "array") { |
284
|
|
|
$key = $children[$index]['name']; |
285
|
|
|
if (null !== $key) { |
286
|
|
|
$output[$key->__toString()] = $this->parseXmlStringValues($children[$index]); |
287
|
|
|
} |
288
|
|
|
} else { |
289
|
|
|
$output = array_merge($output, $this->parseXmlStringValues($children[$index])); |
290
|
|
|
} |
291
|
|
|
} |
292
|
|
|
} else { |
293
|
|
|
$key = $xml['name']; |
294
|
|
|
if (null !== $key) { |
295
|
|
|
$output[$key->__toString()] = $xml->__toString(); |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
return $output; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Gets a value from a defined key |
303
|
|
|
* @param string $key Key |
304
|
|
|
* @return string Value defined for the key $key or an empty string if the |
305
|
|
|
* key is not defined |
306
|
|
|
*/ |
307
|
|
|
public function get($key) { |
308
|
|
|
if (isset($this->values[$key])) { |
309
|
|
|
return $this->values[$key]; |
310
|
|
|
} else { |
311
|
|
|
return ""; |
312
|
|
|
} |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
public function onConfigChange() { |
316
|
|
|
$this->reloadConfig(); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
public function onLoad() { |
320
|
|
|
|
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
public function onRemove() { |
324
|
|
|
|
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
} |
328
|
|
|
|
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.
To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.