1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Charcoal\Translator; |
4
|
|
|
|
5
|
|
|
use InvalidArgumentException; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Locales Manager |
9
|
|
|
* |
10
|
|
|
* The manager handles the collection of available languages, their definitions, |
11
|
|
|
* the default language, and tracks the current language. |
12
|
|
|
*/ |
13
|
|
|
class LocalesManager |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* Dictionary of language definitions. |
17
|
|
|
* |
18
|
|
|
* @var array |
19
|
|
|
*/ |
20
|
|
|
private $locales; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* List of language codes. |
24
|
|
|
* |
25
|
|
|
* @var string[] |
26
|
|
|
*/ |
27
|
|
|
private $languages; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Language code for the default locale. |
31
|
|
|
* |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
private $defaultLanguage; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Language code for the current locale. |
38
|
|
|
* |
39
|
|
|
* @var string|null |
40
|
|
|
*/ |
41
|
|
|
private $currentLanguage; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Create the Locales Manager with locales and optional options. |
45
|
|
|
* |
46
|
|
|
* Required parameters: |
47
|
|
|
* - **locales** (`array`) |
48
|
|
|
* |
49
|
|
|
* Optional parameters: |
50
|
|
|
* - **default_language** (`string`) |
51
|
|
|
* - If none is set, the first language (from _locales_) will be used. |
52
|
|
|
* - **current_language** (`string`) |
53
|
|
|
* - If none is set, then the default language will be used. |
54
|
|
|
* |
55
|
|
|
* @param array $data Constructor dependencies. |
56
|
|
|
* @throws InvalidArgumentException If the default language is not a valid language. |
57
|
|
|
*/ |
58
|
|
|
public function __construct(array $data) |
59
|
|
|
{ |
60
|
|
|
$this->setLocales($data['locales']); |
61
|
|
|
|
62
|
|
|
$default = isset($data['default_language']) ? $data['default_language'] : null; |
63
|
|
|
$this->setDefaultLocale($default); |
64
|
|
|
|
65
|
|
|
$current = isset($data['current_language']) ? $data['current_language'] : null; |
66
|
|
|
$this->setCurrentLocale($current); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Retrieve the available locales information. |
71
|
|
|
* |
72
|
|
|
* @return array |
73
|
|
|
*/ |
74
|
|
|
public function locales() |
75
|
|
|
{ |
76
|
|
|
return $this->locales; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Retrieve the available locales (language codes). |
81
|
|
|
* |
82
|
|
|
* @return string[] |
83
|
|
|
*/ |
84
|
|
|
public function availableLocales() |
85
|
|
|
{ |
86
|
|
|
return $this->languages; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* Set the default language. |
91
|
|
|
* |
92
|
|
|
* @param string|null $lang The default language code. |
93
|
|
|
* If NULL, the first language is assigned. |
94
|
|
|
* @throws InvalidArgumentException If the language is invalid. |
95
|
|
|
* @return void |
96
|
|
|
*/ |
97
|
|
View Code Duplication |
private function setDefaultLocale($lang) |
|
|
|
|
98
|
|
|
{ |
99
|
|
|
if ($lang === null) { |
100
|
|
|
$this->defaultLanguage = $this->languages[0]; |
101
|
|
|
return; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
if (!$this->hasLocale($lang)) { |
105
|
|
|
if (!is_string($lang)) { |
106
|
|
|
$lang = is_object($lang) ? get_class($lang) : gettype($lang); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
throw new InvalidArgumentException(sprintf( |
110
|
|
|
'Unsupported default language; must be one of "%s", received "%s"', |
111
|
|
|
implode(', ', $this->availableLocales()), |
112
|
|
|
$lang |
113
|
|
|
)); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
$this->defaultLanguage = $lang; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Retrieve the default language. |
121
|
|
|
* |
122
|
|
|
* @return string |
123
|
|
|
*/ |
124
|
|
|
public function defaultLocale() |
125
|
|
|
{ |
126
|
|
|
return $this->defaultLanguage; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Set the current language. |
131
|
|
|
* |
132
|
|
|
* @param string|null $lang The current language code. |
133
|
|
|
* If NULL, the current language is unset. |
134
|
|
|
* @throws InvalidArgumentException If the language is invalid. |
135
|
|
|
* @return void |
136
|
|
|
*/ |
137
|
|
View Code Duplication |
public function setCurrentLocale($lang) |
|
|
|
|
138
|
|
|
{ |
139
|
|
|
if ($lang === null) { |
140
|
|
|
$this->currentLanguage = null; |
141
|
|
|
return; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
if (!$this->hasLocale($lang)) { |
145
|
|
|
if (!is_string($lang)) { |
146
|
|
|
$lang = is_object($lang) ? get_class($lang) : gettype($lang); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
throw new InvalidArgumentException(sprintf( |
150
|
|
|
'Unsupported language; must be one of "%s", received "%s"', |
151
|
|
|
implode(', ', $this->availableLocales()), |
152
|
|
|
$lang |
153
|
|
|
)); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
$this->currentLanguage = $lang; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Retrieve the current language. |
161
|
|
|
* |
162
|
|
|
* @return string |
163
|
|
|
*/ |
164
|
|
|
public function currentLocale() |
165
|
|
|
{ |
166
|
|
|
if ($this->currentLanguage === null) { |
167
|
|
|
return $this->defaultLanguage; |
168
|
|
|
} |
169
|
|
|
return $this->currentLanguage; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Determine if a locale is available. |
174
|
|
|
* |
175
|
|
|
* @param string $lang The language code to check. |
176
|
|
|
* @return boolean |
177
|
|
|
*/ |
178
|
|
|
public function hasLocale($lang) |
179
|
|
|
{ |
180
|
|
|
return isset($this->locales[$lang]); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Set the available languages. |
185
|
|
|
* |
186
|
|
|
* Ensure that explicitely inactive locales are excluded and that the required |
187
|
|
|
* values are set on the locales configuration structure. |
188
|
|
|
* |
189
|
|
|
* This method is only called from the constructor. |
190
|
|
|
* |
191
|
|
|
* @param array $locales The locales configuration structure. |
192
|
|
|
* @throws InvalidArgumentException If there are no active locales. |
193
|
|
|
* @return void |
194
|
|
|
*/ |
195
|
|
|
private function setLocales(array $locales) |
196
|
|
|
{ |
197
|
|
|
$this->locales = []; |
198
|
|
|
$this->languages = []; |
199
|
|
|
foreach ($locales as $langCode => $locale) { |
200
|
|
|
if (isset($locale['active']) && !$locale['active']) { |
201
|
|
|
continue; |
202
|
|
|
} |
203
|
|
|
if (!isset($locale['locale'])) { |
204
|
|
|
$locale['locale'] = $langCode; |
205
|
|
|
} |
206
|
|
|
$this->locales[$langCode] = $locale; |
207
|
|
|
$this->languages[] = $langCode; |
208
|
|
|
} |
209
|
|
|
if (empty($this->locales)) { |
210
|
|
|
throw new InvalidArgumentException( |
211
|
|
|
'Locales can not be empty.' |
212
|
|
|
); |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
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.