Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
TranslationServiceProvider
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
5 / 5
12
100.00% covered (success)
100.00%
1 / 1
 register
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
2
 setLocale
n/a
0 / 0
n/a
0 / 0
1
 getTranslator
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 loadFile
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getFile
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getFileLoader
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Engelsystem\Helpers\Translation;
6
7use Engelsystem\Config\Config;
8use Engelsystem\Container\ServiceProvider;
9use Engelsystem\Http\Request;
10use Gettext\Loader\MoLoader;
11use Gettext\Loader\PoLoader;
12use Gettext\Translations;
13use Illuminate\Contracts\Container\BindingResolutionException;
14use Illuminate\Support\Str;
15use Symfony\Component\HttpFoundation\Session\Session;
16
17class TranslationServiceProvider extends ServiceProvider
18{
19    protected GettextTranslator|array $translators = [];
20
21    public function register(): void
22    {
23        /** @var Config $config */
24        $config = $this->app->get('config');
25        /** @var Session $session */
26        $session = $this->app->get('session');
27        /** @var Request $request */
28        $request = $this->app->get('request');
29
30        $locales = $config->get('locales');
31        $defaultLocale = $config->get('default_locale');
32        $fallbackLocale = $config->get('fallback_locale', 'en_US');
33        $locale = $request->getPreferredLanguage(array_merge([$defaultLocale], array_keys($locales)));
34
35        $sessionLocale = $session->get('locale', $locale);
36        if (isset($locales[$sessionLocale])) {
37            $locale = $sessionLocale;
38        }
39
40        $session->set('locale', $locale);
41
42        $translator = $this->app->make(
43            Translator::class,
44            [
45                'locale'                => $locale,
46                'locales'               => $locales,
47                'fallbackLocale'        => $fallbackLocale,
48                'getTranslatorCallback' => [$this, 'getTranslator'],
49                'localeChangeCallback'  => [$this, 'setLocale'],
50            ]
51        );
52        $this->app->singleton(Translator::class, function () use ($translator) {
53            return $translator;
54        });
55        $this->app->alias(Translator::class, 'translator');
56    }
57
58    /**
59     * @codeCoverageIgnore
60     */
61    public function setLocale(string $locale): void
62    {
63        $locale .= '.UTF-8';
64        // Set the users locale
65        putenv('LC_ALL=' . $locale);
66        setlocale(LC_ALL, $locale);
67
68        // Reset numeric formatting to allow output of floats
69        putenv('LC_NUMERIC=C');
70        setlocale(LC_NUMERIC, 'C');
71    }
72
73    public function getTranslator(string $locale): GettextTranslator
74    {
75        if (isset($this->translators[$locale])) {
76            return $this->translators[$locale];
77        }
78
79        $names = ['default', 'additional'];
80
81        /** @var Translations $translations */
82        $translations = $this->app->call([Translations::class, 'create']);
83        $path = $this->app->get('path.lang');
84        foreach ($names as $name) {
85            $file = $this->getFile($locale, $path, $name);
86            $translations = $this->loadFile($file, $translations);
87        }
88
89        $file = $this->getFile($locale, $this->app->get('path.config') . '/lang', 'custom');
90        $translations = $this->loadFile($file, $translations);
91
92        /** @var GettextTranslator $translator */
93        $translator = GettextTranslator::createFromTranslations($translations);
94        $this->translators[$locale] = $translator;
95
96        return $this->translators[$locale];
97    }
98
99    protected function loadFile(string $file, Translations $translations): Translations
100    {
101        if (!file_exists($file)) {
102            return $translations;
103        }
104
105        $loader = $this->getFileLoader($file);
106
107        return $loader->loadFile($file, $translations);
108    }
109
110    protected function getFile(string $locale, string $basePath, string $name = 'default'): string
111    {
112        $filepath = $basePath . '/' . $locale . '/' . $name;
113        $file = $filepath . '.mo';
114
115        if (!file_exists($file)) {
116            $file = $filepath . '.po';
117        }
118
119        return $file;
120    }
121
122    /**
123     * @throws BindingResolutionException
124     */
125    protected function getFileLoader(string $file): MoLoader|PoLoader
126    {
127        if (Str::endsWith($file, '.mo')) {
128            /** @var MoLoader $loader */
129            return $this->app->make(MoLoader::class);
130        } else {
131            /** @var PoLoader $loader */
132            return $this->app->make(PoLoader::class);
133        }
134    }
135}