zendframework / zend-expressive

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

Update cookbook for locale routing parameter #350

Closed geerteltink closed 7 years ago

geerteltink commented 8 years ago

I've followed the guidelines for setting up a locale depending on a routing parameter.

The problem I have that if a locale is given in the url, I have to inject it inside every route. This has to be done after the LocalizationMiddleware. Since the config and routes are already loaded I found no way to set the current locale as the default locale for every route.

However by a simple hack this can be done automatically:

<?php

namespace App\Core\Router;

class FastRouteRouter extends \Zend\Expressive\Router\FastRouteRouter
{
    public function generateUri($name, array $substitutions = [])
    {
        if (!array_key_exists('locale', $substitutions)) {
            $substitutions['locale'] = substr(\Locale::getDefault(), 0, 2);
        }

        return parent::generateUri($name, $substitutions);
    }
}

Would this be useful to implement this directly or add it to the cookbook?

moderndeveloperllc commented 8 years ago

They seem to want all the locale stuff in the cookbook. If they ever merge this pull request, you can take out the substr() as the locale logic will account for language-country locales. (But not script - sorry Serbians!)

Ocramius commented 8 years ago

\Locale::getDefault()

This is an absolute NO-GO in a PSR-7 environment. The locale should be resolved via the request object, not from global environment

class FastRouteRouter extends \Zend\Expressive\Router\FastRouteRouter

I wouldn't extend, but instead wrap and then use a delegator factory around the router. That would simplify things by a huge lot, in my opinion.

geerteltink commented 8 years ago

@Ocramius I'm setting it with middleware first:

class LocalizationMiddleware
{
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
    {
        $locale = $request->getAttribute(
            'locale',
            Locale::acceptFromHttp($request->getServerParams()['HTTP_ACCEPT_LANGUAGE'])
        );
        Locale::setDefault($locale);

        if ($request->getUri()->getPath() === '/') {
            return new RedirectResponse('/' . substr(\Locale::getDefault(), 0, 2));
        }

        return $next($request, $response);
    }
}

Thanx for the advice on the delegator factory. I'll try that.

Ocramius commented 8 years ago

Locale::setDefault($locale);

Argh, we should really kill that stuff :-\

geerteltink commented 8 years ago

As discussed on IRC, it's better to inject the locale as request attribute and not rely on a static global.

RalfEggert commented 8 years ago

@xtreamwayz

could you document that in the cookbook? Or is that already included in the recipies?

geerteltink commented 8 years ago

I'm figuring out a solution right now. The cookbook sets the static default locale and hasn't any locale detection.

What I have so far is something ugly but it's working: https://gist.github.com/xtreamwayz/1df70d2c072021633405a31e48f9138c

I still need to hook it up with a translation lib and twig. Once I have it completely working I'll update the cookbook.

geerteltink commented 8 years ago

I've got translations working with Twig and Symfony Translator. It should be almost the same for the Zend translator since they have almost the same api.

To get the translation working, you don't even need to inject it into the request. I've updated my gist: https://gist.github.com/xtreamwayz/1df70d2c072021633405a31e48f9138c

If you guys want to review it before I transfer it to the cookbook.

/cc @Ocramius @RalfEggert

geerteltink commented 7 years ago

This is changed with #351.