how to create a switch language in Laravel? - php

I'm having a problem to build a translation switcher, this is what I have already did:
Step 1 : I have prefixed all the routes with the locale parameter {languge}
Route::redirect('/', '/en');
Route::group(['prefix' => '{language}'], function () {
//products routes
Route::get('/', 'ProductController#index' )->name('acceuil');
Route::get('/boutique/{slug}', 'ProductController#show' )->name('product.show');
Route::get('/search', 'ProductController#search' )->name('product.search');
});
step 2: then I created a middleware for setting the language of app depending on the request
public function handle($request, Closure $next)
{
App::setLocale($request->language);
return $next($request);
}
step 3: here I added Locale parameter {languge} to All Existing Links, like this:
<form method="POST" action="{{ route('register', app()->getLocale()) }}">
right here everything is fine but:
here I want to create a language switcher, this is what I did:
step 4: here I added Locale parameter {languge}to All Existing Links, like this:
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
{{ _('language') }}<span class="caret"></span>
<ul class="dropdown-menu">
<li>{{ _('Francais') }}</li>
<li role="separator" class="divider"></li>
<li>{{ _('anglais') }}</li>
</ul>
</li>
</ul>
The problem is that I have different routes, some of them require a parameters and then Step 4 doesn't work:
ANY ideas ?

This seems to work for me:
{{ route(Route::currentRouteName(), array_merge(['fr'], array_slice(($rp = Route::current()->parameters()), 1, count($rp)))) }}
First we need to array_slice the old language from the parameters then we can merge them with the new language. Since we merge the language with the current parameters, the order will always give us the language first and subsequent ordering of the current parameters.

Related

Laravel Language changer

I add localization to my laravel app. I define language in my routes.
Route::group(['prefix' => '{language}/tender', 'middleware' => ['permission:tender-page']], function () {
Route::get('/', 'TenderController#index')->name('tender');
Route::get('/add', 'TenderController#add')->name('tender_add');
Route::get('/{id}', 'TenderController#detail')->name('tender_detail');
});
I try to change languages by this way
<li class="nav-item">
RU
</li>
<li class="nav-item">
TR
</li>
but if i use this way, this kind of routes Route::get('/{id}', 'TenderController#detail')->name('tender_detail'); got error.
How can realize language changer?
You need to pass the {id} parameter again.
{{ route(Route::currentRouteName(), ['language' => 'ru', 'id' => $tender_id]) }}
You need to get your current route parameters and override the {language}. You can accomplish this by getting the current route's parameter array with Route::current()->parameters() and then using array_merge to override the language.
{{ route(Route::currentRouteName(), array_merge(Route::current()->parameters(), ['language' => 'ru']) ) }}

Laravel - manual rendering of breadcrumbs

I'm using Laravel 5.2 and I would like to use breadcrumbs by davejamesmiller. I have set route Route::resource('admin/users', '\Easyk\Controllers\Admin\UsersController'); and according documentation created file Http/breadcrumbs.php where content is:
Breadcrumbs::register('admin.users.index', function ($breadcrumbs) {
$breadcrumbs->push('Users', route('admin.users.index'));
});
When I try in template {!! Breadcrumbs::render() !!} then it will render without problem. But I would like to render it manualy. According documentation I created file config/breadcrumbs.php with content:
return [
'view' => 'partials/_breadcrumbs',
];
but when I try to render it there is no $breadcrumbs variable:
#if(!empty($breadcrumbs))
<ol class="breadcrumb">
<li>{!! link_to_route('main', 'Home') !!}</li>
#foreach($breadcrumbs as $bread)
#if(isset($bread['url']))
<li>{!! link_to($bread['url'], $bread['name']) !!}</li>
#else
<li>{!! $bread['name'] !!}</li>
#endif
#endforeach
</ol>
#endif
Do you have any experience how to get $breadcrumbs variable to the view specified in file?
I already solved it. In layout I need {!! Breadcrumbs::renderIfExists() !!} and then in partials/_breadcrumbs I will get $breadcrumbs variable. If I get it right then method renderIfExists() works as include.
Also in config/breadcrumbs.php must be dot convention:
return [
'view' => 'partials._breadcrumbs',
];

Laravel get current route

I have some navigation links and I want to get the current route in laravel 5 so that I can use the class active in my navigations. Here are the sample links:
<li class="active"> Home </li>
<li> Contact </li>
<li> About </li>
As you can see, in the Home link there is the active class which means that it is the current selected route. But since I am using laravel blade so that I would not repeat every navigation links in my blades, I can't use the active class because I only have the navigation links in my template.blade.php. How can I possibly get the current route and check if it is equal to the current link? Thank you in advance.
$uri = Request::path()
Check out the docs
You can use named routes like
Route::get('/', ['as'=>'home', 'uses'=>'PagesController#index']);
and then in the view you can do the following
<li {!! (Route::is('home') ? 'class="active"' : '') !!}>
{!! link_to_route('home', 'Home') !!}
</li>
So I got it working with some little tricks. For example the url in the address bar is http://localhost:8000/tourism/places.
If I will use the Request::path() method, I will get tourism/places. But what I wanted to get is the tourism part only so what I did is this:
$currentPath = Request::path();
$values = explode("/", $currentPath);
$final = $values[0];
Now the $final variable will have the value "tourism".
Now to make the variable load globally, I included the code in the AppServiceProvider.php inside the public function boot().
public function boot()
{
$currentPath = Request::path();
$values = explode("/", $currentPath);
$final = $values[0];
view()->share('final', $final);
}
And lastly in my blade template,
<li #if ($final== "tourism") class="active" #endif>
Places
</li>
Simple way is always better, just use the same function you use to generate links and it will give you all, including the flexibility to use wild cards
<a class="nav-link {{ Request::url() === route("products.list", [$group_key]) ? 'active' : '' }}"
href="{{ route("products.list", [$group_key]) }}"
>
LInk text
</a>
Plus, you still are going to have only one place to manage URL-s - your router files.

blade templates recursive includes

I have an array of items that represent the file and dir structure of a directory on the server.
The $items array is constructed like this:
Array
(
[folder1] => Array
(
[folder1_1] => Array
(
[0] => filenameX.txt
[1] => filenameY.txt
)
)
[pages] => Array
(
)
[0] => filename.txt
[1] => filename1.txt
)
what we want, is essentially <ul> with <li> for every node.
the resulting HTML should be something like
folder1/
folder1_1/
filenameX.txt
filenameY.txt
pages/
filename_1.txt
filename_2.txt
Now, my question has to do with nested includes with laravel's blade templating engine.
I have a view list.blade.php with the following contents
<div class="listing">
#include('submenu', array('items', $items))
</div>
and I pass it the array like this:
View::make('list')->with('items', $items)
the included template (submenu.blade.php) has the following:
<ul>
#foreach($items as $key=>$value)
#if (is_array($value))
<li>{{$key}}/
#include('submenu', array('items', $value))
</li>
#else
<li>{{$value}}</li>
#endif
#endforeach
</ul>
I #include the same template from within itself but with the new data, in case the $value is an array (directory)
First of all, is this at all possible?
If not, is there another way to achive the desired result?
TIA,
Yes, this is indeed possible.
However, there's an issue in your includes, you have:
#include('submenu', array('items', $value))
It should be:
#include('submenu', array('items' => $value))
It's worth noting also another hidden blade statment, #each. You can use this instead of looping through the array yourself, something like this:
<ul>
#each('item.detail', $items, 'item')
</ul>
Then you create a new blade file named item.detail and pop what you previously had in your loop in that file. It helps to clean up your view from having more and more nested loops.
The data for the item when you are inside your new blade file will be held in the third parameter, in this case $item
Instead of using array, use an eloquent collection. Instead of using #include, use \View::make. It cleans up the code a bit. Here is an example drop down menu for the Foundation 5 framework, using an eloquent model with parent/child relationship:
My model has a parent->child relationship
public function children() {
return $this->hasMany('Category', 'parent_id');
}
I generate my results like so in my controller
$categories = \Category::where('parent_id', '=', '0')->with('children')->get();
Blade template: _partials.dd-menu.blade.php
<ul class="{{$class}}">
#foreach($items as $item)
<?php
$active = $item->id == \Input::get('category') ? 'active' : '';
$hdd = $item->children->count() ? 'has-dropdown' : '';
?>
<li class="{{$hdd}} {{$active}}">
{{$item->name}}
#if ($item->children->count())
{{ View::make('_partials.dd-menu')->withItems($item->children)->withClass('dropdown')}}
#endif
</li>
#endforeach
In your parent blade:
<nav class="top-bar" data-topbar role="navigation">
<ul class="title-area">
<li class="name">
<h1>Categories</h1>
</li>
<!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone -->
<li class="toggle-topbar menu-icon"><span>Menu</span></li>
</ul>
<section class="top-bar-section">
<!-- Right Nav Section -->
{{ View::make('_partials.dd-menu')->withItems($categories)->withClass('right')}}
</section>
</nav>

Passing default data for a controller in Laravel

I want to build a menu from an array in Laravel. What I'm currently doing is putting the array in a view
$menu = ['home', 'users' => ['create users' , 'update user', 'activity log']];
and then looping through it to generate the menu:
<section>
<!-- Left Nav Section -->
<ul class="left">
<li class="divider"></li>
#foreach($menu as $key => $nav)
<li class="has-dropdown">
{{ $key }}
<ul class="dropdown">
#foreach($nav as $subnav)
<li>
{{ $subnav }}
</li>
#endforeach
</ul>
</li>
#endforeach
</ul>
</section>
Is there any other way that I can achieve the same result without putting the data in the view?
I also tried creating a constructor function in the controller:
public function __construct() {
$menu = ['home', 'users' => ['create users' , 'update user', 'activity log']];
return $menu;
}
But I guess that is not how it works. I appreciate any ideas on how I can go about this. Thanks in advance
View composers to the rescue!
They are executed every time before a view is rendered, so you can use this to pass standard data to them.
If you're using controller layouts you can bind data to the layout from within the constructor. Just make sure you call the parent constructor first so that the layout is instantiated properly.
public function __construct()
{
parent::__construct();
$this->layout->menu = ['home', 'users' => ['create users' , 'update user', 'activity log']];
}
That will bind a $menu variable to the layout, and will also be available to any nested views that are used with Blades #include.
Have a look at view composers:
http://www.laravel.com/docs/views#view-composers

Categories