Last active
June 4, 2016 09:28
-
-
Save geerteltink/1df70d2c072021633405a31e48f9138c to your computer and use it in GitHub Desktop.
PSR-7 Localization POC. A symfony translator is used but the zend-i18n translator has a similar setup.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Core\I18n; | |
use Zend\Expressive\Helper\UrlHelper; | |
class I18nUrlHelper extends UrlHelper | |
{ | |
public function __invoke($route = null, array $params = []) | |
{ | |
if ($this->getRouteResult()) { | |
$matchedParams = $this->getRouteResult()->getMatchedParams(); | |
$params['locale'] = $params['locale'] ?? $matchedParams['locale'] ?? 'en'; | |
} | |
return parent::__invoke($route, $params); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Core\I18n; | |
use Interop\Container\ContainerInterface; | |
use Zend\Expressive\Helper\Exception\MissingRouterException; | |
use Zend\Expressive\Router\RouterInterface; | |
class I18nUrlHelperFactory | |
{ | |
/** | |
* Create a UrlHelper instance. | |
* | |
* @param ContainerInterface $container | |
* | |
* @return I18nUrlHelper | |
* @throws \Interop\Container\Exception\NotFoundException | |
* @throws \Interop\Container\Exception\ContainerException | |
* @throws \Zend\Expressive\Helper\Exception\MissingRouterException | |
*/ | |
public function __invoke(ContainerInterface $container) | |
{ | |
if (!$container->has(RouterInterface::class)) { | |
throw new MissingRouterException(sprintf( | |
'%s requires a %s implementation; none found in container', | |
I18nUrlHelper::class, | |
RouterInterface::class | |
)); | |
} | |
return new I18nUrlHelper($container->get(RouterInterface::class)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Core\I18n; | |
use Psr\Http\Message\ResponseInterface; | |
use Psr\Http\Message\ServerRequestInterface; | |
use Symfony\Component\Translation\TranslatorInterface; | |
use Zend\Diactoros\Response\RedirectResponse; | |
class LocalizationMiddleware | |
{ | |
private $translator; | |
public function __construct(TranslatorInterface $translator) | |
{ | |
$this->translator = $translator; | |
} | |
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null) | |
{ | |
$acceptedLanguages = ['en', 'nl', 'fr', 'de', 'es']; | |
$locale = $request->getAttribute('locale'); | |
// If there is no or an invalid locale | |
if (!$locale || !in_array(substr(trim($locale), 0, 2), $acceptedLanguages, true)) { | |
// Try the user preferred locales | |
$userLocales = $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] ?? ''; | |
foreach (explode(',', $userLocales) as $userLocale) { | |
if (in_array(substr(trim($userLocale), 0, 2), $acceptedLanguages, true)) { | |
$locale = $userLocale; | |
break; | |
} | |
} | |
} | |
// Fallback to first accepted language | |
if (!$locale) { | |
$locale = $acceptedLanguages[0]; | |
} | |
// Only the language is needed | |
$locale = substr(trim($locale), 0, 2); | |
if ($request->getUri()->getPath() === '/') { | |
// Redirect and set the locale for the homepage | |
return new RedirectResponse('/' . $locale); | |
} | |
// Set current locale | |
$this->translator->setLocale($locale); | |
// Get response first, apply content language later | |
if (null !== $next) { | |
$response = $next($request->withAttribute('locale', $locale), $response); | |
} | |
// Append the preferred language if it's different from the locale | |
if ($acceptedLanguages[0] !== $locale) { | |
$locale .= ', ' . $acceptedLanguages[0]; | |
} | |
// Add the content language to the response | |
return $response->withHeader('Content-Language', $locale); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Core\I18n; | |
use Interop\Container\ContainerInterface; | |
use Symfony\Component\Translation\Loader\ArrayLoader; | |
use Symfony\Component\Translation\MessageSelector; | |
use Symfony\Component\Translation\Translator; | |
class TranslatorFactory | |
{ | |
public function __invoke(ContainerInterface $container) | |
{ | |
$config = $container->get('config'); | |
$config['i18n']['default_locale'] = 'en'; | |
$translator = new Translator($config['i18n']['default_locale'], new MessageSelector()); | |
$translator->addLoader('array', new ArrayLoader()); | |
$translator->setFallbackLocales([$config['i18n']['default_locale']]); | |
$translator->addResource('array', [ | |
'Hello World!' => 'Bonjour!', | |
], 'fr'); | |
$translator->addResource('array', [ | |
'Hello World!' => 'Hallo!', | |
], 'nl'); | |
return $translator; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Core\I18n; | |
use Interop\Container\ContainerInterface; | |
use Symfony\Bridge\Twig\Extension\TranslationExtension; | |
use Symfony\Component\Translation\TranslatorInterface; | |
class TwigTranslationExtensionFactory | |
{ | |
public function __invoke(ContainerInterface $container) | |
{ | |
return new TranslationExtension($container->get(TranslatorInterface::class)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Frontend\Action; | |
use App\Core\Action\AbstractAction; | |
use Psr\Http\Message\ResponseInterface; | |
use Psr\Http\Message\ServerRequestInterface; | |
use Symfony\Component\Translation\TranslatorInterface; | |
use Zend\Diactoros\Response\HtmlResponse; | |
use Zend\Expressive\Template\TemplateRendererInterface; | |
class HomePageAction extends AbstractAction | |
{ | |
private $template; | |
private $translator; | |
public function __construct(TemplateRendererInterface $template, TranslatorInterface $translator) | |
{ | |
$this->template = $template; | |
$this->translator = $translator; | |
} | |
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null) | |
{ | |
return new HtmlResponse($this->translator->trans('Hello World!')); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"require": { | |
"twig/extensions": "^1.3", | |
"symfony/translation": "^3.1", | |
"symfony/twig-bridge": "^3.1" | |
}, | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use App\Domain; | |
use Zend\Expressive; | |
return [ | |
'dependencies' => [ | |
'invokables' => [ | |
], | |
'factories' => [ | |
Expressive\Helper\UrlHelper::class => App\Core\I18n\I18nUrlHelperFactory::class, | |
App\Core\I18n\LocalizationMiddleware::class => App\Core\I18n\LocalizationMiddlewareFactory::class, | |
Symfony\Component\Translation\TranslatorInterface::class => App\Core\I18n\TranslatorFactory::class, | |
Symfony\Bridge\Twig\Extension\TranslationExtension::class => | |
App\Core\I18n\TwigTranslationExtensionFactory::class, | |
], | |
], | |
'middleware_pipeline' => [ | |
'routing' => [ | |
'middleware' => [ | |
Expressive\Container\ApplicationFactory::ROUTING_MIDDLEWARE, | |
Expressive\Helper\UrlHelperMiddleware::class, | |
App\Core\I18n\LocalizationMiddleware::class, | |
Expressive\Container\ApplicationFactory::DISPATCH_MIDDLEWARE, | |
], | |
'priority' => 1, | |
], | |
], | |
'twig' => [ | |
'cache_dir' => 'data/cache/twig', | |
'assets_url' => '/assets/', | |
'assets_version' => null, | |
'extensions' => [ | |
Symfony\Bridge\Twig\Extension\TranslationExtension::class, | |
], | |
], | |
]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Core\I18n; | |
use Interop\Container\ContainerInterface; | |
use Symfony\Component\Translation\TranslatorInterface; | |
class LocalizationMiddlewareFactory | |
{ | |
public function __invoke(ContainerInterface $container) | |
{ | |
return new LocalizationMiddleware( | |
$container->get(TranslatorInterface::class) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment