yii2 create translated URLs

2019-07-20 16:20发布

问题:

I need to create user-friendly URLs which are translated, yet point to the same controller as the others for a language.

Example:

/en/myCar/100 -> /de/meinAuto/100 -> /fr/monVoiture/100

I tried using routes but couldn't find a way to call the controller depending on a translated URL.

Any hints where I should start?

回答1:

It can't be done easily with built in functionality, but someone had the same need and wrote a package specifically for this: yii2-localeurls. I think that might be what you are looking for:

With this extension you can use URLs that contain a language code like:

/en/some/page
/de/some/page
http://www.example.com/en/some/page
http://www.example.com/de/some/page

You can also configure friendly names if you want:

http://www.example.com/english/some/page
http://www.example.com/deutsch/some/page

The language code is automatically added whenever you create a URL, and read back when a URL is parsed. For best user experience the language is autodetected from the browser settings, if no language is used in the URL. The user can still access other languages, though, simply by calling a URL with another language code.

The last requested language is also persisted in the user session and in a cookie. So if the user tries to access your site without a language code in the URL, he'll get redirected to the language he had used on his last visit.



回答2:

This is my working solution, by using the https://github.com/codemix/yii2-localeurls in addition and yii2 advanced template:

Create frontend/components/i18nUrlRules.php

namespace frontend\components;
use Yii;
use yii\base\BootstrapInterface;
class i18nUrlRules implements BootstrapInterface
{
    public function bootstrap($app)
    {
        //Place here the translated UrlRules
        $i18nRules=[
            'myCar/index' => [
                'de' => 'meinAuto',
                'fr' => 'monVoiture',
                'en' => 'myCar',
            ],
            '...' => [
                ...
            ],
        ];
        $reqLang=explode("/",$_SERVER['REQUEST_URI'])[1];
        $languages = ['en','de','fr'];
        $reqLang=in_array($reqLang,$languages)?$reqLang:\Yii::$app->language; //If not in array, use the default language
        \Yii::$app->getUrlManager()->addRules(
            [ 
                $i18nRules['myCar/index'][$reqLang] =>'myCar/index',
                ...
            ],
        false);
    }
}

And then on frontend/config/main.php:

'bootstrap' => [
        'log',
        'frontend\components\i18nUrlRules',
    ],

So, /en/myCar, /de/meinAuto and /fr/monVoiture will use myCar/index rule



回答3:

Ok, turns out, it's pretty simple with rules (some trial and error helped):

'<language:(de)>/meinAuto' => 'myCar/index',
'<language:(fr)>/monVoiture' => 'myCar/index'

... and so on...

And just to comment the answer below: the language-code wasn't the problem, I had solved this a while ago... the problem was, that I needed the controller-part in the user's language



回答4:

You can do it easy manually in Yii2 without any extensions:

1) Inside config/web.php change you rule (for example)

from

'rules' =>[
    [
        'pattern' => '',
        'route' => 'main/index',
        'suffix' => ''
    ],
]

to (add rule for language)

'rules' =>[
    [
        'pattern' => '',
        'route' => 'main/index',
        'suffix' => ''
    ],
    '<language:\w{2}>'=>'main/index',
]

do the same for other rules if you have (for example)

[
    'pattern' => '<controller>/<action>/<id:\w+>',
    'route' => '<controller>/<action>',
    'suffix' => ''
],
[
    'pattern' => '<language:\w{2}>/<controller>/<action>/<id:\w+>',
    'route' => '<controller>/<action>',
    'suffix' => ''
],

2) Imagine that we have 3 landuages: ru, en, kz. And all controllers extends our BehaviorsController.php (example, class MainController extends BehaviorsController)

Inside BehaviorsController.php create beforeAction() function

public function beforeAction($action)
{       
    $language = Yii::$app->getRequest()->getQueryParam('language');
    if($language){
        if(in_array($language,Yii::$app->params['langs'])) Yii::$app->session->set('lang',$language);
        Yii::$app->language = $language;
    }
    return parent::beforeAction($action);
}

3) Inside config/params.php add langs key to array

return [
    ... // some params
    'langs' => ['RU' => 'ru','KZ' => 'kz','EN' => 'en'],    //allowed languages
];

4) That's it. Now we can check the path using language param:

example.com/ru

or

example.com/en