10

Is there a way to create routes with prefixes so I can have routes like this

/articles.html -> goes to listing  Controller in default language
/en/articles.html -> goes to the same controller
/fr/articles.html -> goes to the same controller

My current problem is that by doing:

Route::group(['prefix=>'/{$lang?}/',function(){});

a route like this: /authors/author-100.html will match a prefix 'authors` , and for sure there is no language called "authors".

I use laravel 5.5

user237329
  • 809
  • 1
  • 10
  • 27

4 Answers4

10

There doesn't seem to be any good way to have optional prefixes as the group prefix approach with an "optional" regex marker doesn't work. However it is possible to declare a Closure with all your routes and add that once with the prefix and once without:

$optionalLanguageRoutes = function() {
    // add routes here
}

// Add routes with lang-prefix
Route::group(
    ['prefix' => '/{lang}/', 'where' => ['lang' => 'fr|en']],
    $optionalLanguageRoutes
);

// Add routes without prefix
$optionalLanguageRoutes();
edruid
  • 693
  • 4
  • 14
  • This solution worked beautifully to quickly retrofit a version prefix to my API routes. It will duplicate the route table, so there might be some performance loss, but I didn't really notice. – Jeroen de Lau Dec 10 '20 at 02:54
9

This should be sufficient using the where Regex match on the optional route parameter:

Route::get('/{lang?}, 'SameController@doMagic')->where('lang', 'en|fr');

You can do the same on Route Group as well, else having all the options as in this answer evidently works.

An update to show the use of prefix:

Route::group(['prefix' => '{lang?}', 'where' => ['lang' => 'en|fr']],function (){
    Route::get('', 'SameController@doNinja');
});

As far as I am concerned this should be sufficient even when there is no lang as well as when there is one, just maybe this group could come before other routes.

  • My question was about prefix. Your solutions would mean to add lang rule for each route – user237329 Sep 04 '17 at 20:51
  • 1
    Hi, with the above it means when the optional variable is there it has to be 'en' or 'fr' but when it is NOT there then the condition is not executed hence it works without passing anything – Oluwatobi Samuel Omisakin Sep 05 '17 at 08:33
  • ah okay pardon me, but you can use the same idea for prefixing a route group. I'll edit my question to see if I can make it clearer – Oluwatobi Samuel Omisakin Sep 05 '17 at 08:36
  • True. This way works. I wasn't awere of where options as array key, and where method on group is not allowed. Still it remains a problem with optional prefix. For example: /aboutus.html would not match your group, because somewhere in routing it will try to match with a regexp like this : /^/(en|fr)/aboutus.html): double "/". I tried "|en|fr", but the problem would be again that "//" – user237329 Sep 05 '17 at 09:11
  • Yes. I will dig more – user237329 Sep 05 '17 at 10:20
  • 1
    {lang?} Question mark fix my issue for optional language in url – Muhammad Shahzad Oct 24 '21 at 06:51
1

You can use a table to define the accepted languages and then:

Route::group([
    'prefix' => '/{lang?}',
    'where' => ['lang' => 'exists:languages,short_name'],
], function() {

    // Define Routes Here
});
aaron0207
  • 2,293
  • 1
  • 17
  • 24
  • Tx. Partially is working: it works constraining with smth like this: `'lang' => '|en|fr'`, but it won't work with the optional – user237329 Sep 05 '17 at 06:52
1

Another working solution would be to create an array of langs and loop over it:

$langs = ['en', 'fr', ''];

foreach($langs as $lang) {
  Route::get($lang . "/articles", "SomeController@someMethod");
}

For sure this makes your route file less readable, however you may use php artisan route:list to clearly list your routes.

Yezan Rafed
  • 532
  • 5
  • 15