Skip to content

Commit

Permalink
Add twig extension to canonicalize locales for momentjs (#336)
Browse files Browse the repository at this point in the history
  • Loading branch information
jordisala1991 committed May 10, 2022
1 parent 43463cd commit 6c297ca
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 3 deletions.
3 changes: 0 additions & 3 deletions assets/scss/app.scss
Expand Up @@ -10,7 +10,4 @@
// Eonasdan Bootstrap DateTimePicker in its version 3 does not
// provide the scss or plain css, it only provides the less version
// of its source files, that's why it is not included it via npm.
//
// Eonasdan Bootstrap DateTimePicker is not directly used in SonataAdmin
// but it is used on form-extensions package
@import '../vendor/bootstrap-datetimepicker.min.css';
Expand Up @@ -50,6 +50,7 @@ public function load(array $configs, ContainerBuilder $container): void
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('date.php');
$loader->load('form_types.php');
$loader->load('twig.php');
$loader->load('validator.php');

$container->setParameter('sonata.form.form_type', $config['form_type']);
Expand Down
31 changes: 31 additions & 0 deletions src/Bridge/Symfony/Resources/config/twig.php
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Sonata\Form\Twig\CanonicalizeRuntime;
use Sonata\Form\Twig\Extension\CanonicalizeExtension;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
// Use "service" function for creating references to services when dropping support for Symfony 4.4
$containerConfigurator->services()

->set('sonata.form.twig.canonicalize_extension', CanonicalizeExtension::class)
->tag('twig.extension')

->set('sonata.form.twig.canonicalize_runtime', CanonicalizeRuntime::class)
->tag('twig.runtime')
->args([
new ReferenceConfigurator('request_stack'),
]);
};
70 changes: 70 additions & 0 deletions src/Twig/CanonicalizeRuntime.php
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\Form\Twig;

use Symfony\Component\HttpFoundation\RequestStack;
use Twig\Extension\RuntimeExtensionInterface;

final class CanonicalizeRuntime implements RuntimeExtensionInterface
{
// @todo: there are more locales which are not supported by "Moment.js" NPM library and they need to be translated/normalized/canonicalized here
private const MOMENT_UNSUPPORTED_LOCALES = [
'de' => ['de', 'de-at'],
'es' => ['es', 'es-do'],
'nl' => ['nl', 'nl-be'],
'fr' => ['fr', 'fr-ca', 'fr-ch'],
];

private RequestStack $requestStack;

/**
* @internal This class should only be used through Twig
*/
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}

/**
* Returns a canonicalized locale for "Moment.js" NPM library,
* or `null` if the locale's language is "en", which doesn't require localization.
*/
public function getCanonicalizedLocaleForMoment(): ?string
{
$locale = $this->getLocale();

// "en" language doesn't require localization.
if (('en' === $lang = substr($locale, 0, 2)) && !\in_array($locale, ['en-au', 'en-ca', 'en-gb', 'en-ie', 'en-nz'], true)) {
return null;
}

foreach (self::MOMENT_UNSUPPORTED_LOCALES as $language => $locales) {
if ($language === $lang && !\in_array($locale, $locales, true)) {
$locale = $language;
}
}

return $locale;
}

private function getLocale(): string
{
$request = $this->requestStack->getCurrentRequest();
if (null === $request) {
throw new \LogicException('The request stack is empty.');
}

return str_replace('_', '-', $request->getLocale());
}
}
31 changes: 31 additions & 0 deletions src/Twig/Extension/CanonicalizeExtension.php
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\Form\Twig\Extension;

use Sonata\Form\Twig\CanonicalizeRuntime;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class CanonicalizeExtension extends AbstractExtension
{
/**
* @return TwigFunction[]
*/
public function getFunctions(): array
{
return [
new TwigFunction('sonata_form_canonicalize_locale_for_moment', [CanonicalizeRuntime::class, 'getCanonicalizedLocaleForMoment']),
];
}
}
172 changes: 172 additions & 0 deletions tests/Twig/CanonicalizeRuntimeTest.php
@@ -0,0 +1,172 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\Form\Tests\Twig;

use PHPUnit\Framework\TestCase;
use Sonata\Form\Twig\CanonicalizeRuntime;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

final class CanonicalizeRuntimeTest extends TestCase
{
private Request $request;

private CanonicalizeRuntime $canonicalizeRuntime;

protected function setUp(): void
{
$this->request = new Request();
$requestStack = new RequestStack();
$requestStack->push($this->request);
$this->canonicalizeRuntime = new CanonicalizeRuntime($requestStack);
}

/**
* @dataProvider momentLocalesProvider
*/
public function testCanonicalizedLocaleForMoment(?string $expected, string $original): void
{
$this->changeLocale($original);
static::assertSame($expected, $this->canonicalizeRuntime->getCanonicalizedLocaleForMoment());
}

/**
* @return array<array{?string, string}>
*/
public function momentLocalesProvider(): array
{
return [
['af', 'af'],
['ar-dz', 'ar-dz'],
['ar', 'ar'],
['ar-ly', 'ar-ly'],
['ar-ma', 'ar-ma'],
['ar-sa', 'ar-sa'],
['ar-tn', 'ar-tn'],
['az', 'az'],
['be', 'be'],
['bg', 'bg'],
['bn', 'bn'],
['bo', 'bo'],
['br', 'br'],
['bs', 'bs'],
['ca', 'ca'],
['cs', 'cs'],
['cv', 'cv'],
['cy', 'cy'],
['da', 'da'],
['de-at', 'de-at'],
['de', 'de'],
['de', 'de-de'],
['dv', 'dv'],
['el', 'el'],
[null, 'en'],
[null, 'en-us'],
['en-au', 'en-au'],
['en-ca', 'en-ca'],
['en-gb', 'en-gb'],
['en-ie', 'en-ie'],
['en-nz', 'en-nz'],
['eo', 'eo'],
['es-do', 'es-do'],
['es', 'es-ar'],
['es', 'es-mx'],
['es', 'es'],
['et', 'et'],
['eu', 'eu'],
['fa', 'fa'],
['fi', 'fi'],
['fo', 'fo'],
['fr-ca', 'fr-ca'],
['fr-ch', 'fr-ch'],
['fr', 'fr-fr'],
['fr', 'fr'],
['fy', 'fy'],
['gd', 'gd'],
['gl', 'gl'],
['he', 'he'],
['hi', 'hi'],
['hr', 'hr'],
['hu', 'hu'],
['hy-am', 'hy-am'],
['id', 'id'],
['is', 'is'],
['it', 'it'],
['ja', 'ja'],
['jv', 'jv'],
['ka', 'ka'],
['kk', 'kk'],
['km', 'km'],
['ko', 'ko'],
['ky', 'ky'],
['lb', 'lb'],
['lo', 'lo'],
['lt', 'lt'],
['lv', 'lv'],
['me', 'me'],
['mi', 'mi'],
['mk', 'mk'],
['ml', 'ml'],
['mr', 'mr'],
['ms', 'ms'],
['ms-my', 'ms-my'],
['my', 'my'],
['nb', 'nb'],
['ne', 'ne'],
['nl-be', 'nl-be'],
['nl', 'nl'],
['nl', 'nl-nl'],
['nn', 'nn'],
['pa-in', 'pa-in'],
['pl', 'pl'],
['pt-br', 'pt-br'],
['pt', 'pt'],
['ro', 'ro'],
['ru', 'ru'],
['se', 'se'],
['si', 'si'],
['sk', 'sk'],
['sl', 'sl'],
['sq', 'sq'],
['sr-cyrl', 'sr-cyrl'],
['sr', 'sr'],
['ss', 'ss'],
['sv', 'sv'],
['sw', 'sw'],
['ta', 'ta'],
['te', 'te'],
['tet', 'tet'],
['th', 'th'],
['tlh', 'tlh'],
['tl-ph', 'tl-ph'],
['tr', 'tr'],
['tzl', 'tzl'],
['tzm', 'tzm'],
['tzm-latn', 'tzm-latn'],
['uk', 'uk'],
['uz', 'uz'],
['vi', 'vi'],
['x-pseudo', 'x-pseudo'],
['yo', 'yo'],
['zh-cn', 'zh-cn'],
['zh-hk', 'zh-hk'],
['zh-tw', 'zh-tw'],
];
}

private function changeLocale(string $locale): void
{
$this->request->setLocale($locale);
}
}

0 comments on commit 6c297ca

Please sign in to comment.