2

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?

Swissdude
  • 3,486
  • 3
  • 35
  • 68

5 Answers5

3

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.

Blizz
  • 8,082
  • 2
  • 33
  • 53
  • thanks - but this wasn't the problem as you can see from my own answer. The language-code part was pretty easy to implement... :) – Swissdude Jun 03 '15 at 13:43
  • 1
    Right, not the same thing indeed. Anyway I'll leave the answer for if anyone is actually looking for the language part alone. – Blizz Jun 03 '15 at 13:50
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

nacesprin
  • 392
  • 7
  • 16
1

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

  • 1
    Nice answer but it's better to use yii2-localeurls because it has a lot of features under hood and you don't need to implement existing features again... – Akmal Oct 28 '19 at 06:15
0

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

Swissdude
  • 3,486
  • 3
  • 35
  • 68
  • If you have a lot of urls like that you might want to fall back on a database or so by means of your own URL Rule, might become a very large list otherwise... – Blizz Jun 03 '15 at 13:47
  • indeed, but for my case, it's just about 3 or 4 URLs, that should be doable :) – Swissdude Jun 03 '15 at 13:52
  • Then you came up with the best solution yourself I guess :) – Blizz Jun 03 '15 at 13:56
0

For anyone who came to this question, see this package: Yii2 TranslatableUrlRule

because of not new commit for this package, use this fork of Mohamed Amer

or directly use this class and copy it to your components directory then do url rules like this:

In advanced project, I used it in common/components directory.

'rules' => [
            [
                'class' => 'common\components\TranslatableUrlRule',
                'patterns' => [
                    'ar' => 'مرحبا',
                    'en' => 'hi',
                    'en' => 'Hola',
                ],
                'route' => '/main/hi',
            ],
ttrasn
  • 4,322
  • 4
  • 26
  • 43