From 3d5da057b89b46875bd8deaaf2fb1835f37f40a7 Mon Sep 17 00:00:00 2001 From: gseric Date: Wed, 16 Mar 2022 23:53:40 +0100 Subject: [PATCH 1/5] [Locale] Change language negotiation from simple string comparison to RFC 4647 based --- docs/book/api/translations.rst | 7 +++++- .../RequestHeaderBasedLocaleContext.php | 25 +++++++++++++------ .../RequestHeaderBasedLocaleContextSpec.php | 25 ++++++------------- tests/Api/Shop/ProductsTest.php | 2 +- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/docs/book/api/translations.rst b/docs/book/api/translations.rst index 1b8e0c14fc..682bf8044d 100644 --- a/docs/book/api/translations.rst +++ b/docs/book/api/translations.rst @@ -2,8 +2,13 @@ Translations ============ In the shop part of our API translatable entities are translated at the server-side and users get an already translated field in the response. -By default it will be provided in default locale configured on the channel, different locale must be configured in the header (for example `accept-language: de_DE`) +By default it will be provided in default locale configured on the channel, different locale must be configured in the header (e.g. `Accept-Language: de-DE`) .. warning:: Remember that the chosen locale has to be enabled in the channel! + +.. note:: + + Though Sylius' locale code format (e.g. `de_DE`) will also be accepted in `Accept-Language` header, it's not valid value according to HTTP specification. + Also, it silently changes CORS behavior - results with CORS restrictions because the "_" character is not considered safe for this header type (https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header). diff --git a/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php b/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php index eb7060af57..4ebaef9aa2 100644 --- a/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php +++ b/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php @@ -18,6 +18,11 @@ use Sylius\Component\Locale\Context\LocaleNotFoundException; use Sylius\Component\Locale\Provider\LocaleProviderInterface; use Symfony\Component\HttpFoundation\RequestStack; +/** + * Locale context implementation based on Symfony Request's language negotiation (RFC 4647 based). + * + * @see Request::getPreferredLanguage() + */ final class RequestHeaderBasedLocaleContext implements LocaleContextInterface { public function __construct(private RequestStack $requestStack, private LocaleProviderInterface $localeProvider) @@ -31,16 +36,20 @@ final class RequestHeaderBasedLocaleContext implements LocaleContextInterface throw new LocaleNotFoundException('No main request available.'); } - $localeCode = $request->headers->get('Accept-Language'); - if (null === $localeCode) { - throw new LocaleNotFoundException('No locale is set on the master request\'s headers.'); - } - $availableLocalesCodes = $this->localeProvider->getAvailableLocalesCodes(); - if (!in_array($localeCode, $availableLocalesCodes, true)) { - throw LocaleNotFoundException::notAvailable($localeCode, $availableLocalesCodes); + + // Request::getPreferredLanguage() returns first available locale code if none matches. To allow detection of + // this unwanted behavior, we will prepend special locale code to the list of available locale codes. + $prependedAvailableLocalesCodes = array_merge(['FIRSTLOCALECODE'], $availableLocalesCodes); + + $bestLocaleCode = $request->getPreferredLanguage($prependedAvailableLocalesCodes); + if ('FIRSTLOCALECODE' === $bestLocaleCode) { + throw new LocaleNotFoundException(sprintf( + 'None of the available locales is acceptable: "%s".', + implode('", "', $availableLocalesCodes), + )); } - return $localeCode; + return $bestLocaleCode; } } diff --git a/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php b/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php index 85a99401a2..2c064d6520 100644 --- a/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php +++ b/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php @@ -40,42 +40,31 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $this->shouldThrow(LocaleNotFoundException::class)->during('getLocaleCode'); } - function it_throws_locale_not_found_exception_if_main_request_does_not_have_accept_language_in_header( - RequestStack $requestStack, - Request $request, - ): void { - $requestStack->getMainRequest()->willReturn($request); - - $request->headers = new HeaderBag(); - - $this->shouldThrow(LocaleNotFoundException::class)->during('getLocaleCode'); - } - - function it_throws_locale_not_found_exception_if_main_request_locale_code_is_not_among_available_ones( + function it_throws_locale_not_found_exception_if_main_request_preferred_language_is_default_locale( RequestStack $requestStack, LocaleProviderInterface $localeProvider, Request $request, ): void { $requestStack->getMainRequest()->willReturn($request); - $request->headers = new HeaderBag(['ACCEPT_LANGUAGE' => 'en_US']); - $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); + $request->getPreferredLanguage(['FIRSTLOCALECODE', 'pl_PL', 'de_DE'])->willReturn('FIRSTLOCALECODE'); + $this->shouldThrow(LocaleNotFoundException::class)->during('getLocaleCode'); } - function it_returns_main_request_locale_code( + function it_returns_main_request_preferred_language( RequestStack $requestStack, LocaleProviderInterface $localeProvider, Request $request, ): void { $requestStack->getMainRequest()->willReturn($request); - $request->headers = new HeaderBag(['Accept-Language' => 'pl_PL']); - $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); - $this->getLocaleCode()->shouldReturn('pl_PL'); + $request->getPreferredLanguage(['FIRSTLOCALECODE', 'pl_PL', 'de_DE'])->willReturn('de_DE'); + + $this->getLocaleCode()->shouldReturn('de_DE'); } } diff --git a/tests/Api/Shop/ProductsTest.php b/tests/Api/Shop/ProductsTest.php index 7b1913cfc4..cd4bbe5671 100644 --- a/tests/Api/Shop/ProductsTest.php +++ b/tests/Api/Shop/ProductsTest.php @@ -65,7 +65,7 @@ final class ProductsTest extends JsonApiTestCase sprintf('/api/v2/shop/products/%s', $product->getCode()), [], [], - ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json', 'HTTP_ACCEPT_LANGUAGE' => 'de_DE'] + ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json', 'HTTP_ACCEPT_LANGUAGE' => 'de-DE'] ); $this->assertResponse( From e002d791d9f3cfff9bdbebf9016c5e1564c728ab Mon Sep 17 00:00:00 2001 From: Jan Goralski Date: Thu, 21 Dec 2023 18:08:40 +0100 Subject: [PATCH 2/5] [Locale] Add some more tests for header languange negotiation --- UPGRADE-1.12.md | 5 ++ .../RequestHeaderBasedLocaleContext.php | 6 +- .../RequestHeaderBasedLocaleContextSpec.php | 57 ++++++++++++++++--- tests/Api/Shop/ProductsTest.php | 37 +++++++++--- 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/UPGRADE-1.12.md b/UPGRADE-1.12.md index a6c52c1501..1091024142 100644 --- a/UPGRADE-1.12.md +++ b/UPGRADE-1.12.md @@ -1,3 +1,8 @@ +# UPGRADING FROM `v1.12.13` TO `v1.12.14` + +1. The `Accept-Language` header should now correctly resolve locale codes based on RFC 4647 using Symfony's request language negotiation, + meaning that values `en_US`, `en-US`, `en-us` etc. will all result in the `en_US` locale. + # UPGRADE FROM `v1.12.11` TO `v1.12.12` 1. The `Sylius\Component\User\Model\UserInterface` extends the `Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface` diff --git a/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php b/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php index 4ebaef9aa2..80bf3aa759 100644 --- a/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php +++ b/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php @@ -25,6 +25,8 @@ use Symfony\Component\HttpFoundation\RequestStack; */ final class RequestHeaderBasedLocaleContext implements LocaleContextInterface { + private const NO_CODE_VALID_STUB = 'NO_CODE_VALID_STUB'; + public function __construct(private RequestStack $requestStack, private LocaleProviderInterface $localeProvider) { } @@ -40,10 +42,10 @@ final class RequestHeaderBasedLocaleContext implements LocaleContextInterface // Request::getPreferredLanguage() returns first available locale code if none matches. To allow detection of // this unwanted behavior, we will prepend special locale code to the list of available locale codes. - $prependedAvailableLocalesCodes = array_merge(['FIRSTLOCALECODE'], $availableLocalesCodes); + $prependedAvailableLocalesCodes = array_merge([self::NO_CODE_VALID_STUB], $availableLocalesCodes); $bestLocaleCode = $request->getPreferredLanguage($prependedAvailableLocalesCodes); - if ('FIRSTLOCALECODE' === $bestLocaleCode) { + if (self::NO_CODE_VALID_STUB === $bestLocaleCode) { throw new LocaleNotFoundException(sprintf( 'None of the available locales is acceptable: "%s".', implode('", "', $availableLocalesCodes), diff --git a/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php b/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php index 2c064d6520..e496416de0 100644 --- a/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php +++ b/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php @@ -17,7 +17,6 @@ use PhpSpec\ObjectBehavior; use Sylius\Component\Locale\Context\LocaleContextInterface; use Sylius\Component\Locale\Context\LocaleNotFoundException; use Sylius\Component\Locale\Provider\LocaleProviderInterface; -use Symfony\Component\HttpFoundation\HeaderBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -40,30 +39,72 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $this->shouldThrow(LocaleNotFoundException::class)->during('getLocaleCode'); } - function it_throws_locale_not_found_exception_if_main_request_preferred_language_is_default_locale( + function it_throws_locale_not_found_exception_if_locale_from_main_request_preferred_language_cannot_be_resolved( RequestStack $requestStack, LocaleProviderInterface $localeProvider, - Request $request, ): void { + $request = new Request(); + $request->headers->set('Accept-Language', 'fr_FR'); + $requestStack->getMainRequest()->willReturn($request); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); - $request->getPreferredLanguage(['FIRSTLOCALECODE', 'pl_PL', 'de_DE'])->willReturn('FIRSTLOCALECODE'); - $this->shouldThrow(LocaleNotFoundException::class)->during('getLocaleCode'); } - function it_returns_main_request_preferred_language( + function it_resolves_locale_from_main_request_preferred_language_in_locale_syntax( RequestStack $requestStack, LocaleProviderInterface $localeProvider, - Request $request, ): void { + $request = new Request(); + $request->headers->set('Accept-Language', 'de_DE'); + $requestStack->getMainRequest()->willReturn($request); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); - $request->getPreferredLanguage(['FIRSTLOCALECODE', 'pl_PL', 'de_DE'])->willReturn('de_DE'); + $this->getLocaleCode()->shouldReturn('de_DE'); + } + + function it_resolves_locale_from_main_request_preferred_language_in_mixed_cased_language_syntax( + RequestStack $requestStack, + LocaleProviderInterface $localeProvider, + ): void { + $request = new Request(); + $request->headers->set('Accept-Language', 'dE-De'); + + $requestStack->getMainRequest()->willReturn($request); + + $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); + + $this->getLocaleCode()->shouldReturn('de_DE'); + } + + function it_resolves_locale_from_main_request_preferred_language_in_upper_cased_language_syntax( + RequestStack $requestStack, + LocaleProviderInterface $localeProvider, + ): void { + $request = new Request(); + $request->headers->set('Accept-Language', 'DE-DE'); + + $requestStack->getMainRequest()->willReturn($request); + + $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); + + $this->getLocaleCode()->shouldReturn('de_DE'); + } + + function it_resolves_locale_from_main_request_preferred_language_in_lower_cased_language_syntax( + RequestStack $requestStack, + LocaleProviderInterface $localeProvider, + ): void { + $request = new Request(); + $request->headers->set('Accept-Language', 'de-de'); + + $requestStack->getMainRequest()->willReturn($request); + + $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); $this->getLocaleCode()->shouldReturn('de_DE'); } diff --git a/tests/Api/Shop/ProductsTest.php b/tests/Api/Shop/ProductsTest.php index cd4bbe5671..c9c6b3f8cd 100644 --- a/tests/Api/Shop/ProductsTest.php +++ b/tests/Api/Shop/ProductsTest.php @@ -53,8 +53,11 @@ final class ProductsTest extends JsonApiTestCase ); } - /** @test */ - public function it_returns_product_with_translations_in_locale_from_header(): void + /** + * @test + * @dataProvider getGermanLocales + */ + public function it_returns_product_with_translations_in_locale_from_header(string $germanLocale): void { $fixtures = $this->loadFixturesFromFile('product/product_with_many_locales.yaml'); @@ -65,7 +68,7 @@ final class ProductsTest extends JsonApiTestCase sprintf('/api/v2/shop/products/%s', $product->getCode()), [], [], - ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json', 'HTTP_ACCEPT_LANGUAGE' => 'de-DE'] + ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json', 'HTTP_ACCEPT_LANGUAGE' => $germanLocale] ); $this->assertResponse( @@ -95,9 +98,13 @@ final class ProductsTest extends JsonApiTestCase ); } - /** @test */ - public function it_returns_product_attributes_collection_with_translations_in_locale_from_header(): void - { + /** + * @test + * @dataProvider getPolishLocales + */ + public function it_returns_product_attributes_collection_with_translations_in_locale_from_header( + string $polishLocale, + ): void { $this->loadFixturesFromFiles(['channel.yaml', 'product/product_attribute.yaml']); $this->client->request( @@ -105,7 +112,7 @@ final class ProductsTest extends JsonApiTestCase sprintf('/api/v2/shop/products/%s/attributes', 'MUG_SW'), [], [], - array_merge(self::CONTENT_TYPE_HEADER, ['HTTP_ACCEPT_LANGUAGE' => 'pl_PL']) + array_merge(self::CONTENT_TYPE_HEADER, ['HTTP_ACCEPT_LANGUAGE' => $polishLocale]) ); $this->assertResponse( @@ -129,4 +136,20 @@ final class ProductsTest extends JsonApiTestCase $this->assertCount(2, json_decode($this->client->getResponse()->getContent(), true)['hydra:member']); } + + public function getGermanLocales(): iterable + { + yield ['de_DE']; // Locale code syntax + yield ['de-DE']; // RFC 4647 and RFC 3066 + yield ['DE-DE']; // RFC 4647 and RFC 3066 + yield ['de-de']; // RFC 4647 and RFC 3066 + } + + public function getPolishLocales(): iterable + { + yield ['pl_PL']; // Locale code syntax + yield ['pl-PL']; // RFC 4647 and RFC 3066 + yield ['PL-PL']; // RFC 4647 and RFC 3066 + yield ['pl-pl']; // RFC 4647 and RFC 3066 + } } From d896de175d3a458ece3dbb92e66d6384e97fbb4e Mon Sep 17 00:00:00 2001 From: Jan Goralski Date: Fri, 22 Dec 2023 09:11:03 +0100 Subject: [PATCH 3/5] [Unit] Fix JsonApiTestCase constructor arguments --- tests/Api/JsonApiTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Api/JsonApiTestCase.php b/tests/Api/JsonApiTestCase.php index 4b60184e1b..6ede32bdd5 100644 --- a/tests/Api/JsonApiTestCase.php +++ b/tests/Api/JsonApiTestCase.php @@ -19,7 +19,7 @@ abstract class JsonApiTestCase extends BaseJsonApiTestCase { public const CONTENT_TYPE_HEADER = ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json']; - public function __construct(?string $name = null, array $data = [], string $dataName = '') + public function __construct(?string $name = null, array $data = [], int|string $dataName = '') { parent::__construct($name, $data, $dataName); From 02c9b7428b8a06f8f6dd48eb84108241505959f1 Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Fri, 22 Dec 2023 09:51:48 +0100 Subject: [PATCH 4/5] Typo cart-flow.rst --- docs/book/orders/cart-flow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/orders/cart-flow.rst b/docs/book/orders/cart-flow.rst index 5201b33e52..d2024b9a6f 100644 --- a/docs/book/orders/cart-flow.rst +++ b/docs/book/orders/cart-flow.rst @@ -47,7 +47,7 @@ Third scenario:: Then the cart should be empty .. note:: - The cart mentioned in the last scenario will we available once you log in again. + The cart mentioned in the last scenario will be available once you log in again. Learn more ---------- From 0ceb7db6971e70764cb1798b07edc4d80817585c Mon Sep 17 00:00:00 2001 From: Jan Goralski Date: Fri, 22 Dec 2023 11:26:31 +0100 Subject: [PATCH 5/5] [Behat][API] Allow setting no accept-language in header [Locale] Prepend default channel locale when resolving by header --- ..._with_the_locale_other_than_the_default.feature | 2 +- src/Sylius/Behat/Context/Api/Shop/CartContext.php | 4 +++- .../Context/RequestHeaderBasedLocaleContext.php | 14 +++++++++++--- .../RequestHeaderBasedLocaleContextSpec.php | 5 +++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/features/checkout/picking_up_the_cart_with_the_locale_other_than_the_default.feature b/features/checkout/picking_up_the_cart_with_the_locale_other_than_the_default.feature index 860e44badd..a1dbe0b743 100644 --- a/features/checkout/picking_up_the_cart_with_the_locale_other_than_the_default.feature +++ b/features/checkout/picking_up_the_cart_with_the_locale_other_than_the_default.feature @@ -18,7 +18,7 @@ Feature: Picking up the cart with the locale other than the default @api Scenario: Picking up the cart without specified locale - When I pick up cart + When I pick up cart without specifying locale And I check details of my cart Then my cart's locale should be "French (France)" diff --git a/src/Sylius/Behat/Context/Api/Shop/CartContext.php b/src/Sylius/Behat/Context/Api/Shop/CartContext.php index 7e2ede3a96..cf4f9196ef 100644 --- a/src/Sylius/Behat/Context/Api/Shop/CartContext.php +++ b/src/Sylius/Behat/Context/Api/Shop/CartContext.php @@ -218,6 +218,7 @@ final class CartContext implements Context /** * @When I pick up (my )cart (again) * @When I pick up cart in the :localeCode locale + * @When I pick up cart without specifying locale * @When the visitor picks up the cart */ public function iPickUpMyCart(?string $localeCode = null): void @@ -776,8 +777,9 @@ final class CartContext implements Context $request = $this->requestFactory->custom( sprintf('%s/shop/orders', $this->apiUrlPrefix), HttpRequest::METHOD_POST, - $localeCode ? ['HTTP_ACCEPT_LANGUAGE' => $localeCode] : [], + ['HTTP_ACCEPT_LANGUAGE' => $localeCode ?? ''], ); + $this->shopClient->executeCustomRequest($request); $tokenValue = $this->responseChecker->getValue($this->shopClient->getLastResponse(), 'tokenValue'); diff --git a/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php b/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php index 80bf3aa759..3b4a7d8803 100644 --- a/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php +++ b/src/Sylius/Bundle/LocaleBundle/Context/RequestHeaderBasedLocaleContext.php @@ -27,6 +27,9 @@ final class RequestHeaderBasedLocaleContext implements LocaleContextInterface { private const NO_CODE_VALID_STUB = 'NO_CODE_VALID_STUB'; + /** @var array $availableLocalesCodes */ + private array $availableLocalesCodes = []; + public function __construct(private RequestStack $requestStack, private LocaleProviderInterface $localeProvider) { } @@ -38,17 +41,22 @@ final class RequestHeaderBasedLocaleContext implements LocaleContextInterface throw new LocaleNotFoundException('No main request available.'); } - $availableLocalesCodes = $this->localeProvider->getAvailableLocalesCodes(); + if ([] === $this->availableLocalesCodes) { + $this->availableLocalesCodes = array_unique(array_merge( + [$this->localeProvider->getDefaultLocaleCode()], + $this->localeProvider->getAvailableLocalesCodes() + )); + } // Request::getPreferredLanguage() returns first available locale code if none matches. To allow detection of // this unwanted behavior, we will prepend special locale code to the list of available locale codes. - $prependedAvailableLocalesCodes = array_merge([self::NO_CODE_VALID_STUB], $availableLocalesCodes); + $prependedAvailableLocalesCodes = array_merge([self::NO_CODE_VALID_STUB], $this->availableLocalesCodes); $bestLocaleCode = $request->getPreferredLanguage($prependedAvailableLocalesCodes); if (self::NO_CODE_VALID_STUB === $bestLocaleCode) { throw new LocaleNotFoundException(sprintf( 'None of the available locales is acceptable: "%s".', - implode('", "', $availableLocalesCodes), + implode('", "', $this->availableLocalesCodes), )); } diff --git a/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php b/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php index e496416de0..9bfdbf3425 100644 --- a/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php +++ b/src/Sylius/Bundle/LocaleBundle/spec/Context/RequestHeaderBasedLocaleContextSpec.php @@ -48,6 +48,7 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $requestStack->getMainRequest()->willReturn($request); + $localeProvider->getDefaultLocaleCode()->willReturn('pl_PL'); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); $this->shouldThrow(LocaleNotFoundException::class)->during('getLocaleCode'); @@ -62,6 +63,7 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $requestStack->getMainRequest()->willReturn($request); + $localeProvider->getDefaultLocaleCode()->willReturn('pl_PL'); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); $this->getLocaleCode()->shouldReturn('de_DE'); @@ -76,6 +78,7 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $requestStack->getMainRequest()->willReturn($request); + $localeProvider->getDefaultLocaleCode()->willReturn('pl_PL'); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); $this->getLocaleCode()->shouldReturn('de_DE'); @@ -90,6 +93,7 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $requestStack->getMainRequest()->willReturn($request); + $localeProvider->getDefaultLocaleCode()->willReturn('pl_PL'); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); $this->getLocaleCode()->shouldReturn('de_DE'); @@ -104,6 +108,7 @@ final class RequestHeaderBasedLocaleContextSpec extends ObjectBehavior $requestStack->getMainRequest()->willReturn($request); + $localeProvider->getDefaultLocaleCode()->willReturn('pl_PL'); $localeProvider->getAvailableLocalesCodes()->willReturn(['pl_PL', 'de_DE']); $this->getLocaleCode()->shouldReturn('de_DE');