diff --git a/src/App/Adapters/WebAppAdapter.php b/src/App/Adapters/WebAppAdapter.php index dfdb396e0..d15f77ccc 100644 --- a/src/App/Adapters/WebAppAdapter.php +++ b/src/App/Adapters/WebAppAdapter.php @@ -97,8 +97,6 @@ public function start(): ?int try { $this->initializeRequestResponse($this->request, $this->response); - $this->loadLanguage(); - if ($this->request->isMethod('OPTIONS')) { stop(); } @@ -110,6 +108,8 @@ public function start(): ?int $this->initializeRouter($this->request); + $this->loadLanguage(); + info(HookManager::getInstance()->getRegistered(), ['tab' => Debugger::HOOKS]); if (current_middlewares()) { diff --git a/src/Http/Request/HttpRequest.php b/src/Http/Request/HttpRequest.php index 64672caaa..6da60fdf2 100644 --- a/src/Http/Request/HttpRequest.php +++ b/src/Http/Request/HttpRequest.php @@ -142,8 +142,9 @@ public static function setRequestParams(array $params) /** * Sets the uploaded files array merging handled $_FILES and parsed files - * @param array $rawInputFiles + * @param array $files * @throws BaseException + * @throws ReflectionException */ public static function setUploadedFiles(array $files) { diff --git a/src/Http/Traits/Request/Internal.php b/src/Http/Traits/Request/Internal.php index e5dffbd5c..c937ce3ce 100644 --- a/src/Http/Traits/Request/Internal.php +++ b/src/Http/Traits/Request/Internal.php @@ -86,7 +86,7 @@ public static function create( if ($headers) { foreach ($headers as $name => $value) { - $server->set('HTTP_' . strtoupper($name), $value); + $server->set('HTTP_' . strtoupper(str_replace('-', '_', $name)), $value); } } diff --git a/src/Libraries/Lang/Factories/LangFactory.php b/src/Libraries/Lang/Factories/LangFactory.php index 268dad892..bfe23baf5 100644 --- a/src/Libraries/Lang/Factories/LangFactory.php +++ b/src/Libraries/Lang/Factories/LangFactory.php @@ -53,17 +53,39 @@ public static function get(): Lang } $isEnabled = filter_var(config()->get('lang.enabled'), FILTER_VALIDATE_BOOLEAN); + $supported = (array)config()->get('lang.supported'); + $default = config()->get('lang.default'); - $langSegmentIndex = (int)config()->get('lang.url_segment'); + $queryLang = Request::getQueryParam('lang'); - if (!empty(route_prefix()) && $langSegmentIndex == 1) { - $langSegmentIndex++; + $lang = $queryLang && in_array($queryLang, $supported) + ? $queryLang + : null; + + if (empty($lang)) { + $segmentIndex = (int)config()->get('lang.url_segment'); + + if (!empty(route_prefix()) && $segmentIndex == 1) { + $segmentIndex++; + } + + $segmentLang = Request::getSegment($segmentIndex); + + $lang = $segmentLang && in_array($segmentLang, $supported) + ? $segmentLang + : null; } - $lang = Request::getSegment($langSegmentIndex); + if (empty($lang)) { + $acceptedLang = server()->acceptedLang(); - if (empty($lang) || !in_array($lang, (array)config()->get('lang.supported'))) { - $lang = config()->get('lang.default'); + $lang = $acceptedLang && in_array($acceptedLang, $supported) + ? $acceptedLang + : null; + } + + if (empty($lang)) { + $lang = $default; } if (!$lang) { @@ -71,7 +93,6 @@ public static function get(): Lang } $translator = new Translator($lang); - return self::$instance = new Lang($lang, $isEnabled, $translator); } -} +} \ No newline at end of file diff --git a/tests/Unit/AppTestCase.php b/tests/Unit/AppTestCase.php index ebafc50d6..e9d28ecb1 100644 --- a/tests/Unit/AppTestCase.php +++ b/tests/Unit/AppTestCase.php @@ -5,7 +5,9 @@ use Quantum\Libraries\Storage\Factories\FileSystemFactory; use Quantum\App\Factories\AppFactory; use Quantum\Environment\Environment; +use Quantum\Router\RouteController; use PHPUnit\Framework\TestCase; +use Quantum\Http\Request; use Quantum\Loader\Setup; use ReflectionClass; use Quantum\App\App; @@ -65,4 +67,24 @@ protected function removeFile(string $filePath) $this->fs->remove($filePath); } } + + protected function testRequest( + string $uri, + string $method = 'GET', + array $body = [], + array $headers = [] + ) + { + $request = new Request(); + + $request->create($method, $uri, $body, $headers); + + RouteController::setCurrentRoute([ + "route" => "test", + "method" => $method, + "controller" => 'TestController', + "action" => 'testAction', + "module" => 'Test', + ]); + } } \ No newline at end of file diff --git a/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php b/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php index e89d58c7b..afb888e31 100644 --- a/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php +++ b/tests/Unit/Libraries/Lang/Factories/LangFactoryTest.php @@ -1,6 +1,6 @@ setPrivateProperty(LangFactory::class, 'instance', null); - - config()->set('lang', [ - 'enabled' => true, - 'default' => 'en', - 'supported' => ['en', 'es'], - 'url_segment' => 1 - ]); } - public function testLangFactoryGetLangInstance(): void + public function testLangFactoryGetLangInstance() { $lang = LangFactory::get(); @@ -35,7 +28,7 @@ public function testLangFactoryGetLangInstance(): void $this->assertTrue($lang->isEnabled()); } - public function testLangFactoryGetReturnsSameInstance(): void + public function testLangFactoryGetReturnsSameInstance() { $first = LangFactory::get(); @@ -44,20 +37,88 @@ public function testLangFactoryGetReturnsSameInstance(): void $this->assertSame($first, $second); } - public function testLangFactoryGetFallsBackToDefaultIfSegmentInvalid(): void + public function testLangFactoryDetectedFromRouteParameter() + { + $this->testRequest('http://127.0.0.1/es/api/rest'); + + $lang = LangFactory::get(); + + $this->assertEquals('es', $lang->getLang()); + } + + public function testLangFactoryDetectedFromQueryParameter() + { + $this->testRequest('http://127.0.0.1/api/rest?lang=es'); + + $lang = LangFactory::get(); + + $this->assertEquals('es', $lang->getLang()); + } + + public function testLangFactoryDetectedFromAcceptedLangParameter() + { + $this->testRequest('http://127.0.0.1/api/rest', 'GET', [], ['Accept-Language' => 'es, en;q=0.8, fr;q=0.6']); + + $lang = LangFactory::get(); + + $this->assertEquals('es', $lang->getLang()); + } + + public function testLangFactoryFallsBackToDefaultIfNoLangDetected() + { + $this->testRequest('http://127.0.0.1/api/rest'); + + $lang = LangFactory::get(); + + $this->assertEquals('en', $lang->getLang()); + } + + public function testLangFactoryFallsBackToDefaultIfProvidedLangIsNotSupported() { - config()->set('lang.url_segment', 0); + config()->set('lang', [ + 'enabled' => true, + 'default' => 'en', + 'supported' => ['en', 'es'], + 'url_segment' => 1 + ]); + + $this->testRequest('http://127.0.0.1/fr/api/rest'); + + $lang = LangFactory::get(); + + $this->assertEquals('en', $lang->getLang()); + + $this->setPrivateProperty(LangFactory::class, 'instance', null); + + $this->testRequest('http://127.0.0.1/api/rest?lang=fr'); + + $lang = LangFactory::get(); + + $this->assertEquals('en', $lang->getLang()); + + $this->setPrivateProperty(LangFactory::class, 'instance', null); + + $this->testRequest('http://127.0.0.1/api/rest', 'GET', [], ['Accept-Language' => 'fr, en;q=0.8, fr;q=0.6']); $lang = LangFactory::get(); $this->assertEquals('en', $lang->getLang()); } - public function testGetThrowsIfNoDefaultConfigured(): void + public function testLangFactoryThrowsErrorIfNoDefaultLangFound() { + config()->set('lang', [ + 'enabled' => true, + 'default' => null, + 'supported' => ['en', 'es'], + 'url_segment' => 1 + ]); + + $this->testRequest('http://127.0.0.1/fr/api/rest'); + $this->expectException(LangException::class); - config()->set('lang.default', null); + $this->expectExceptionMessage('Misconfigured lang default config'); LangFactory::get(); } diff --git a/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php b/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php index 17d9efc21..00709e21b 100644 --- a/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php +++ b/tests/Unit/Libraries/Lang/Helpers/LangHelperFunctionsTest.php @@ -14,12 +14,14 @@ public function setUp(): void { parent::setUp(); + $this->setPrivateProperty(LangFactory::class, 'instance', null); + $this->lang = LangFactory::get(); $this->lang->load(); } - public function testCurrentLang() + public function testLangHelperCurrentLang() { $this->assertEquals('en', current_lang()); @@ -28,14 +30,14 @@ public function testCurrentLang() $this->assertEquals('am', current_lang()); } - public function testHelperT() + public function testLangHelperT() { $this->assertEquals('Testing', t('custom.test')); $this->assertEquals('Information about the new feature', t('custom.info', ['new'])); } - public function testHelperUnderscoreT() + public function testLangHelperUnderscoreT() { ob_start(); @@ -46,7 +48,7 @@ public function testHelperUnderscoreT() $this->assertEquals('Testing', $output); } - public function testHelperTFail() + public function testLangHelperTFail() { $this->assertEquals('custom.non_existing_key', t('custom.non_existing_key')); } diff --git a/tests/_root/modules/Test/resources/lang/es/custom.php b/tests/_root/modules/Test/resources/lang/es/custom.php new file mode 100644 index 000000000..80ef6b057 --- /dev/null +++ b/tests/_root/modules/Test/resources/lang/es/custom.php @@ -0,0 +1,7 @@ + 'Aprender más', + 'info' => 'Información sobre la función {%1}', + 'test' => 'Prueba' +]; \ No newline at end of file diff --git a/tests/_root/shared/config/lang.php b/tests/_root/shared/config/lang.php index abd9dc007..56835fb06 100644 --- a/tests/_root/shared/config/lang.php +++ b/tests/_root/shared/config/lang.php @@ -7,7 +7,7 @@ * --------------------------------------------------------- */ 'enabled' => true, - 'supported' => ['en', 'ru', 'am'], + 'supported' => ['en', 'es'], 'default' => 'en', 'url_segment' => 1, ]; \ No newline at end of file diff --git a/tests/_root/shared/resources/lang/es/custom.php b/tests/_root/shared/resources/lang/es/custom.php new file mode 100644 index 000000000..80ef6b057 --- /dev/null +++ b/tests/_root/shared/resources/lang/es/custom.php @@ -0,0 +1,7 @@ + 'Aprender más', + 'info' => 'Información sobre la función {%1}', + 'test' => 'Prueba' +]; \ No newline at end of file