diff --git a/src/I18n/Middleware/LocaleSelectorMiddleware.php b/src/I18n/Middleware/LocaleSelectorMiddleware.php new file mode 100644 index 00000000000..f9a80be41cf --- /dev/null +++ b/src/I18n/Middleware/LocaleSelectorMiddleware.php @@ -0,0 +1,61 @@ +locales = $locales; + } + + /** + * @param ServerRequestInterface $request The request. + * @param ResponseInterface $response The response. + * @param callable $next The next middleware to call + * @return \Psr\Http\Message\ResponseInterface A response + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next) + { + $locale = Locale::acceptFromHttp($request->getHeaderLine('Accept-Language')); + + if ($locale && (in_array($locale, $this->locales) || $this->locales === ['*'])) { + I18n::locale($locale); + } + return $next($request, $response); + } +} diff --git a/tests/TestCase/I18n/Middleware/LocaleSelectorMiddlewareTest.php b/tests/TestCase/I18n/Middleware/LocaleSelectorMiddlewareTest.php new file mode 100644 index 00000000000..c4f2563ef20 --- /dev/null +++ b/tests/TestCase/I18n/Middleware/LocaleSelectorMiddlewareTest.php @@ -0,0 +1,116 @@ +locale = Locale::getDefault(); + $this->next = function ($req, $res) { + return $res; + }; + } + + /** + * Resets the default locale + * + * @return void + */ + public function tearDown() + { + parent::tearDown(); + Locale::setDefault($this->locale); + } + + /** + * The default locale should not change when there are no accepted + * locales. + * + * @return void + */ + public function testInvokeNoAcceptedLocales() + { + $request = ServerRequestFactory::fromGlobals(); + $response = new Response(); + $middleware = new LocaleSelectorMiddleware([]); + $middleware($request, $response, $this->next); + $this->assertSame($this->locale, I18n::locale()); + } + + /** + * The default locale should not change when the request locale is not accepted + * + * @return void + */ + public function testInvokeLocaleNotAccepted() + { + $request = ServerRequestFactory::fromGlobals(['HTTP_ACCEPT_LANGUAGE' => 'en-GB,en;q=0.8,es;q=0.6,da;q=0.4']); + $response = new Response(); + $middleware = new LocaleSelectorMiddleware(['en_CA', 'en_US', 'es']); + $middleware($request, $response, $this->next); + $this->assertSame($this->locale, I18n::locale(), 'en-GB is not accepted'); + } + + /** + * The default locale should change when the request locale is accepted + * + * @return void + */ + public function testInvokeLocaleAccepted() + { + $request = ServerRequestFactory::fromGlobals(['HTTP_ACCEPT_LANGUAGE' => 'es,es-ES;q=0.8,da;q=0.4']); + $response = new Response(); + $middleware = new LocaleSelectorMiddleware(['en_CA', 'es']); + $middleware($request, $response, $this->next); + $this->assertSame('es', I18n::locale(), 'es is accepted'); + } + + /** + * The default locale should change when the '*' is accepted + * + * @return void + */ + public function testInvokeLocaleAcceptAll() + { + $response = new Response(); + $middleware = new LocaleSelectorMiddleware(['*']); + + $request = ServerRequestFactory::fromGlobals(['HTTP_ACCEPT_LANGUAGE' => 'es,es-ES;q=0.8,da;q=0.4']); + $middleware($request, $response, $this->next); + $this->assertSame('es', I18n::locale(), 'es is accepted'); + + $request = ServerRequestFactory::fromGlobals(['HTTP_ACCEPT_LANGUAGE' => 'en;q=0.4,es;q=0.6,da;q=0.8']); + $middleware($request, $response, $this->next); + $this->assertSame('da', I18n::locale(), 'da is accepted'); + } +}