Yii2 I18n change controller name with selected language

Hi,

Is it possible to change controller name and action name with current selected language like:

If current language is en then url shuold:

http://localhost/yii2app/site/index

and if current language is da then url should:

http://localhost/yii2app/websted/indeks

It is what I have tried but it shows 404 not found:

frontend/config/main.php


'urlManager' => [

            'baseUrl' => $baseUrl,

            'enablePrettyUrl' => true,

            'showScriptName' => false,

            'rules' => [

                Yii::t('app','site/index') => Yii::t('app','site/index'),

            ],

        ],

    

in common/messages/da/app.php




	return [

             'site/index'=>'websted/indeks'

	];



In my layouts/main.php




<a href="<?= Yii::$app->urlManager

                      ->createUrl([Yii::t('app','site/index')])?>">

          <?= Yii::t('app','Home') ?>

          </a>




I made something similar some time ago but it’s not perfect.

Take a look here.

Thank you friend, can you please share


 parseRequest() 

detail, how you integrated that?




    public function parseRequest($request)

    {

        if ($this->enablePrettyUrl) {

            /* @var $rule UrlRule */

            foreach ($this->rules as $rule) {

                if (($result = $rule->parseRequest($this, $request)) !== false) {

                    $routeParts = explode('/', $result[0]);

                    if (isset($routeParts[0]) && !empty($this->languageControllers[$this->language])) {

                        foreach ($this->languageControllers[$this->language] as $default => $localized) {

                            if ($localized == $routeParts[0]) {

                                $routeParts[0] = $default;

                                break;

                            }

                        }

                    }

                    if (isset($routeParts[1]) && !empty($this->languageActions[$this->language])) {

                        foreach ($this->languageActions[$this->language] as $default => $localized) {

                            if ($localized == $routeParts[1]) {

                                $routeParts[1] = $default;

                                break;

                            }

                        }

                    }

                    $result[0] = implode('/', $routeParts);

                    return $result;

                }

            }


            if ($this->enableStrictParsing) {

                return false;

            }


            Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__);


            $suffix = (string) $this->suffix;

            $pathInfo = $request->getPathInfo();

            if ($suffix !== '' && $pathInfo !== '') {

                $n = strlen($this->suffix);

                if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) {

                    $pathInfo = substr($pathInfo, 0, -$n);

                    if ($pathInfo === '') {

                        // suffix alone is not allowed

                        return false;

                    }

                } else {

                    // suffix doesn't match

                    return false;

                }

            }


            return [$pathInfo, []];

        } else {

            Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);

            $route = $request->getQueryParam($this->routeParam, '');

            if (is_array($route)) {

                $route = '';

            }


            return [(string) $route, []];

        }

    }



Thank you so much for your time and piece of code,

I’m getting Not Found (#404) error when my url looks like this: websted/indeks

but it is okay with site/index.

Here is what I have tried:

In frontend\config/main.php





'urlManager' => [

            'baseUrl' => $baseUrl,

            'class' => 'frontend\components\CustomUrlRule',

            'enablePrettyUrl' => true,

            'showScriptName' => false,

            'enableStrictParsing' => false,

            'rules' => [

            ],

        ],



and in frontend\components\CustomUrlRule




<?php

namespace frontend\components;

use Yii;

use yii\web\UrlManager;


class CustomUrlRule extends UrlManager

{




     public function parseRequest($request)

    {

        if ($this->enablePrettyUrl) {

            /* @var $rule UrlRule */

            foreach ($this->rules as $rule) {

                if (($result = $rule->parseRequest($this, $request)) !== false) {

                    $routeParts = explode('/', $result[0]);

                    if (isset($routeParts[0]) && !empty($this->languageControllers[$this->language])) {

                        foreach ($this->languageControllers[$this->language] as $default => $localized) {

                            if ($localized == $routeParts[0]) {

                                $routeParts[0] = $default;

                                break;

                            }

                        }

                    }

                    if (isset($routeParts[1]) && !empty($this->languageActions[$this->language])) {

                        foreach ($this->languageActions[$this->language] as $default => $localized) {

                            if ($localized == $routeParts[1]) {

                                $routeParts[1] = $default;

                                break;

                            }

                        }

                    }

                    $result[0] = implode('/', $routeParts);

                    return $result;

                }

            }


            if ($this->enableStrictParsing) {

                return false;

            }


            Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__);


            $suffix = (string) $this->suffix;

            $pathInfo = $request->getPathInfo();

            if ($suffix !== '' && $pathInfo !== '') {

                $n = strlen($this->suffix);

                if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) {

                    $pathInfo = substr($pathInfo, 0, -$n);

                    if ($pathInfo === '') {

                        // suffix alone is not allowed

                        return false;

                    }

                } else {

                    // suffix doesn't match

                    return false;

                }

            }


            return [$pathInfo, []];

        } else {

            Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);

            $route = $request->getQueryParam($this->routeParam, '');

            if (is_array($route)) {

                $route = '';

            }


            return [(string) $route, []];

        }

    }

    

}



Also please let me know, Is my including of CustomUrlRule class is ok or I need to move somewhere else?

Edit:

This condition is not getting true:


if (($result = $rule->parseRequest($this, $request)) !== false)

I have modified this code to work with the current framework version. It needs to be tested because I’m pretty sure not every case is covered there.

common\components\UrlManager.php:


<?php


namespace common\components;


use Yii;

use yii\web\Request;

use yii\web\UrlManager as YiiUrlManager;


/**

 * UrlManager

 * Allows to translate urls dynamically.

 */

class UrlManager extends YiiUrlManager

{

    public $enablePrettyUrl = true;

    public $showScriptName  = false;


    public $language;


    /**

     * Translated controllers names.

     * language code => [

     *      source name => translated name

     * ]

     * @var array 

     */

    public $languageControllers = [

        'eo' => [

            'site'  => 'ejo',

            'users' => 'uzantoj'

        ],

    ];


    /**

     * Translated actions names.

     * language code => [

     *      source name => translated name

     * ]

     * @var array 

     */

    public $languageActions = [

        'eo' => [

            'contact' => 'kontakton',

            'about'   => 'pri-ni',

            'test'    => 'testo'

        ],

    ];


    /**

     * Initializes UrlManager.

     */

    public function init()

    {

        parent::init();


        if (empty($this->language)) {

            $this->language = Yii::$app->language;

        }

    }


    /**

     * Creates translated url.

     * @param array $params

     * @return string the created URL

     */

    public function createUrl($params)

    {

        $params = (array)$params;


        $route = explode('/', trim($params[0], '/'));

        if (isset($route[0]) && !empty($this->languageControllers[$this->language][$route[0]])) {

            $route[0] = $this->languageControllers[$this->language][$route[0]];

        }

        if (isset($route[1]) && !empty($this->languageActions[$this->language][$route[1]])) {

            $route[1] = $this->languageActions[$this->language][$route[1]];

        }

        $params[0] = implode('/', $route);


        return parent::createUrl($params);

    }


    /**

     * Translates the request back to the source one.

     * @param Request $request the request component

     * @return Request

     */

    public function translateRequest($request)

    {

        if (empty($this->languageControllers[$this->language])) {

            return $request;

        }

        $url = ltrim($request->getPathInfo(), '/');

        $parts = explode('/', $url);

        $controller = $parts[0];

        $action = isset($parts[1]) ? $parts[1] : null;

        foreach ($this->languageControllers[$this->language] as $default => $localized) {

            if ($localized == $controller) {

                $controller = $default;

                break;

            }

        }

        $parts[0] = $controller;

        if ($action !== null) {

            foreach ($this->languageActions[$this->language] as $default => $localized) {

                if ($localized === substr($action, 0, mb_strlen($localized, 'UTF-8'))) {

                    $action = $default . substr($action, mb_strlen($localized, 'UTF-8'));

                    break;

                }

            }

            $parts[1] = $action;

        }

        $request->setPathInfo(implode('/', $parts));

        return $request;

    }


    /**

     * Parses and translates the user request.

     * @param Request $request the request component

     * @return array|boolean the route and the associated parameters. The latter is always empty

     * if [[enablePrettyUrl]] is false. False is returned if the current request cannot be successfully parsed.

     */

    public function parseRequest($request)

    {

        return parent::parseRequest($this->translateRequest($request));

    }

}

UrlManager configuration:


// ...

'components' => [

    // ...

    'urlManager' => [

        'class' => 'common\components\UrlManager',

        // ...

    ],

],

Now, for Yii:$app->language = ‘eo’;

[list=1]

[*]/site/test calls controller Site with action Test.

[*]/ejo/testo calls controller Site with action Test.

[*]/ejo calls controller Site with action Index.

[*]/site/testo calls controller Site with action Test.

[/list]

For different languages only existing routes work. You can send parameters to action in the normal way.