Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

fantasma's avatar

Translate URL Slug

I'm using Laravel 5.6 and trying to sort out what's the best method to translate a route.

I use the top level domain to sort the locale so

mydomain.pt -> locale pt

mydomain.es -> locale es

mydomain.com -> locale en

I created a middleware to handle this

class Language
{

    public function handle($request, Closure $next)
    {
        $url_array = explode('.', parse_url($request->url(), PHP_URL_HOST));
        $top_domain = end($url_array);

        if(!empty($top_domain)){
            App::setLocale($top_domain);
        }
    }
}

This is working fine and the translated strings within the respective files work when i switch domain.

However i want to be able, for SEO purposes, to have links like this

mydomain.pt/dynamic/perto-de-mim

mydomain.es/dynamic/cerca-de-mi

mydomain.com/dynamic/near-me

What's the best approach in laravel to get my route

Route::get('{category}/near-me/', 'ServicesController@nearMe');

To work with all the examples above?

I've already tried something like

Route::middleware(['language'])->group(function () {
    // dd(trans('routes.near-me'));
    Route::get(__('routes.near-me'), 'ServicesController@nearMe')
         ->where(['limit' => '[0-9]*'])->name('near-me');
 });

But, still, no luck

0 likes
8 replies
lostdreamer_nl's avatar

Using route::bind you could change the way {category} would be resolved according to the language setting (depending how your translations are handled).

    Route::bind('category', function ($categorySlug) {
    $locale = App::getLocale();
    // Do some query to get the category according to the locale
        return App\Category::where('translated_'. $locale, $categorySlug)->firstOrFail();
    });

https://laravel.com/docs/5.6/routing#explicit-binding (Customizing The Resolution Logic)

fantasma's avatar

@lostdreamer_nl , thank you for your response

It's not the category I want to localize, but the "near-me" string.

mydomain.pt/dynamic/perto-de-mim

mydomain.es/dynamic/cerca-de-mi

mydomain.com/dynamic/near-me

lostdreamer_nl's avatar

Aah ok,

I've done the same once and if I can remember correctly I was simply able to use the trans() helper inside the routes file.

The only difference was that I had my middleware running on all requests instead of having it on a group inside the route file itself.

Try adding the Language middleware in "app/Http/Kernel.php"

protected $middleware = [
    'App\Http\Middleware\Language',
....
....
];

After that I think your last attempt should work

Sergiu17's avatar

I work on a project, and this is the way I solved your problem.

Let's say we work with Posts. So, I've created 2 Models Post and PostTranslation, 2 migrations create_posts_table and create_posts_translation_table, single controller PostsController, and a Model, a Controller and a migration for Language

create_posts_table.php

Schema::create('posts', function (Blueprint $table) {
    $table->engine = 'InnoDB';

    $table->increments('id');
    $table->timestamps();
});

create_posts_translation_table.php

Schema::create('posts', function (Blueprint $table) {
    $table->engine = 'InnoDB';

    $table->increments('id');
    $table->unsignedInteger('lang_id'); 
    $table->unsignedInteger('post_id');
    $table->string('title');
    $table->text('body');
    $table->string('slug');
    $table->timestamps();

    $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
    $table->foreign('lang_id')->references('id')->on('lang')->onDelete('cascade');
});

Post.php

<?php

class Post extends Model
{
    public function translation()
    {
        $lang = Language::where('language', session('applocale'))->first()->id ?? Language::first()->id;

        return $this->hasMany(PostTranslation::class)->where('lang_id', $lang);
    }
}

So, when you write

Post::with('translation')->get();

you get all posts where lang_id is session('applocale') or Language::first()->id

The key here is slug form posts_translation_table :)

And in your create_posts_migration you could add Image or tag_id or category_id

Not sure if it's the best way to do it..

If someone knows other way to do this, please help))

fantasma's avatar

@Sergiu17 Thanks for your suggestion, but in my case, having a table for each model translated seems a bit unscalable for me

@lostdreamer_nl I've done precisely that. The thing is, if I do

dd(App::getLocale());

on my routes/web.php I always get the default locale, and not the one I've setted in the middleware. What I think is, that the routes are running before middleware, and therefore the locale is not being setted properly

lostdreamer_nl's avatar

In that case, add the routes from the RouteServiceProvider

Do the whole check you're now doing in your service provider (using Route::getCurrentRequest()->url() ).

And add the correct routes/lang/{language}.php files from there.

ofat's avatar

Please checkout my package - ofat/laravel-translatable-routes

I made it specially for this purposes

Čamo's avatar

This is solution from today. Its middleware which translates url segments to the router valid segments and create new Request object without redirect.

Please or to participate in this conversation.