Skip to content

Commit

Permalink
feature #1511 Refactor how we define the available locales (javieregu…
Browse files Browse the repository at this point in the history
…iluz)

This PR was squashed before being merged into the main branch.

Discussion
----------

Refactor how we define the available locales

I never liked the `app_locales` parameter: https://github.com/symfony/demo/blob/main/config/services.yaml#L9

But we need it for the route locale requirements.

I was digging into how to improve this ... and realized that if we use the standard [enabled_locales](https://symfony.com/doc/current/reference/configuration/framework.html#enabled-locales) config option from Symfony, the `{_locale}` parameter included in the URLs is automatically restricted to those values.

So, we can simplify code by moving to `enabled_locales` without losing any functionality.

Commits
-------

2955454 Refactor how we define the available locales
  • Loading branch information
javiereguiluz committed Apr 12, 2024
2 parents 719a423 + 2955454 commit e8dc87b
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 36 deletions.
4 changes: 4 additions & 0 deletions config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ framework:
http_method_override: false
handle_all_throwables: true

# this defines the codes of the locales (languages) available in the application
# https://symfony.com/doc/current/reference/configuration/framework.html#enabled-locales
enabled_locales: ['ar', 'bg', 'bn', 'bs', 'ca', 'cs', 'de', 'en', 'es', 'eu', 'fr', 'hr', 'id', 'it', 'ja', 'lt', 'ne', 'nl', 'pl', 'pt_BR', 'ro', 'ru', 'sl', 'sq', 'sr_Cyrl', 'sr_Latn', 'tr', 'uk', 'vi', 'zh_CN']

# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
Expand Down
2 changes: 1 addition & 1 deletion config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ security:
access_control:
# this is a catch-all for the admin area
# additional security lives in the controllers
- { path: '^/(%app_locales%)/admin', roles: ROLE_ADMIN }
- { path: '^/{_locale}/admin', roles: ROLE_ADMIN }

# The ROLE_ADMIN role inherits from the ROLE_USER role
role_hierarchy:
Expand Down
4 changes: 0 additions & 4 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
homepage:
path: /{_locale}
controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
requirements:
_locale: '%app_locales%'
defaults:
template: default/homepage.html.twig
_locale: '%locale%'
Expand All @@ -17,7 +15,5 @@ controllers:
namespace: App\Controller
type: attribute
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'
4 changes: 1 addition & 3 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
locale: 'en'
# This parameter defines the codes of the locales (languages) enabled in the application
app_locales: ar|en|fr|de|es|cs|nl|ru|uk|ro|pt_BR|pl|it|ja|id|ca|sl|sq|hr|zh_CN|bg|tr|lt|bs|sr_Cyrl|sr_Latn|eu|ne|bn|vi
app.notifications.email_sender: anonymous@example.com

services:
Expand All @@ -18,7 +16,7 @@ services:
# this allows to define the scalar arguments once and apply them to any services
# defined/created in this file; if some argument is used rarely, instead of defining
# it here you can use the #[Autowire] attribute to inject it manually in the service constructor
string $locales: '%app_locales%'
array $enabledLocales: '%kernel.enabled_locales%'
string $defaultLocale: '%locale%'

# makes classes in src/ available to be used as services
Expand Down
27 changes: 10 additions & 17 deletions src/EventSubscriber/RedirectToPreferredLocaleSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,27 @@
*/
final class RedirectToPreferredLocaleSubscriber implements EventSubscriberInterface
{
/**
* @var string[]
*/
private array $locales;
private readonly string $defaultLocale;

public function __construct(
private readonly UrlGeneratorInterface $urlGenerator,
string $locales,
?string $defaultLocale = null
/** @var string[] */
private array $enabledLocales,
private ?string $defaultLocale = null
) {
$this->locales = explode('|', trim($locales));

if (empty($this->locales)) {
if (empty($this->enabledLocales)) {
throw new \UnexpectedValueException('The list of supported locales must not be empty.');
}

$this->defaultLocale = $defaultLocale ?: $this->locales[0];
$this->defaultLocale = $defaultLocale ?: $this->enabledLocales[0];

if (!\in_array($this->defaultLocale, $this->locales, true)) {
throw new \UnexpectedValueException(sprintf('The default locale ("%s") must be one of "%s".', $this->defaultLocale, $locales));
if (!\in_array($this->defaultLocale, $this->enabledLocales, true)) {
throw new \UnexpectedValueException(sprintf('The default locale ("%s") must be one of "%s".', $this->defaultLocale, implode(', ', $this->enabledLocales)));
}

// Add the default locale at the first position of the array,
// because Symfony\HttpFoundation\Request::getPreferredLanguage
// returns the first element when no an appropriate language is found
array_unshift($this->locales, $this->defaultLocale);
$this->locales = array_unique($this->locales);
array_unshift($this->enabledLocales, $this->defaultLocale);
$this->enabledLocales = array_unique($this->enabledLocales);
}

public static function getSubscribedEvents(): array
Expand All @@ -81,7 +74,7 @@ public function onKernelRequest(RequestEvent $event): void
return;
}

$preferredLanguage = $request->getPreferredLanguage($this->locales);
$preferredLanguage = $request->getPreferredLanguage($this->enabledLocales);

if ($preferredLanguage !== $this->defaultLocale) {
$response = new RedirectResponse($this->urlGenerator->generate('homepage', ['_locale' => $preferredLanguage]));
Expand Down
16 changes: 5 additions & 11 deletions src/Twig/AppExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,17 @@
*/
final class AppExtension extends AbstractExtension
{
/**
* @var string[]
*/
private readonly array $localeCodes;

/**
* @var list<array{code: string, name: string}>|null
*/
private ?array $locales = null;

// The $locales argument is injected thanks to the service container.
// See https://symfony.com/doc/current/service_container.html#binding-arguments-by-name-or-type
public function __construct(string $locales)
{
$localeCodes = explode('|', $locales);
sort($localeCodes);
$this->localeCodes = $localeCodes;
public function __construct(
/** @var string[] */
private array $enabledLocales,
) {
}

public function getFunctions(): array
Expand All @@ -65,7 +59,7 @@ public function getLocales(): array

$this->locales = [];

foreach ($this->localeCodes as $localeCode) {
foreach ($this->enabledLocales as $localeCode) {
$this->locales[] = ['code' => $localeCode, 'name' => Locales::getName($localeCode, $localeCode)];
}

Expand Down

0 comments on commit e8dc87b

Please # to comment.