# Multilanguage website with locale url

**URL:** <https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176>\
**Category:** Questions\
**Created:** [May 20, 2019, 8:47am UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176 "2019-05-20T08:47:00Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![brainstorm](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@brainstorm](https://discourse.slimframework.com/u/brainstorm)\
**Post date:** [May 20, 2019, 8:47am UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/1 "2019-05-20T08:47:00Z")

</div>

Hello  
I would like to create a middleware to add in the App for the locale in the url without change existing route.  
Example:  
$app-\>get(’/’, function (Request $request, Response $response) use ($container) {  
//code here  
//URI is [https://www.example.com/](https://www.example.com/)  
or  
//URI is [https://www.example.com/en/](https://www.example.com/en/)  
or  
//URI is [https://www.example.com/de/](https://www.example.com/de/)  
}  
$app-\>get(’/about’, function (Request $request, Response $response) use ($container) {  
//code here  
//URI is [https://www.example.com/en/about](https://www.example.com/en/about)  
or  
//URI is [https://www.example.com/de/about](https://www.example.com/de/about)  
}  
When locale is in the URL, a locale option in the container was set.

What is the best solution for this without editing pattern in the routes?

---

<div class="post-metadata">

**Author:** ![ChaoticCoder](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@ChaoticCoder](https://discourse.slimframework.com/u/ChaoticCoder)\
**Post date:** [May 20, 2019, 4:15pm UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/2 "2019-05-20T16:15:33Z")

</div>

I don’t know if this is the way to go, but it works for me. First of all, wrap all your routes up in a group that takes an optional parameter named lang, something like below

```auto
$app->group('/{lang}', function() use($container) {

    $this->get('/', 'HomeController:index')->setName('home');
    $this->get('/signup', AuthSignUpController::class.':getSignUp')->setName('auth.signup'); 
    $this->post('/signup', AuthSignUpController::class.':postSignUp');
    $this->get('/signin', AuthSignInController::class.':getSignIn')->setName('auth.signin');
    $this->post('/signin', AuthSignInController::class.':postSignIn');
});

```

Then in _my_ middleware I check if the request has a parameter named lang, and I check if the value of lang is something valid.

```auto
/**
 * Checks if Uri has invalid or missing language prefix, and redirects to valid route
 * @package App\Middleware
 */
class UriLanguagePrefixerMiddleware
{

    private $router;
    private $view;
    private $localization;
    private $translator;
    private $requestedLanguage;

    public function __construct(Router $router, Twig $view, $localization, Translator $translator)
    {
        $this->router = $router;
        $this->view = $view;
        $this->localization = $localization;
        $this->translator = $translator;
    }

    /**
     * Automatically invoked during any request to the site
     * @param Request | \Slim\Http\Request $request
     * @param Response | \Slim\Http\Response $response
     * @param $next
     * @return mixed
     */
    public function __invoke(Request $request, Response $response, callable $next)
    {
        $validLanguages = $this->localization['languages'];

        // running this middleware (NON-route attached) requires settings -> determineRouteBeforeAppMiddleware = true
        $route = $request->getAttribute('route');
        if (null == $route) {
            $routeName = 'auth.signin';
            $requestedLanguage = null;
        } else {
            $routeName = $route->getName();
            $requestedLanguage = explode('/', $route->getArgument('lang'))[0];
        }

        if (null == $requestedLanguage || !array_key_exists($requestedLanguage, $validLanguages)) {

            $_SESSION['lang'] = key($validLanguages); // first key of language array in settings = de_DE
            $requestedLanguage = $_SESSION['lang'];

            return $response->withRedirect($this->router->pathFor($routeName, [
                'lang' => $requestedLanguage,
            ]));

        }
        $this->view->getEnvironment()->addGlobal('lang', $requestedLanguage);
        $this->translator->setLocale($requestedLanguage);
        $response = $next($request, $response);
        return $response;
    }
}

```

localization comes from my settings array by the way

```auto
$app = new \Slim\App([
    'settings' => [
        'displayErrorDetails' => true,
        'devMode' => true,
        'determineRouteBeforeAppMiddleware' => true,

        'localization' => [

            'languages' => [
                'de_DE' => 'Deutsch',
                'en_US' => 'English'
            ],

            'locales' => [
                'de' => 'de_DE',
                'en' => 'en_US'
            ],
         ],
]
]);
```

---

<div class="post-metadata">

**Author:** ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)\
**Post date:** [May 20, 2019, 5:33pm UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/3 "2019-05-20T17:33:39Z")

</div>

[Route groups](http://www.slimframework.com/docs/v3/objects/router.html#route-groups) are good to organize routes into logical groups.

Example:

```php
use Slim\App;

// ...

// https://www.example.com/
$app->get('/', \App\Action\HomeIndexAction::class)->setName('root');

// Language group
$app->group('/{language:(?:en|de)}', function () {
    /** @var App $this */

    // https://www.example.com/en
    // https://www.example.com/de
    $this->get('', \App\Action\LanguageIndexAction::class);

    // https://www.example.com/en/about
    // https://www.example.com/de/about
    $this->get('/about', \App\Action\AboutAction::class);
});

```

To get the url’s language use the $request variable:

```php
$language = $request->getAttribute('language'); // "en" or "de"

```

---

<div class="post-metadata">

**Author:** ![brainstorm](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@brainstorm](https://discourse.slimframework.com/u/brainstorm)\
**Post date:** [May 20, 2019, 6:01pm UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/4 "2019-05-20T18:01:05Z")

</div>

Yes, I know group already. I need something before the routing, outside the get/map logic because my app is modular, anyone can add routes outside my routes file, so all the routes outside my routes file can’t be added to this rule.

---

<div class="post-metadata">

**Author:** ![brainstorm](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@brainstorm](https://discourse.slimframework.com/u/brainstorm)\
**Post date:** [August 22, 2019, 8:51am UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/5 "2019-08-22T08:51:40Z")

</div>

I have found a solution to this problem, I have created a middleware that replace the SLIM $request object (leave the URI part intact). This is the code: [https://github.com/BrainStormDevel/perseo/blob/master/Core/PerSeo/MiddleWare/Language.php](https://github.com/BrainStormDevel/perseo/blob/master/Core/PerSeo/MiddleWare/Language.php)  
The solution is not perfect, because this code will break the container and, for now, I don’t know why.

---

<div class="post-metadata">

**Author:** ![Mikalay](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.slimframework.com/mikalay/32/720_2.png) [@Mikalay](https://discourse.slimframework.com/u/Mikalay)\
**Post date:** [August 22, 2019, 1:42pm UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/6 "2019-08-22T13:42:07Z")

</div>

As an option, you can consider the approach [as here](https://codecourse.com/courses/eloquent-translations-with-slim-3) (Simple translation switching, using the Eloquent translations component from Laravel.)

---

<div class="post-metadata">

**Author:** ![brainstorm](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@brainstorm](https://discourse.slimframework.com/u/brainstorm)\
**Post date:** [August 22, 2019, 4:54pm UTC](https://discourse.slimframework.com/t/multilanguage-website-with-locale-url/3176/7 "2019-08-22T16:54:08Z")

</div>

The approch I interested in was a language args invoked before any route. So, the unique solution I’ve found was this Middleware.
