Yii2 - Make hyperlink to toggle between languages - php

Hello.
In Yii1.1 i could make an action in siteController and then using: Yii::app()->controller->createUrl('actionname', array('language'=>'new language to toggle'));
It was possible to me to create hiperlinks with CHTML in index file and when clicked those hiperlinks changed the entire tranlations of the website from Portuguese to other language and all way around.
Now i'm beginning with Yii2 and controller does not have createUrl() anymore. Also the other methods dont work that way. I tried run, runAction, tried with the Url:: class and nothing.
Also, in Yii2 making <?php echo Html::a('Portuguese', Yii::$app->language = "pt"); ?>
Doesn't do anything !!! When clicked the hyperlink does not change the language of the site.
Does anyone know how to create an hiperlink or some other way in Yii 2 that toggles completely the entire website language. I need to have two versions of this website -> English and Portuguese.
I need to perform like this -> when click in the english word it will translate to English, and when click the portuguese word it will change the site to Portuguese language.
Any Ideas ??
Many thanks in advance.
NEW EDIT TO THE QUESTION
I wrote this code in my siteController, and now the sites toggles languages, but only on second mouse click the toggle happens and the content is refreshed. Anybody knows why?
Here are my actions
public function beforeAction($action) {
if (Yii::$app->session->has('lang')) {
Yii::$app->language = Yii::$app->session->get('lang');
} else {
Yii::$app->language = 'us';
}
return parent::beforeAction($action);
}
public function actionLangus(){
Yii::$app->session->set('lang', 'us'); //or $_GET['lang']
return $this->render('index');
}
public function actionLangpt(){
Yii::$app->session->set('lang', 'pt'); //or $_GET['lang']
return $this->render('index');
}
I opted for render('index'), because redirect was not finding the view to display.
Many thanks for a solution...

You can do like below in Yii2:
\yii\helpers\Html::a('Change Language',\yii\helpers\Url::toRoute(['controller/action',['language'=>'NEW_LANGUAGE']]));
\yii\helpers\Html::a('Change Language',['controller/action',['language'=>'NEW_LANGUAGE']]);
Or:
use yii\helpers\Html;
use yii\helpers\Url;
Html::a('Change Language',Url::toRoute(['controller/action',['language'=>'NEW_LANGUAGE']]));
Html::a('Change Language',['controller/action',['language'=>'NEW_LANGUAGE']]);
Then, in your action, you need to do:
//validation
Yii::$app->language= "NEW_LANGIAGE";
// store current language using state or cookie or database
UPDATE
action code:
//please put some validation on $_GET['lang']
Yii::$app->session->set('lang', 'us'); //or $_GET['lang']
$this->redirect('controller/action'); // redirecting user to somewhere
Then in your controller's beforeAction:
public function beforeAction($action) {
if (Yii::$app->session->has('lang')) {
Yii::$app->language = Yii::$app->session->get('lang');
} else {
//or you may want to set lang session, this is just a sample
Yii::$app->language = 'us';
}
return parent::beforeAction($action);
}
By above code, in every action, it checks whether the language is set in session or not. If yes, it changes the language. If not, it sets language to us as default. In your change language action, it just sets the new language, which, is given from $_GET request, into the session. Then it redirects user to another page.
Please note that, this is just a suggestion, others might use different ways, such as creating a bootstrap component, using controller init() method, storing lang into cookie or database and so on.

Related

Best way to assign view variable depending on prefix in Cake PHP 3.x

In my default layout, I have a snippet that check if $this->fetch('noindex') is true. This allow me to don't index specific pages by adding $this->assign('noindex', true); in my views. But what I want, is assigning this variable to true, only when the prefix is admin. To this problem, I have found two solutions with one not working.
Solution 1: In the AppController
public function beforeRender(Event $event)
{
if($this->request->param('prefix') === 'admin'){
$this->set('noindex', true);
}
}
This way allow me to check the prefix, but I would have to do $this->assign('noindex', $noindex); in every views. So this is not a great solution.
Solution 2: In the AppView (not working)
In my AppView, I can assign variables for my layouts without having to do it in all views.
public function initialize()
{
$this->assign('noindex', true);
}
But I can't do it depending on the prefix.
Solution 3: A mix (not working)
In the doc, we can see the event list of the AppView, so I though I could use the two solutions to do something working. But nothings happen.. I think that this is not the way I should use these.
// In AppController
public function beforeRender(Event $event)
{
if($this->request->param('prefix') === 'admin'){
$this->set('noindex', true);
}
}
// In AppView
public function afterRender()
{
$this->assign('noindex', $noindex);
}
So what do you think is the best way to achieve this ?
I don't get the real problem you try to solve. I assume you want do to this:
if ($this->request->param('prefix') === 'admin'){
echo $this->Html->meta('robots', 'noindex, nofollow');
}
Either put this directly in the layout file or create a custom helper and put it in a method of it and call it
echo $this->MyHelper->conditionalNoFollow();
in your layout(s).
And by the way, assign doesn't set a variable but a blocks content. No idea if this is your intend or not.

CodeIgniter behaviour, constructors and routes

I am using CodeIgniter 2.0 for the first time to create a multilingual site where the home page contains a slide show. I am developing it on my laptop - localhost/website/.
I am using the routes.php file to specify which language function to call to set variables depending on the url with format http://localhost/website/language/page_id/some-page-title. Thus http://localhost/website/en/1/Home-Page gives the english page of page_id 1.
Routes file therefore has:
$route['default_controller'] = "content";
$route['en/(:num)/(:any)'] = "content/en/$1";
$route['de/(:num)/(:any)'] = "content/de/$1";
$route['es/(:num)/(:any)'] = "content/es/$1";
etc
An example of a language function (the en function) in the content controller is:
public function en ($page_id) {
$language="en";
$lang_array['css']="base.css";
$this->get_content($page_id, $lang_array);
}
The get_content function then does everything.
The index function of the content controller however looks like this:
public function index() {
//setting defaults for when arrive straight at home page or with no language in url
$page_id=1;
$lang_array['language']="en";
$lang_array['css']="base.css";
$this->get_content($page_id, $language);
}
My problem is that when I go to http;//localhost/website/ everything works fine including the slideshow. However, when i go to the url http://localhost/website/en/1/Home-Page everything works except the pictures in the slideshow dont appear (even though they are both executing the same code and the html output is the same when i look at view source on the page).
The only thing i could think of is the fact that if i just put http;//localhost/website/ then the index function will be called which activates the constructor, but if i put http://localhost/website/en/1/Home-Page then the index and thus constructor are bypassed. However dont know why therefore other things still work but pic slideshow doesn't. Is this the reason do you think? any solutions?
Thanks
TOm
What I could think is some sort of JavaScript error on an undefined variable, possible related to the $lang_array['language'] not being set.
In the index, you set the key to default to 'en',
public function index() {
//setting defaults for when arrive straight at home page or with no language in url
$page_id=1;
$lang_array['language']="en";
$lang_array['css']="base.css";
$this->get_content($page_id, $language);
}
but in the en method, you did not
public function en ($page_id) {
$language="en";
$lang_array['css']="base.css";
$this->get_content($page_id, $lang_array);
}
Since they look pretty much the same, you should abstract the identical behavior into a private function, or perhaps modify the route to send the language as a param to a single function.

Yii language control using behaviours how to prevent form resubmition dialog

I used this tutorial http://www.yiiframework.com/wiki/208/how-to-use-an-application-behavior-to-maintain-runtime-configuration/ to change language. But I ran into problem that $_Post['lang'] variable is not being reset and every time I try to refresh the page, It gives me form resubmition dialog, which I don't want to have. But I don't know where and how to use redirect, since it doesnt work in behaiours class. How can I prevent this form resubmition?
Edit: I found an ugly solution, to put this code in every view file that I have
<?php
$this->renderPartial('//lang/_refresh', array())
?>
But It involed repeating same code alot and I am sure there is a better solution out there (probably to place a refresh function in the right place)
Found a solution, all you need is to add a beforeAction to components/Controller since all added controllers extend it. The problem was I didn't know that. Here is the function that works so that I dont have to rewrite the code.
protected function beforeAction()
{
if (isset($_POST['lang'])) {
$this->refresh();
}
return true;
}

cakephp - callback function for every controller action to set available navigation links

I'm trying to achieve something so basic in my cakephp-app, that I'm quite surprised I didn't easily find a solution to it...
What I just want to do is to set available links for my app's main navigation depending on the user being logged in or not and if he is, depending on his role (which is stored in the users-table).
So basically a function like this:
if(!$this->request->is('ajax')) {
if(_user_is_not_logged_in_) {
$availableNavItems = array('login','help');
}
else {
if($this->Auth->User('role') == 'user') {
$availableNavItems = array('something','something else','whatever','help','logout');
}
elseif($this->Auth->User('role') == 'admin') {
$availableNavItems = array('something','something else','whatever','admin-tool','user management','help','logout');
}
}
// set available pages for layout
$this->set('availableNavItems',$availableNavItems);
}
In my layout of course I would create a navbar with links to those available pages.
The only question I have - where would I put code like the above? Is there any callback-function I could put in AppController which cakephp calls on every request?
And, what would be a good way to check what I wrote as pseudo-code "_user_is_not_logged_in_" above?
Thanks in advance for any help!
if(_user_is_not_logged_in_) {
could be written as
if(!$this->Auth->user('id')){
And you could put the function in your beforeRender method of your AppController, which executes on every request, right before the view is rendered.
Also of note is the beforeFilter method, which gets called early, before the controller logic executes. You shouldn't need it in this case, but it's worth knowing about.

Passing language as variable as url parameter in yii

i'm having a problem with yii which seems very simple but i can't find an appropriate solution for it. I need to do I18N in web page and i'm using yii, i have translations already done, i found that it's possible to easily change language in controller class like that:
class Controller extends CController
{
function init() {
parent::init();
if(isset($_GET['lang'])) {
Yii::app()->language = 'lt';
}
}
}
Everything is ok, but obviously the language parameter is lost when url doesn't contain the language parameter. One way around is adding the parameter in all urls across whole site, but that doesn't seem like a solution.
Is there some more static way of passing the parameter? Maybe some option in UrlManager in yii? Or maybe there is another way of changing the language more dynamically?
And what if you'll use session only when get-request is absent?
But it is still bad idea to show different content on the same url.
if(isset($_GET['lang'])) {
$app->session['language'] = 'lt';
} elseif($app->session->contains('language')) {
$app->language = $app->session['language'];
}
A very simple solution is to use session data to remember the user's language choice across pages:
function init() {
parent::init();
$app = Yii::app();
// If "lang" is specified, remember that
if(isset($_GET['lang'])) {
$app->session['language'] = 'lt';
}
// If we remember a language put it in use
if($app->session->contains('language')) {
$app->language = $app->session['language'];
}
}
You can easy add it as static param to url manager rules. I recommend using urls in form /en/controller/action etc, so first parameter is always language. I'm using this approach for long time and works like a charm.
For details check this answer: https://stackoverflow.com/a/4625710/133408

Categories