I'm trying to implement a multilanguage laravel 4 website, with language code in the url ( mywebsite.com/en/home and mywebsite.com/de/home )
I've seen a couple of options like filtering all requests and checking if the first param is one of the language code.
I've also check on packagist but haven't find something that already do tee job.
Is there a better way to implement it?
Thank you
Finally, I've create a config variable in config/app.php
'available_language' => array('en', 'fr', 'es'),
In filters.php I detect the browser language:
Route::filter('detectLang', function($lang = "auto")
{
if($lang != "auto" && in_array($lang , Config::get('app.available_language')))
{
Config::set('app.locale', $lang);
}else{
$browser_lang = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? strtok(strip_tags($_SERVER['HTTP_ACCEPT_LANGUAGE']), ',') : '';
$browser_lang = substr($browser_lang, 0,2);
$userLang = (in_array($browser_lang, Config::get('app.available_language'))) ? $browser_lang : Config::get('app.locale');
Config::set('app.locale', $userLang);
}
});
and then in routes.php I can either detect the language or force it:
Route::get('/', array(
'before' => 'detectLang()', // auto-detect language
function(){
...
})
);
or
Route::get('/', array(
'before' => 'detectLang("fr")', // force language to "fe"
function(){
...
})
);
You could set a language variable in the user session.
Then use a 'before' filter, and view that variable, and log the correct language file.
If there is no variable set - then use a default (perhaps based upon their IP location).
Related
Is it possible to put an optional parameter before a required one?
I am trying to create a multilingual web application using laravel 5, if the user didnt specify the language in URL, the default language is used:
http://localhost/localizationtest/public/es/test/4
how can i make this URL works: http://localhost/localizationtest/public/test/4
my routes.php:
Route::group(array('prefix' => '{lang?}/test'), function($lang = null)
{
Route::get('{id}', function($lang = null, $id) {
App::setlocale($lang);
return view('lang_test')->with('id', $id);
});
});
one more question: is it possible to put the id this way: /test4 instead of /test/4 ?
Why don't you declare an explicit route for it?
Route::get('/test/{id}', function($id) {
App::setlocale('es');
return view('lang_test')->with('id', $id);
});
To answer your other question - yes you can change the wildcard so that its that way. (remove the '/').
My code in laravel to handle multiple language is:
$languages = array('it-IT','en-GB','fr-FR');
$lingua = Request::segment(1);
if(in_array($lingua, $languages)){
\App::setLocale($lingua);
}else{
$lingua = 'it-IT';
}
Route::group(array('prefix' => $lingua), function()
{
Route::get('/', array('as' => 'home', 'uses' => 'ItemController#menu'));
Route::get('/{idcampo}','ItemController#show');
});
How can i:
1)Make the page start always with it-IT as default. (i need it because I use $lingua to fetch from a database) so i can't have that null. Should I use a redirect::to / to /it-IT?
2) change url and language(app:locale) on he fly with a link in the upper section of every pages. withouth returning to the home.
3) to link pages I learn to use:
URL::route('home')
but how to do it when the link change with the entry of a database (for example my link is {{ URL::to($lingua. '/'. $campo[1].'/') }}) I need to use
URL::action('ItemController#show', ($lingua. '/'. $campo[1].'/'))
EDIT:
OK at the top of my pages there is a link to change language on the fly.
Italian //
English //
French
I create a controller clled LanguageController
<?php
class LanguageController extends BaseController {
public function select($lingua)
{
// Store the current language in the session
Session::put('lingua', $lingua);
return Redirect::back(); // redirect to the same page, nothing changes, just the language
}
}
I create a route:
Route::get('lingua/{lingua}', 'LanguageController#select');
Route::get('/', array('as' => 'home', 'uses' => 'ItemController#menu'));
Route::get('/mondo/','ItemController#mondo');
Route::get('/{idcampo}','ItemController#show');
I have my ItemController#menu
public function menu()
{ $linguadefault='it-IT';
$lingua = Session::get('lingua',$linguadefault);
$data = DB::table('campo')->lists('id');
return View::make('index')->with('campo',$data)->with('lingua',$lingua);
}
1) I don't understand why i need to route at lingua/{lingua} if i never route there but i use a url:action to a controller directly.
2) now i need to add
$linguadefault='it-IT';
$lingua = Session::get('lingua',$linguadefault);
at the beginning of every function to have a lingua variable in my page right?
3) now my language seems stucked to french and i can't change it anymore.
I would not use the language in the URL all the time, you can just switch languages when you need and persist it:
1) Use Session to persist the language chosen:
// Set the default language to the current user language
// If user is not logged, defaults to Italian
$linguaDefault = Auth::check()
? Auth::user()->lingua
: 'it-IT';
/// If not stored in Session, current language will be the default one
\App::setLocale(Session::get('lingua', $linguaDefault));
To have the language always set in your application, you can put this code in your file
app/start/global.php
And you don't need to add this anywhere else. So it will use it in this order:
a) Language stored in Session (selected online)
b) Language user has in database
c) Italian
2) To change the language you create a route:
Route::get('lingua/{lang}', 'LanguageController#select');
Your links
URL::action('LanguageController#select', 'it-IT')
URL::action('LanguageController#select', 'en-GB')
URL::action('LanguageController#select', 'fr-FR');
And in your controller you just have to do:
public function select($lang)
{
// Store the current language in the session
Session::put('lingua', $lang);
return Redirect::back(); // redirect to the same page, nothing changes, just the language
}
3) This way you don't need your language in all your URLs, you don't have to deal with it in all your routes. If your user changes the language in database, you just:
$user->save();
Session::put('lingua', $user->lingua);
return Redirect::route('home'); // or anything else
Hy i have this http://laravel.io/bin/jaPB
The problem is when i go to:
domain.com -> it serves the homepage (wich is ok)
domain.com/foo -> it serves a subpage (still ok)
but when i go from one of those to:
domain.com/en -> it gives an error (not ok)
But after hitting refresh its ok.
So again when i'm on domain.com/en first time error after refresh ok
Same goes to subpage like domain.com/en/contact first time error after refresh ok
I would point out that the error says first time it tries to go to PublicPageController#subpage
but this shouldn't happen when i go to domain.com/en it should need to go to PublicPageController#homepage
Any idea ?
Thank you all.
My guess here form looking at the way you set up the locale-based routes is that the Session::get('urilang) isn't set the first time you visit, hence the error, and is only set once you've been to a page first.
Now, I haven't yet had to deal with multilingual sites, but as far as I'm aware the way you're doing it is not the correct way. Instead think of the lang key as a URI parameter, and use the filter to validate and set it for the routes. Something a bit like the below code:
// Main and subpage - not default language
Route::group(array('prefix' => '{lang}', 'before' => 'detectLanguage'), function () {
Route::get('', 'PublicPage#homepage');
Route::get('{slug}', 'PublicPage#subpage');
});
// Main and subpage - default language
Route::group(array('before' => 'setDefaultLanguage'), function () {
Route::get('/', 'PublicPage#homepage');
Route::get('/{slug}', 'PublicPage#subpage');
});
Route::filter('detectLanguage', function($route, $request, $response, $value){
// hopefully we could do something here with our named route parameter "lang" - not really on sure the details though
// set default
$locale = 'hu';
$lang = '';
// The 'en' -> would come from db and if there is more i would of corse use in array
if (Request::segment(1) == 'en')
{
$lang = 'en';
$locale = 'en';
}
App::setLocale($locale);
Session::put('uriLang', $lang);
Session::put('locale', $locale);
});
Route::filter('setDefaultLanguage', function($route, $request, $response, $value){
App::setLocale('hu');
Session::put('uriLang', '');
Session::put('locale', 'hu');
});
I don't know if you can use a segment variable in a Route::group prefix, but you should certainly have a go at it as it'd be the most useful.
That said, I wouldn't advise setting up default language routes that mimic specific language routes but without the language segment. If I were you, I'd set up a special root route that will redirect to /{defaultlang}/ just so you have fewer routing issues.
My question is: How can I leave the Frozennode administrator runs normaly on Laravel Maintenance Mode?
This is what I got in global.php
App::down(function()
{
return Response::view('maintenance', array(), 503);
});
Thanks!
I've dug in the core, there's no way you can do it. Laravel checks for a file named down in app/storage/meta folder, if it's there, Laravel won't even call the routes, it'll just show the error page.
This is isDownForMaintenance function from laravel:
public function isDownForMaintenance()
{
return file_exists($this['path.storage'].'/meta/down');
}
There's no configuration possible.
An alternative way to the laravelish "maintenance mode" is to set a new value in config/app.php, add:
'maintenance' => true,
Then add this to your before filter:
App::before(function($request)
{
if(
Config::get('app.maintenance') &&
Request::segment(1) != 'admin' // This will work for all admin routes
// Other exception URLs
)
return Response::make(View::make('hello'), 503);
});
And then just set :
'maintenance' => true,
To go back to normal mode
There is actually another way, more straightforward. As you can read in Laravel documentation, returning NULL from closure will make Laravel ignore particular request:
If the Closure passed to the down method returns NULL, maintenance mode will be ignored for that request.
So for routes beginning with admin, you can do something like this:
App::down(function()
{
// requests beginning with 'admin' will bypass 'down' mode
if(Request::is('admin*')) {
return null;
}
// all other routes: default 'down' response
return Response::view('maintenance', array(), 503);
});
I'm trying to set up sub-domain based routing in Laravel 4 and I've hit a bit of an annoyance...
My route group looks like this:
Route::group(array('domain' => '{company}.domain.com'), function() {
// ...
});
Which seems to work fine, however, I need to specify the company parameter for every route/url I generate. I.e:
{{ HTML::linkRoute('logout', 'Logout', ['company' => Input::get('company')]) }}
Is there any way to specify the company parameter as static/global, so it is automatically added to any links I specify, unless otherwise overwritten/removed?
Unfortunately, no (I haven't seen any evidence in the router or HTMLBuilder that you can). You could, however, make an HTML macro... Example:
HTML::macro('lr', function($link, $title) {
$company = !empty(Input::get('company')) ? Input::get('company') : "";
return HTML::linkRoute($link, $title, ['company' => $company]);
});
Then call it - instead of HTML::linkRoute, use HTML::lr('logout', 'Logout')
Just an idea.