From 8fa8663583afffcfed806e78fb04dc57de46efba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Parafi=C5=84ski?= Date: Fri, 21 Dec 2018 13:10:25 +0100 Subject: [PATCH] EZP-29932: As a Developer I want list of Languages based on User's browser settings (#2507) * EZP-29932: As a Developer I want list of Languages based on User's browser settings * EZP-29932: proper kernel docblocks * EZP-29925: Extract UserLanguagePreferenceProviderInterface * EZP-29932: Add fallback for getName and getDescription when mainLanguageCode is not provided --- .../Resources/config/locale.yml | 46 ++++++++++ .../UserLanguagePreferenceProviderTest.php | 89 +++++++++++++++++++ .../Locale/UserLanguagePreferenceProvider.php | 70 +++++++++++++++ ...serLanguagePreferenceProviderInterface.php | 33 +++++++ .../Values/MultiLanguageDescriptionTrait.php | 4 +- .../Values/MultiLanguageNameTrait.php | 4 +- 6 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 eZ/Publish/Core/MVC/Symfony/Locale/Tests/UserLanguagePreferenceProviderTest.php create mode 100644 eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProvider.php create mode 100644 eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProviderInterface.php diff --git a/eZ/Bundle/EzPublishCoreBundle/Resources/config/locale.yml b/eZ/Bundle/EzPublishCoreBundle/Resources/config/locale.yml index 85e3bb34614..4d1a4f22095 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Resources/config/locale.yml +++ b/eZ/Bundle/EzPublishCoreBundle/Resources/config/locale.yml @@ -44,6 +44,47 @@ parameters: tur-TR: tr_TR ukr-UA: uk_UA + ezpublish.locale.browser_map: + au: ['eng-AU'] + be: ['fre-BE'] + br: ['por-BR'] + ca: ['eng-CA'] + cn: ['chi-CN'] + cz: ['cze-CZ'] + de: ['ger-DE'] + dk: ['dan-DK'] + en: ['eng-GB', 'eng-US'] + en-us: ['eng-US'] + es: ['esl-ES'] + fi: ['fin-FI'] + fr: ['fre-FR'] + gb: ['eng-GB'] + gr: ['ell-GR'] + hk: ['chi-HK'] + hr: ['cro-HR'] + hu: ['hun-HU'] + id: ['ind-ID'] + il: ['heb-IL'] + in: ['hin-IN'] + it: ['ita-IT'] + jp: ['jpn-JP'] + kr: ['kor-KR'] + mx: ['esl-MX'] + mz: ['por-MZ'] + nl: ['dut-NL'] + no: ['nor-NO'] + nz: ['eng-NZ'] + pl: ['pol-PL'] + pt: ['por-PT'] + rs: ['srp-RS'] + ru: ['rus-RU'] + sa: ['ara-SA'] + se: ['swe-SE'] + sk: ['slk-SK'] + tr: ['tur-TR'] + tw: ['chi-TW'] + ua: ['ukr-UA'] + ezpublish.locale.converter.class: eZ\Publish\Core\MVC\Symfony\Locale\LocaleConverter services: @@ -57,3 +98,8 @@ services: arguments: ["@request_stack", "%kernel.default_locale%", "@?router"] tags: - { name: kernel.event_subscriber } + + eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProvider: + autowire: true + arguments: + $languageCodesMap: '%ezpublish.locale.browser_map%' diff --git a/eZ/Publish/Core/MVC/Symfony/Locale/Tests/UserLanguagePreferenceProviderTest.php b/eZ/Publish/Core/MVC/Symfony/Locale/Tests/UserLanguagePreferenceProviderTest.php new file mode 100644 index 00000000000..e8e48a4d0e9 --- /dev/null +++ b/eZ/Publish/Core/MVC/Symfony/Locale/Tests/UserLanguagePreferenceProviderTest.php @@ -0,0 +1,89 @@ +requestStackMock = $this->createMock(RequestStack::class); + + $this->userLanguagePreferenceProvider = new UserLanguagePreferenceProvider( + $this->requestStackMock, + $this->getLanguageCodesMap() + ); + } + + /** + * @dataProvider providerForTestGetPreferredLanguages + * + * @param array $userLanguages + * @param array $expectedEzLanguageCodes + */ + public function testGetPreferredLanguages(array $userLanguages, array $expectedEzLanguageCodes) + { + $request = new Request(); + $request->headers = new HeaderBag( + [ + 'Accept-Language' => implode(', ', $userLanguages), + ] + ); + $this + ->requestStackMock + ->expects($this->once()) + ->method('getCurrentRequest') + ->willReturn($request); + + self::assertEquals( + $expectedEzLanguageCodes, + $this->userLanguagePreferenceProvider->getPreferredLanguages() + ); + } + + /** + * @see testGetPreferredLanguages + * + * @return array + */ + public function providerForTestGetPreferredLanguages(): array + { + return [ + [['pl'], ['pol-PL']], + [['pol-PL'], ['pol-PL']], + [['fr'], ['fre-FR']], + [['en'], ['eng-GB', 'eng-US']], + ]; + } + + private function getLanguageCodesMap(): array + { + $config = Yaml::parseFile( + realpath(dirname(__DIR__, 6) . '/Bundle/EzPublishCoreBundle/Resources/config/locale.yml') + ); + + return $config['parameters']['ezpublish.locale.browser_map']; + } +} diff --git a/eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProvider.php b/eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProvider.php new file mode 100644 index 00000000000..dfaa717fab1 --- /dev/null +++ b/eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProvider.php @@ -0,0 +1,70 @@ +requestStack = $requestStack; + $this->languageCodesMap = $languageCodesMap; + } + + public function getPreferredLocales(Request $request = null): array + { + $request = $request ?? $this->requestStack->getCurrentRequest(); + $preferredLocales = $request->headers->get('Accept-Language') ?? ''; + $preferredLocales = array_reduce( + explode(',', $preferredLocales), + function (array $result, string $languageWithQuality) { + [$language, $quality] = array_merge(explode(';q=', $languageWithQuality), [1]); + $result[$language] = (float) $quality; + + return $result; + }, + [] + ); + arsort($preferredLocales); + + return array_keys($preferredLocales); + } + + public function getPreferredLanguages(): array + { + $languageCodes = []; + foreach ($this->getPreferredLocales() as $locale) { + $locale = strtolower($locale); + if (isset($this->languageCodesMap[$locale])) { + $languageCodes = array_merge($languageCodes, $this->languageCodesMap[$locale]); + } elseif (preg_match('/^([a-z]{3})-([a-z]{2})$/', $locale, $matches)) { + // if the given locale is already in the eZ format + $languageCodes[] = strtolower($matches[1]) . '-' . strtoupper($matches[2]); + } + } + + return array_unique($languageCodes); + } +} diff --git a/eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProviderInterface.php b/eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProviderInterface.php new file mode 100644 index 00000000000..a7a0d919498 --- /dev/null +++ b/eZ/Publish/Core/MVC/Symfony/Locale/UserLanguagePreferenceProviderInterface.php @@ -0,0 +1,33 @@ +descriptions[$this->mainLanguageCode]; + return isset($this->descriptions[$this->mainLanguageCode]) + ? $this->descriptions[$this->mainLanguageCode] + : reset($this->descriptions); } } diff --git a/eZ/Publish/Core/Repository/Values/MultiLanguageNameTrait.php b/eZ/Publish/Core/Repository/Values/MultiLanguageNameTrait.php index cbc96947c34..ef88d48734e 100644 --- a/eZ/Publish/Core/Repository/Values/MultiLanguageNameTrait.php +++ b/eZ/Publish/Core/Repository/Values/MultiLanguageNameTrait.php @@ -43,6 +43,8 @@ public function getName($languageCode = null) } } - return $this->names[$this->mainLanguageCode]; + return isset($this->names[$this->mainLanguageCode]) + ? $this->names[$this->mainLanguageCode] + : reset($this->names); } }