1 | <?php |
||
2 | |||
3 | namespace Backend\Core\Language; |
||
4 | |||
5 | use Backend\Core\Engine\Model; |
||
6 | use Backend\Modules\Locale\Engine\Model as BackendLocaleModel; |
||
7 | use RuntimeException; |
||
8 | use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; |
||
9 | |||
10 | /** |
||
11 | * This class will store the language-dependant content for the Backend, it will also store the |
||
12 | * current language for the user. |
||
13 | */ |
||
14 | class Language |
||
15 | { |
||
16 | /** |
||
17 | * The errors |
||
18 | * |
||
19 | * @var array |
||
20 | */ |
||
21 | protected static $err = []; |
||
22 | |||
23 | /** |
||
24 | * The labels |
||
25 | * |
||
26 | * @var array |
||
27 | */ |
||
28 | protected static $lbl = []; |
||
29 | |||
30 | /** |
||
31 | * The messages |
||
32 | * |
||
33 | * @var array |
||
34 | */ |
||
35 | protected static $msg = []; |
||
36 | |||
37 | /** |
||
38 | * The active languages |
||
39 | * |
||
40 | * @var array |
||
41 | */ |
||
42 | protected static $activeLanguages; |
||
43 | |||
44 | /** |
||
45 | * The current interface-language |
||
46 | * |
||
47 | * @var string |
||
48 | */ |
||
49 | protected static $currentInterfaceLanguage; |
||
50 | |||
51 | /** |
||
52 | * The current language that the user is working with |
||
53 | * |
||
54 | * @var string |
||
55 | */ |
||
56 | protected static $currentWorkingLanguage; |
||
57 | |||
58 | public static function getActiveLanguages(): array |
||
59 | { |
||
60 | // validate the cache |
||
61 | if (empty(self::$activeLanguages)) { |
||
62 | self::$activeLanguages = (array) Model::get('fork.settings')->get('Core', 'active_languages'); |
||
63 | } |
||
64 | |||
65 | // return from cache |
||
66 | return self::$activeLanguages; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * Get all active languages in a format usable by SpoonForm's addRadioButton |
||
71 | * |
||
72 | * @return array |
||
73 | */ |
||
74 | public static function getCheckboxValues(): array |
||
75 | { |
||
76 | $languages = self::getActiveLanguages(); |
||
77 | $results = []; |
||
78 | |||
79 | // stop here if no languages are present |
||
80 | if (empty($languages)) { |
||
81 | return []; |
||
82 | } |
||
83 | |||
84 | // addRadioButton requires an array with keys 'value' and 'label' |
||
85 | foreach ($languages as $abbreviation) { |
||
86 | $results[] = [ |
||
87 | 'value' => $abbreviation, |
||
88 | 'label' => self::lbl(mb_strtoupper($abbreviation)), |
||
89 | ]; |
||
90 | } |
||
91 | |||
92 | return $results; |
||
93 | } |
||
94 | |||
95 | 71 | public static function getCurrentModule(): string |
|
96 | { |
||
97 | // Needed to make it possible to use the backend language in the console. |
||
98 | 71 | if (!defined('APPLICATION') || APPLICATION === 'Console') { |
|
99 | return 'Core'; |
||
100 | } |
||
101 | |||
102 | 71 | if (Model::getContainer()->has('url')) { |
|
103 | 71 | return Model::get('url')->getModule(); |
|
104 | } |
||
105 | |||
106 | if (Model::requestIsAvailable() && Model::getRequest()->query->has('module')) { |
||
107 | return Model::getRequest()->query->get('module'); |
||
108 | } |
||
109 | |||
110 | return 'Core'; |
||
111 | } |
||
112 | |||
113 | 71 | public static function getError(string $key, string $module = null): string |
|
114 | { |
||
115 | 71 | $module = $module ?? self::getCurrentModule(); |
|
116 | |||
117 | 71 | $key = \SpoonFilter::toCamelCase($key); |
|
118 | |||
119 | // check if the error exists |
||
120 | 71 | if (isset(self::$err[$module][$key])) { |
|
121 | 5 | return self::$err[$module][$key]; |
|
122 | } |
||
123 | |||
124 | // check if the error exists in the Core |
||
125 | 71 | if (isset(self::$err['Core'][$key])) { |
|
126 | 71 | return self::$err['Core'][$key]; |
|
127 | } |
||
128 | |||
129 | // otherwise return the key in label-format |
||
130 | 2 | return '{$err' . \SpoonFilter::toCamelCase($module) . $key . '}'; |
|
131 | } |
||
132 | |||
133 | 71 | public static function getErrors(): array |
|
134 | { |
||
135 | 71 | return self::$err; |
|
136 | } |
||
137 | |||
138 | 131 | public static function getInterfaceLanguage(): string |
|
139 | { |
||
140 | 131 | if (self::$currentInterfaceLanguage === null) { |
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
141 | self::$currentInterfaceLanguage = Model::getContainer()->getParameter('site.default_language'); |
||
142 | } |
||
143 | |||
144 | 131 | return self::$currentInterfaceLanguage; |
|
145 | } |
||
146 | |||
147 | 131 | public static function getInterfaceLanguages(): array |
|
148 | { |
||
149 | 131 | $languages = []; |
|
150 | |||
151 | // grab the languages from the settings & loop language to reset the label |
||
152 | 131 | foreach ((array) Model::get('fork.settings')->get('Core', 'interface_languages', ['en']) as $key) { |
|
153 | // fetch language's translation |
||
154 | 131 | $languages[$key] = self::getLabel(mb_strtoupper($key), 'Core'); |
|
155 | } |
||
156 | |||
157 | // sort alphabetically |
||
158 | 131 | asort($languages); |
|
159 | |||
160 | // return languages |
||
161 | 131 | return $languages; |
|
162 | } |
||
163 | |||
164 | 131 | public static function getLabel(string $key, string $module = null): string |
|
165 | { |
||
166 | 131 | $module = $module ?? self::getCurrentModule(); |
|
167 | |||
168 | 131 | $key = \SpoonFilter::toCamelCase($key); |
|
169 | |||
170 | // check if the label exists |
||
171 | 131 | if (isset(self::$lbl[$module][$key])) { |
|
172 | 131 | return self::$lbl[$module][$key]; |
|
173 | } |
||
174 | |||
175 | // check if the label exists in the Core |
||
176 | 131 | if (isset(self::$lbl['Core'][$key])) { |
|
177 | 71 | return self::$lbl['Core'][$key]; |
|
178 | } |
||
179 | |||
180 | // otherwise return the key in label-format |
||
181 | 131 | return '{$lbl' . \SpoonFilter::toCamelCase($module) . $key . '}'; |
|
182 | } |
||
183 | |||
184 | 71 | public static function getLabels(): array |
|
185 | { |
||
186 | 71 | return self::$lbl; |
|
187 | } |
||
188 | |||
189 | 71 | public static function getMessage(string $key, string $module = null): string |
|
190 | { |
||
191 | 71 | $key = \SpoonFilter::toCamelCase((string) $key); |
|
192 | 71 | $module = $module ?? self::getCurrentModule(); |
|
193 | |||
194 | // check if the message exists |
||
195 | 71 | if (isset(self::$msg[$module][$key])) { |
|
196 | 23 | return self::$msg[$module][$key]; |
|
197 | } |
||
198 | |||
199 | // check if the message exists in the Core |
||
200 | 71 | if (isset(self::$msg['Core'][$key])) { |
|
201 | 67 | return self::$msg['Core'][$key]; |
|
202 | } |
||
203 | |||
204 | // otherwise return the key in label-format |
||
205 | 71 | return '{$msg' . \SpoonFilter::toCamelCase($module) . $key . '}'; |
|
206 | } |
||
207 | |||
208 | 71 | public static function getMessages(): array |
|
209 | { |
||
210 | 71 | return self::$msg; |
|
211 | } |
||
212 | |||
213 | 131 | public static function getWorkingLanguage(): string |
|
214 | { |
||
215 | 131 | if (self::$currentWorkingLanguage === null) { |
|
0 ignored issues
–
show
|
|||
216 | 34 | self::$currentWorkingLanguage = Model::getContainer()->getParameter('site.default_language'); |
|
217 | } |
||
218 | |||
219 | 131 | return self::$currentWorkingLanguage; |
|
220 | } |
||
221 | |||
222 | 131 | public static function getWorkingLanguages(): array |
|
223 | { |
||
224 | 131 | $languages = []; |
|
225 | |||
226 | // grab the languages from the settings & loop language to reset the label |
||
227 | 131 | foreach ((array) Model::get('fork.settings')->get('Core', 'languages', ['en']) as $key) { |
|
228 | // fetch the language's translation |
||
229 | 131 | $languages[$key] = self::getLabel(mb_strtoupper($key), 'Core'); |
|
230 | } |
||
231 | |||
232 | // sort alphabetically |
||
233 | 131 | asort($languages); |
|
234 | |||
235 | 131 | return $languages; |
|
236 | } |
||
237 | |||
238 | /** |
||
239 | * Set locale |
||
240 | * It will require the correct file and init the needed vars |
||
241 | * |
||
242 | * @param string $language The language to load. |
||
243 | */ |
||
244 | 131 | public static function setLocale(string $language): void |
|
245 | { |
||
246 | 131 | $application = (!defined('APPLICATION') || APPLICATION === 'Console') ? 'Backend' : APPLICATION; |
|
247 | |||
248 | // validate file, generate it if needed |
||
249 | 131 | if (!is_file(BACKEND_CACHE_PATH . '/Locale/en.json')) { |
|
250 | 2 | BackendLocaleModel::buildCache('en', $application); |
|
251 | } |
||
252 | 131 | if (!is_file(BACKEND_CACHE_PATH . '/Locale/' . $language . '.json')) { |
|
253 | // if you use the language in the console act like it is in the backend |
||
254 | BackendLocaleModel::buildCache($language, $application); |
||
255 | } |
||
256 | |||
257 | // store |
||
258 | 131 | self::$currentInterfaceLanguage = $language; |
|
259 | |||
260 | // attempt to set a cookie |
||
261 | try { |
||
262 | // Needed to make it possible to use the backend language in the console. |
||
263 | 131 | if (defined('APPLICATION') && APPLICATION !== 'Console') { |
|
264 | 131 | Model::getContainer()->get('fork.cookie')->set('interface_language', $language); |
|
265 | } |
||
266 | } catch (RuntimeException|ServiceNotFoundException $e) { |
||
267 | // settings cookies isn't allowed, because this isn't a real problem we ignore the exception |
||
268 | } |
||
269 | |||
270 | // set English translations, they'll be the fallback |
||
271 | 131 | $translations = json_decode( |
|
272 | 131 | file_get_contents(BACKEND_CACHE_PATH . '/Locale/en.json'), |
|
273 | 131 | true |
|
274 | ); |
||
275 | 131 | self::$err = (array) ($translations['err'] ?? []); |
|
276 | 131 | self::$lbl = (array) ($translations['lbl'] ?? []); |
|
277 | 131 | self::$msg = (array) ($translations['msg'] ?? []); |
|
278 | |||
279 | // overwrite with the requested language's translations |
||
280 | 131 | $translations = json_decode( |
|
281 | 131 | file_get_contents(BACKEND_CACHE_PATH . '/Locale/' . $language . '.json'), |
|
282 | 131 | true |
|
283 | ); |
||
284 | 131 | $err = (array) ($translations['err'] ?? []); |
|
285 | 131 | $lbl = (array) ($translations['lbl'] ?? []); |
|
286 | 131 | $msg = (array) ($translations['msg'] ?? []); |
|
287 | 131 | foreach ($err as $module => $translations) { |
|
288 | 131 | if (!isset(self::$err[$module])) { |
|
289 | self::$err[$module] = []; |
||
290 | } |
||
291 | 131 | self::$err[$module] = array_merge(self::$err[$module], $translations); |
|
292 | } |
||
293 | 131 | foreach ($lbl as $module => $translations) { |
|
294 | 131 | if (!isset(self::$lbl[$module])) { |
|
295 | self::$lbl[$module] = []; |
||
296 | } |
||
297 | 131 | self::$lbl[$module] = array_merge(self::$lbl[$module], $translations); |
|
298 | } |
||
299 | 131 | foreach ($msg as $module => $translations) { |
|
300 | 131 | if (!isset(self::$msg[$module])) { |
|
301 | self::$msg[$module] = []; |
||
302 | } |
||
303 | 131 | self::$msg[$module] = array_merge(self::$msg[$module], $translations); |
|
304 | } |
||
305 | 131 | } |
|
306 | |||
307 | /** |
||
308 | * @param string $language The language to use, if not provided we will use the working language. |
||
309 | */ |
||
310 | 131 | public static function setWorkingLanguage(string $language): void |
|
311 | { |
||
312 | 131 | self::$currentWorkingLanguage = $language; |
|
313 | 131 | } |
|
314 | |||
315 | 71 | public static function err(string $key, string $module = null): string |
|
316 | { |
||
317 | 71 | return self::getError($key, $module); |
|
318 | } |
||
319 | |||
320 | 74 | public static function lbl(string $key, string $module = null): string |
|
321 | { |
||
322 | 74 | return self::getLabel($key, $module); |
|
323 | } |
||
324 | |||
325 | 71 | public static function msg(string $key, string $module = null): string |
|
326 | { |
||
327 | 71 | return self::getMessage($key, $module); |
|
328 | } |
||
329 | |||
330 | public static function isActiveLanguage(string $language): bool |
||
331 | { |
||
332 | return in_array($language, self::getActiveLanguages(), true); |
||
333 | } |
||
334 | } |
||
335 |