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?
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.
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
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
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