zendframework / zend-expressive

PSR-15 middleware in minutes!
BSD 3-Clause "New" or "Revised" License
711 stars 196 forks source link

How can I pass locale to Twig extension? #524

Open back-2-95 opened 7 years ago

back-2-95 commented 7 years ago

I have made routes and locale middleware with this Cookbook: setting-locale-depending-routing-parameter.md

Now I wonder how I can pass the locale to Twig Extension which I use to create function {{ __('translate me') }}

Twig Extension is added in config/autoload/templates.global.php like this:

return [
    'dependencies' => [
        'factories' => [
            Twig_Environment::class => TwigEnvironmentFactory::class,
            TemplateRendererInterface::class => TwigRendererFactory::class,
            TranslationExtension::class => TranslationExtension::class,
        ],
    ],

    'templates' => [
        'extension' => 'html.twig',
    ],

    'twig' => [
        'cache_dir'      => 'data/cache/twig',
        'assets_url'     => '/',
        'assets_version' => null,
        'extensions'     => [
            // extension service names or instances
            TranslationExtension::class
        ],
        'runtime_loaders' => [
            // runtime loader names or instances
        ],
        'globals' => [
            // Variables to pass to all twig templates
        ],
        'timezone' => 'Europe/Helsinki',
    ],
];
vaclavvanik commented 7 years ago

Well you have to pass locale variable to twig in middleware

back-2-95 commented 7 years ago

My Twig extension loads translator, but it needs the locale information. So how can I pass the locale from middleware to Twig extension or how can I get it in the extension?

geerteltink commented 7 years ago

Inject the translator extension into the locale detection middleware. Update the locale after detection into the extension.

back-2-95 commented 7 years ago

I created static method in the Extension class and I set locale in Localization middleware after detection.

geerteltink commented 7 years ago

Actually, you don't need to inject the locale into the extension. You can set the default locale directly in the translator. Here is how I did it a while back (old code):

<?php
declare(strict_types = 1);

namespace App\Middleware\I18n;

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Symfony\Component\Translation\TranslatorInterface;
use Zend\Diactoros\Response\RedirectResponse;
use Zend\Stratigility\MiddlewareInterface;

class LocalizationMiddleware implements MiddlewareInterface
{
    private $translator;

    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }

    public function __invoke(Request $request, Response $response, callable $out = null) : Response
    {
        $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 !== $out) {
            $response = $out($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);
    }
}
weierophinney commented 4 years ago

This repository has been closed and moved to mezzio/mezzio; a new issue has been opened at https://github.com/mezzio/mezzio/issues/11.