Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
LanguageListener
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
4 / 4
10
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 onKernelRequest
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 detectLanguage
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
5
 initializeTranslation
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * Language detection and translation initialization listener
5 *
6 * Runs on kernel.request with high priority to set up language and translation
7 * before any controller is invoked.
8 *
9 * This Source Code Form is subject to the terms of the Mozilla Public License,
10 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
11 * obtain one at https://mozilla.org/MPL/2.0/.
12 *
13 * @package   phpMyFAQ
14 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
15 * @copyright 2026 phpMyFAQ Team
16 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
17 * @link      https://www.phpmyfaq.de
18 * @since     2026-02-15
19 */
20
21declare(strict_types=1);
22
23namespace phpMyFAQ\EventListener;
24
25use phpMyFAQ\Configuration;
26use phpMyFAQ\Core\Exception;
27use phpMyFAQ\Language;
28use phpMyFAQ\Strings;
29use phpMyFAQ\Translation;
30use Symfony\Component\DependencyInjection\ContainerInterface;
31use Symfony\Component\HttpKernel\Event\RequestEvent;
32
33class LanguageListener
34{
35    private bool $initialized = false;
36
37    public function __construct(
38        private readonly ContainerInterface $container,
39    ) {
40    }
41
42    /**
43     * @throws Exception
44     */
45    public function onKernelRequest(RequestEvent $event): void
46    {
47        if (!$event->isMainRequest() || $this->initialized) {
48            return;
49        }
50
51        $this->initialized = true;
52
53        $currentLanguage = $this->detectLanguage();
54        $this->initializeTranslation($currentLanguage);
55    }
56
57    private function detectLanguage(): string
58    {
59        if (!$this->container->has('phpmyfaq.configuration') || !$this->container->has('phpmyfaq.language')) {
60            return 'en';
61        }
62
63        /** @var Configuration $configuration */
64        $configuration = $this->container->get(id: 'phpmyfaq.configuration');
65        /** @var Language $language */
66        $language = $this->container->get(id: 'phpmyfaq.language');
67
68        $configuration->setContainer($this->container);
69
70        $detect = (bool) $configuration->get(item: 'main.languageDetection');
71        $configLang = (string) $configuration->get(item: 'main.language');
72
73        $currentLanguage = $detect
74            ? $language->setLanguageWithDetection($configLang)
75            : $language->setLanguageFromConfiguration($configLang);
76
77        require_once PMF_TRANSLATION_DIR . '/language_en.php';
78        if (Language::isASupportedLanguage($currentLanguage)) {
79            require_once PMF_TRANSLATION_DIR . '/language_' . strtolower($currentLanguage) . '.php';
80        }
81
82        $configuration->setLanguage($language);
83
84        return $currentLanguage;
85    }
86
87    /**
88     * @throws Exception
89     */
90    private function initializeTranslation(string $currentLanguage): void
91    {
92        Strings::init($currentLanguage);
93
94        Translation::create()
95            ->setTranslationsDir(PMF_TRANSLATION_DIR)
96            ->setDefaultLanguage(defaultLanguage: 'en')
97            ->setCurrentLanguage($currentLanguage)
98            ->setMultiByteLanguage();
99    }
100}