TranslatorServiceProvider   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 333
rs 10
c 0
b 0
f 0
wmc 22

4 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 5 1
D registerLocales() 0 116 10
A registerMiddleware() 0 19 1
D registerTranslator() 0 166 10
1
<?php
2
3
namespace Charcoal\Translator\ServiceProvider;
4
5
// From Pimple
6
use Pimple\Container;
7
use Pimple\ServiceProviderInterface;
8
9
// From 'symfony/translation'
10
use Symfony\Component\Translation\Loader\ArrayLoader;
11
use Symfony\Component\Translation\Loader\CsvFileLoader;
12
use Symfony\Component\Translation\Loader\IcuDatFileLoader;
13
use Symfony\Component\Translation\Loader\IcuResFileLoader;
14
use Symfony\Component\Translation\Loader\IniFileLoader;
15
use Symfony\Component\Translation\Loader\MoFileLoader;
16
use Symfony\Component\Translation\Loader\PhpFileLoader;
17
use Symfony\Component\Translation\Loader\PoFileLoader;
18
use Symfony\Component\Translation\Loader\QtFileLoader;
19
use Symfony\Component\Translation\Loader\XliffFileLoader;
20
use Symfony\Component\Translation\Loader\JsonFileLoader;
21
use Symfony\Component\Translation\Loader\YamlFileLoader;
22
use Symfony\Component\Translation\MessageSelector;
23
24
// From 'charcoal-translator'
25
use Charcoal\Translator\LocalesConfig;
26
use Charcoal\Translator\LocalesManager;
27
use Charcoal\Translator\Translator;
28
use Charcoal\Translator\TranslatorConfig;
29
use Charcoal\Translator\Middleware\LanguageMiddleware;
30
31
/**
32
 * Translation Service Provider
33
 *
34
 * Provides a service for translating your application into different languages,
35
 * and manage the target locale of a Charcoal application.
36
 */
37
class TranslatorServiceProvider implements ServiceProviderInterface
38
{
39
    /**
40
     * @param  Container $container Pimple DI container.
41
     * @return void
42
     */
43
    public function register(Container$container)
44
    {
45
        $this->registerLocales($container);
46
        $this->registerTranslator($container);
47
        $this->registerMiddleware($container);
48
    }
49
50
    /**
51
     * @param  Container $container Pimple DI container.
52
     * @return void
53
     */
54
    private function registerLocales(Container $container)
55
    {
56
        /**
57
         * Instance of the Locales Configset.
58
         *
59
         * @param  Container $container Pimple DI container.
60
         * @return LocalesConfig
61
         */
62
        $container['locales/config'] = function (Container $container) {
63
            $appConfig     = isset($container['config']) ? $container['config'] : [];
64
            $localesConfig = isset($appConfig['locales']) ? $appConfig['locales'] : null;
65
            return new LocalesConfig($localesConfig);
66
        };
67
68
        /**
69
         * Default language of the application, optionally the navigator's preferred language.
70
         *
71
         * @param  Container $container Pimple DI container.
72
         * @return string|null
73
         */
74
        $container['locales/default-language'] = function (Container $container) {
75
            $localesConfig = $container['locales/config'];
76
            if (isset($localesConfig['auto_detect']) && $localesConfig['auto_detect']) {
77
                if ($container['locales/browser-language'] !== null) {
78
                    return $container['locales/browser-language'];
79
                }
80
            }
81
            return $localesConfig['default_language'];
82
        };
83
84
        /**
85
         * Accepted language from the navigator.
86
         *
87
         * Example with Accept-Language "zh-Hant-HK, fr-CH, fr;q=0.9, en;q=0.7":
88
         *
89
         * 1. zh-Hant-HK
90
         * 2. fr-CH
91
         * 3. fr
92
         * 4. en
93
         *
94
         * @param  Container $container Pimple DI container.
95
         * @return string|null
96
         */
97
        $container['locales/browser-language'] = function (Container $container) {
98
            if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
99
                return null;
100
            }
101
102
            /**
103
             * Using data from configset instead of LocalesManager
104
             * since the latter might need the browser language
105
             * as the default language.
106
             */
107
            $localesConfig    = $container['locales/config'];
108
            $supportedLocales = array_filter($localesConfig['languages'], function ($locale) {
109
                return !(isset($locale['active']) && !$locale['active']);
110
            });
111
112
            $acceptableLanguages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
113
            foreach ($acceptableLanguages as $acceptedLang) {
114
                $lang = explode(';', $acceptedLang);
115
                $lang = trim($lang[0]);
116
                if (isset($supportedLocales[$lang])) {
117
                    return $lang;
118
                }
119
            }
120
121
            return null;
122
        };
123
124
        /**
125
         * List of fallback language codes for the translator.
126
         *
127
         * @todo   Use filtered "fallback_languages" from LocalesManager
128
         * @param  Container $container Pimple DI container.
129
         * @return string[]
130
         */
131
        $container['locales/fallback-languages'] = function (Container $container) {
132
            $localesConfig = $container['locales/config'];
133
            return $localesConfig['fallback_languages'];
134
        };
135
136
        /**
137
         * List of language codes (locale ident) from the available locales.
138
         *
139
         * @param  Container $container Pimple DI container.
140
         * @return string[]
141
         */
142
        $container['locales/available-languages'] = function (Container $container) {
143
            $manager = $container['locales/manager'];
144
            return $manager->availableLocales();
145
        };
146
147
        /**
148
         * List of available locales (as configuration structures) of the application.
149
         *
150
         * @param  Container $container Pimple DI container.
151
         * @return array
152
         */
153
        $container['locales/languages'] = function (Container $container) {
154
            $manager = $container['locales/manager'];
155
            return $manager->locales();
156
        };
157
158
        /**
159
         * Instance of the Locales Manager.
160
         *
161
         * @todo   Filter "fallback_languages"
162
         * @param  Container $container Pimple DI container.
163
         * @return LocalesManager
164
         */
165
        $container['locales/manager'] = function (Container $container) {
166
            $localesConfig = $container['locales/config'];
167
            return new LocalesManager([
168
                'locales'          => $localesConfig['languages'],
169
                'default_language' => $container['locales/default-language']
170
            ]);
171
        };
172
    }
173
174
    /**
175
     * @param  Container $container Pimple DI container.
176
     * @return void
177
     */
178
    private function registerTranslator(Container $container)
179
    {
180
        /**
181
         * Instance of the Translator Configset.
182
         *
183
         * @param  Container $container Pimple DI container.
184
         * @return TranslatorConfig
185
         */
186
        $container['translator/config'] = function (Container $container) {
187
            $appConfig        = isset($container['config']) ? $container['config'] : [];
188
            $translatorConfig = isset($appConfig['translator']) ? $appConfig['translator'] : null;
189
            return new TranslatorConfig($translatorConfig);
190
        };
191
192
        /**
193
         * Dictionary of translations grouped by domain and locale.
194
         *
195
         * @param  Container $container Pimple DI container.
196
         * @return array
197
         */
198
        $container['translator/translations'] = function (Container $container) {
199
            $translatorConfig = $container['translator/config'];
200
            return $translatorConfig['translations'];
201
        };
202
203
        /**
204
         * Instance of the Message Selector, that is used to resolve a translation.
205
         *
206
         * @return MessageSelector
207
         */
208
        $container['translator/message-selector'] = function () {
209
            return new MessageSelector();
210
        };
211
212
        /**
213
         * Instance of the Translator, that is used for translation.
214
         *
215
         * @todo   Improve file loader with a map of file formats.
216
         * @param  Container $container Pimple DI container.
217
         * @return Translator
218
         */
219
        $container['translator'] = function (Container $container) {
220
            $translatorConfig = $container['translator/config'];
221
            $translator = new Translator([
222
                'manager'           => $container['locales/manager'],
223
                'message_selector'  => $container['translator/message-selector'],
224
                'cache_dir'         => $translatorConfig['cache_dir'],
225
                'debug'             => $translatorConfig['debug']
226
            ]);
227
228
            $translator->setFallbackLocales($container['locales/fallback-languages']);
229
230
            $translator->addLoader('array', $container['translator/loader/array']);
231
232
            foreach ($translatorConfig['loaders'] as $loader) {
233
                $translator->addLoader($loader, $container['translator/loader/file/'.$loader]);
234
                $paths = array_reverse($translatorConfig['paths']);
0 ignored issues
show
Unused Code introduced by
The assignment to $paths is dead and can be removed.
Loading history...
235
                foreach ($translatorConfig['paths'] as $path) {
236
                    $path = realpath($container['config']['base_path'].$path);
237
                    if ($path === false) {
238
                        continue;
239
                    }
240
                    $files = glob($path.'/*.'.$loader);
241
                    foreach ($files as $f) {
242
                        $names = explode('.', basename($f));
243
                        if (count($names) < 3) {
244
                            continue;
245
                        }
246
                        $lang = $names[1];
247
                        $domain = $names[0];
248
                        $translator->addResource($loader, $f, $lang, $domain);
249
                    }
250
                }
251
            }
252
253
            foreach ($container['translator/translations'] as $domain => $data) {
254
                foreach ($data as $locale => $messages) {
255
                    $translator->addResource('array', $messages, $locale, $domain);
256
                }
257
            }
258
259
            return $translator;
260
        };
261
262
        /**
263
         * @return ArrayLoader
264
         */
265
        $container['translator/loader/array'] = function () {
266
            return new ArrayLoader();
267
        };
268
269
        /**
270
         * @return CsvFileLoader
271
         */
272
        $container['translator/loader/file/csv'] = function () {
273
            return new CsvFileLoader();
274
        };
275
276
        /**
277
         * @return IcuDatFileLoader
278
         */
279
        $container['translator/loader/file/dat'] = function () {
280
            return new IcuDatFileLoader();
281
        };
282
283
        /**
284
         * @return IcuResFileLoader
285
         */
286
        $container['translator/loader/file/res'] = function () {
287
            return new IcuResFileLoader();
288
        };
289
290
        /**
291
         * @return IniFileLoader
292
         */
293
        $container['translator/loader/file/ini'] = function () {
294
            return new IniFileLoader();
295
        };
296
297
        /**
298
         * @return JsonFileLoader
299
         */
300
        $container['translator/loader/file/json'] = function () {
301
            return new JsonFileLoader();
302
        };
303
304
        /**
305
         * @return MoFileLoader
306
         */
307
        $container['translator/loader/file/mo'] = function () {
308
            return new MoFileLoader();
309
        };
310
311
        /**
312
         * @return PhpFileLoader
313
         */
314
        $container['translator/loader/file/php'] = function () {
315
            return new PhpFileLoader();
316
        };
317
318
        /**
319
         * @return PoFileLoader
320
         */
321
        $container['translator/loader/file/po'] = function () {
322
            return new PoFileLoader();
323
        };
324
325
        /**
326
         * @return QtFileLoader
327
         */
328
        $container['translator/loader/file/qt'] = function () {
329
            return new QtFileLoader();
330
        };
331
332
        /**
333
         * @return XliffFileLoader
334
         */
335
        $container['translator/loader/file/xliff'] = function () {
336
            return new XliffFileLoader();
337
        };
338
339
        /**
340
         * @return YamlFileLoader
341
         */
342
        $container['translator/loader/file/yaml'] = function () {
343
            return new YamlFileLoader();
344
        };
345
    }
346
347
    /**
348
     * @param  Container $container Pimple DI container.
349
     * @return void
350
     */
351
    private function registerMiddleware(Container $container)
352
    {
353
        /**
354
         * @param Container $container
355
         * @return LanguageMiddleware
356
         */
357
        $container['middlewares/charcoal/translator/middleware/language'] = function (Container $container) {
358
            $middlewareConfig = $container['config']['middlewares']['charcoal/translator/middleware/language'];
359
            $middlewareConfig = array_replace(
360
                [
361
                    'default_language'  => $container['translator']->getLocale()
362
                ],
363
                $middlewareConfig,
364
                [
365
                    'translator'        => $container['translator'],
366
                    'browser_language'  => $container['locales/browser-language']
367
                ]
368
            );
369
            return new LanguageMiddleware($middlewareConfig);
370
        };
371
    }
372
}
373