codezero-be / laravel-localized-routes

⭐️ A convenient way to set up and use localized routes in a Laravel app.
MIT License
505 stars 46 forks source link

Dynamic route #28

Closed NadjmanDev closed 4 years ago

NadjmanDev commented 4 years ago

Hi,

I'm trying to access other locales for exemple localhost.com/fr but it always returning page route

i want to have this :

localhost.com/{slug} localhost.com/fr/{slug} localhost.com/pt/{slug}

my config : // localized-routes.php

return [

    'supported-locales' => ['en', 'fr', 'pt'],

    'omit_url_prefix_for_locale' => 'en',

    'use_locale_middleware' => true,

    'use_localizer' => false,

];

// web.php

Route::localized(function () {

            Route::get('/', 'Root\IndexController@index')->name('index');

            Route::get('/{slug}', function ($slug) {
                return Page::where('slug', $slug)->first();
            })->name('page');

});

Thanks for your work

ivanvermeyen commented 4 years ago

Hello,

The / route needs to get the active locale from the session, which is done by Localizer. So I think it should work when you set use_localizer to true.

kasparrov commented 4 years ago

have the same issue with or without localizer tried:

Route::localized(function () {
    Route::get('/', 'PageController@renderIndex');
    Route::get('{page}', 'PageController@render');
});

and

Route::localized(function () {    
     Route::get('{page}', 'PageController@render')->where('page', '.*');
});
NadjmanDev commented 4 years ago

Hi, I think i found the solution. In the config file ( localized-routes.php ), if your omit_url_prefix_for_locale is set to en so in supported-locales you have to add en in the last postition like this example below.

return [

    'supported-locales' => ['pt', 'fr', 'en'],

    'omit_url_prefix_for_locale' => 'en',

    'use_locale_middleware' => true,

    'use_localizer' => false,

];

I hope it helps you

ivanvermeyen commented 4 years ago

Hi,

I was able to reproduce it in a test. It seems the routes are being registered like this:

  #items: array:4 [
    0 => "/"
    1 => "{slug}"
    2 => "nl"
    3 => "nl/{slug}"
  ]

So in this case /nl can not be accessed. The {slug} intercepts it. Looking into it now. 👍

kasparrov commented 4 years ago

yep, i have the same route registration sequence. Sorry to not attach it before. Thx for a fast responce!

ivanvermeyen commented 4 years ago

@NadjmanDev moving the omitted locale to the end seems like the best solution, thanks 👍 Will tag it when tests completed.

ivanvermeyen commented 4 years ago

Fix has been tagged in 2.2.7 👍

kasparrov commented 4 years ago

moving the omitted locale works only when you register the same route twice(for root and for anything else)

Route::localized(function () {
    Route::get('/', 'PageController@renderIndex');
    Route::get('{page}', 'PageController@render');
});

and doesnt work when i tried

Route::localized(function () {    
     Route::get('{page}', 'PageController@render')->where('page', '.*');
});

checked with 2.2.7 tag

ivanvermeyen commented 4 years ago

What is the behavior you see?

I don't immediately see why it would make any difference. (but then again it is confusing) :)

kasparrov commented 4 years ago

I created draft project with 3 route groups(api,admin, web) at web section i have only

Route::localized(function () {
    Route::get('{page}', 'PageController@render')->where('page', '.*');
});

definition for render function:

public function render(Request $request, $page = null)

config:

'supported-locales' => ['be','en','ru'],
'omit_url_prefix_for_locale' => 'ru',
'use_locale_middleware' => true,
'use_localizer' => false,

roule list:

 POST     | admin/api/token |      |
 GET|HEAD | api/test        |      |
 GET|HEAD | be/{page}       | be.  |
 GET|HEAD | en/{page}       | en.  |
 GET|HEAD | {page}          | ru.  |

with this config domain.com/ - get page variable value null domain.com/en - get page variable value "en" domain.com/be - get page variable value "be" domain.com/ololo - get page variable value "ololo" domain.com/en/ololo - get page variable value "ololo" domain.com/be/ololo - get page variable value "ololo"

workaround - change routes to:

Route::localized(function () {
    Route::get('/', 'PageController@render');
    Route::get('{page}', 'PageController@render')->where('page', '.*');
});
ivanvermeyen commented 4 years ago

This test passes for me. Notice the {slug?} placeholder. Does this solve your use case?

/** @test */
public function it_registers_a_dynamic_root_route_without_prefix_for_a_configured_main_locale()
{
    $this->setSupportedLocales(['en', 'nl']);
    $this->setOmitUrlPrefixForLocale('en');
    $this->setUseLocaleMiddleware(true);

    Route::localized(function () {
        Route::get('{slug?}', function ($slug = null) {
            return ($slug ?? 'null') . ' ' . App::getLocale();
         })->where('page', '.*');
    });

    $this->assertEquals(
        ['nl/{slug?}', '{slug?}'],
        $this->getRoutes()->pluck('uri')->toArray()
    );

    $response = $this->call('GET', '/');
    $response->assertOk();
    $this->assertEquals('null en', $response->original);

    $response = $this->call('GET', '/nl');
    $response->assertOk();
    $this->assertEquals('null nl', $response->original);

    $response = $this->call('GET', '/dynamic');
    $response->assertOk();
    $this->assertEquals('dynamic en', $response->original);

    $response = $this->call('GET', '/nl/dynamic');
    $response->assertOk();
    $this->assertEquals('dynamic nl', $response->original);
}
kasparrov commented 4 years ago

{slug?} done the trick, thx a lot!