Skip to content

Commit

Permalink
EZP-29961: Add preferred language value to User Preferences (ezsystem…
Browse files Browse the repository at this point in the history
  • Loading branch information
mikadamczyk authored and Łukasz Serwatka committed Feb 7, 2019
1 parent f5fa172 commit 2365bec
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 26 deletions.
3 changes: 2 additions & 1 deletion eZ/Bundle/EzPublishCoreBundle/Resources/config/locale.yml
Expand Up @@ -54,7 +54,7 @@ parameters:
de: ['ger-DE']
dk: ['dan-DK']
en: ['eng-GB', 'eng-US']
en-us: ['eng-US']
en_us: ['eng-US']
es: ['esl-ES']
fi: ['fin-FI']
fr: ['fre-FR']
Expand Down Expand Up @@ -103,3 +103,4 @@ services:
autowire: true
arguments:
$languageCodesMap: '%ezpublish.locale.browser_map%'
$localeFallback: '%locale_fallback%'
Expand Up @@ -14,9 +14,16 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Yaml\Yaml;
use eZ\Publish\API\Repository\UserPreferenceService;
use eZ\Publish\API\Repository\Values\UserPreference\UserPreference;
use eZ\Publish\Core\Base\Exceptions\NotFoundException;

class UserLanguagePreferenceProviderTest extends TestCase
{
private const LOCALE_FALLBACK = 'en';
private const LANGUAGE_PREFERENCE_NAME = 'language';
private const LANGUAGE_PREFERENCE_VALUE = 'no';

/**
* @var \eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface
*/
Expand All @@ -27,13 +34,31 @@ class UserLanguagePreferenceProviderTest extends TestCase
*/
private $requestStackMock;

/**
* @var \eZ\Publish\API\Repository\UserPreferenceService
*/
private $userPreferenceServiceMock;

public function setUp()
{
$this->requestStackMock = $this->createMock(RequestStack::class);

$userLanguagePreference = new UserPreference([
'name' => self::LANGUAGE_PREFERENCE_NAME,
'value' => self::LANGUAGE_PREFERENCE_VALUE,
]);

$this->userPreferenceServiceMock = $this->createMock(UserPreferenceService::class);
$this->userPreferenceServiceMock
->method('getUserPreference')
->with(self::LANGUAGE_PREFERENCE_NAME)
->willReturn($userLanguagePreference);

$this->userLanguagePreferenceProvider = new UserLanguagePreferenceProvider(
$this->requestStackMock,
$this->getLanguageCodesMap()
$this->userPreferenceServiceMock,
$this->getLanguageCodesMap(),
self::LOCALE_FALLBACK
);
}

Expand All @@ -43,7 +68,46 @@ public function setUp()
* @param array $userLanguages
* @param array $expectedEzLanguageCodes
*/
public function testGetPreferredLanguages(array $userLanguages, array $expectedEzLanguageCodes)
public function testGetPreferredLanguagesWithoutUserLanguage(array $userLanguages, array $expectedEzLanguageCodes): void
{
$request = new Request();
$request->headers = new HeaderBag(
[
'Accept-Language' => implode(', ', $userLanguages),
]
);
$this
->requestStackMock
->expects($this->once())
->method('getCurrentRequest')
->willReturn($request);

$userPreferenceServiceMock = $this->createMock(UserPreferenceService::class);
$userPreferenceServiceMock
->method('getUserPreference')
->with(self::LANGUAGE_PREFERENCE_NAME)
->will($this->throwException(new NotFoundException('User Preference', self::LANGUAGE_PREFERENCE_NAME)));

$userLanguagePreferenceProvider = new UserLanguagePreferenceProvider(
$this->requestStackMock,
$userPreferenceServiceMock,
$this->getLanguageCodesMap(),
self::LOCALE_FALLBACK
);

self::assertEquals(
$expectedEzLanguageCodes,
$userLanguagePreferenceProvider->getPreferredLanguages()
);
}

/**
* @dataProvider providerForTestGetPreferredLanguagesWithUserPreferredLanguage
*
* @param array $userLanguages
* @param array $expectedEzLanguageCodes
*/
public function testGetPreferredLanguagesWithUserPreferredLanguage(array $userLanguages, array $expectedEzLanguageCodes): void
{
$request = new Request();
$request->headers = new HeaderBag(
Expand All @@ -57,9 +121,16 @@ public function testGetPreferredLanguages(array $userLanguages, array $expectedE
->method('getCurrentRequest')
->willReturn($request);

$userLanguagePreferenceProvider = new UserLanguagePreferenceProvider(
$this->requestStackMock,
$this->userPreferenceServiceMock,
$this->getLanguageCodesMap(),
self::LOCALE_FALLBACK
);

self::assertEquals(
$expectedEzLanguageCodes,
$this->userLanguagePreferenceProvider->getPreferredLanguages()
$userLanguagePreferenceProvider->getPreferredLanguages()
);
}

Expand All @@ -71,10 +142,27 @@ public function testGetPreferredLanguages(array $userLanguages, array $expectedE
public function providerForTestGetPreferredLanguages(): array
{
return [
[[], ['eng-GB', 'eng-US']],
[['pl'], ['pol-PL']],
[['pol-PL'], ['pol-PL']],
[['fr'], ['fre-FR']],
[['en'], ['eng-GB', 'eng-US']],
[['en_us'], ['eng-US']],
];
}

/**
* @see testGetPreferredLanguages
*
* @return array
*/
public function providerForTestGetPreferredLanguagesWithUserPreferredLanguage(): array
{
return [
[[], ['nor-NO', 'eng-GB', 'eng-US']],
[['pl'], ['nor-NO', 'pol-PL']],
[['fr'], ['nor-NO', 'fre-FR']],
[['en'], ['nor-NO', 'eng-GB', 'eng-US']],
[['en_us'], ['nor-NO', 'eng-US']],
];
}

Expand Down
Expand Up @@ -10,6 +10,8 @@

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use eZ\Publish\API\Repository\UserPreferenceService;
use eZ\Publish\API\Repository\Exceptions\NotFoundException;

class UserLanguagePreferenceProvider implements UserLanguagePreferenceProviderInterface
{
Expand All @@ -18,53 +20,72 @@ class UserLanguagePreferenceProvider implements UserLanguagePreferenceProviderIn
*/
private $requestStack;

/**
* @var \eZ\Publish\API\Repository\UserPreferenceService
*/
private $userPreferenceService;

/**
* @var array
*/
private $languageCodesMap;

/**
* @var string
*/
private $localeFallback;

/**
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
* @param \eZ\Publish\API\Repository\UserPreferenceService $userPreferenceService
* @param array $languageCodesMap
* @param string $localeFallback
*/
public function __construct(RequestStack $requestStack, array $languageCodesMap)
{
public function __construct(
RequestStack $requestStack,
UserPreferenceService $userPreferenceService,
array $languageCodesMap,
string $localeFallback
) {
$this->requestStack = $requestStack;
$this->userPreferenceService = $userPreferenceService;
$this->languageCodesMap = $languageCodesMap;
$this->localeFallback = $localeFallback;
}

public function getPreferredLocales(Request $request = null): array
{
$languages = [$this->localeFallback];

$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;
if (null !== $request) {
$browserLanguages = $request->getLanguages();
if ([] !== $browserLanguages) {
$languages = $browserLanguages;
}
}

return $result;
},
[]
);
arsort($preferredLocales);
try {
$preferredLanguage = $this->userPreferenceService->getUserPreference('language')->value;
array_unshift($languages, $preferredLanguage);
} catch (NotFoundException $e) {
}

return array_keys($preferredLocales);
return array_unique($languages);
}

public function getPreferredLanguages(): array
{
$languageCodes = [];
$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]);
if (!isset($this->languageCodesMap[$locale])) {
continue;
}

$languageCodes[] = $this->languageCodesMap[$locale];
}

return array_unique($languageCodes);
return array_unique(array_merge(...$languageCodes));
}
}

0 comments on commit 2365bec

Please sign in to comment.