mcamara / laravel-localization

Easy localization for Laravel
MIT License
3.32k stars 507 forks source link

Translatable route parameters isn't work when wich language ? #885

Open ducvu91 opened 7 months ago

ducvu91 commented 7 months ago

Describe the bug Translatable route parameters http://url/en/article/important-change http://url/es/articulo/cambio-importante I setup like example, when access directly from url it ok. But when use button change language (also like example Creating a language selector). it show url 404. if not have parameters, it ok.

To Reproduce Steps to reproduce the behavior:

  1. Go to http://url/en/article/important-change
  2. Click on change language es button.
  3. auto redirect to http://url/es/article/important-change
  4. 404 & See error

Expected behavior when change language ES, it redirect to http://url/es/articulo/cambio-importante

More info:

it seems code in button change language have issue, it not generate to url belong to this language

mlayah commented 7 months ago

Did you get a fix for this, i am currently experiencing the same issue.

StefanoTesla commented 7 months ago

I had the same problem in the past, you didn't paste your controller middlware setting to go deeper in this problem

kichetof commented 7 months ago

Hi!

Same issue here, only the locale change in the url, nothing else. Language selector couldn't redirect to the translated route, only on index or without non dynamic text.

Example code:

Route::group([
    'prefix' => LaravelLocalization::setLocale(),
    'middleware' => ['localize', 'localizationRedirect', 'localeSessionRedirect'],
], function () {
    Route::get(LaravelLocalization::transRoute(__('/{user}/wish/{wish}')), WishIndexController::class);
});

fr.json

{
"/{user}/wish/{wish}": "/{user}/souhait/{wish}",
}

Selector EN: en/username/wish/my-x-mas-idea Selector FR: fr/username/wish/my-x-mas-idea ❌ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎^

Should be: Selector FR: fr/username/souhait/my-x-mas-idea ✅ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ^

Hopefully a fix or a workaround? 🤞🏻

StefanoTesla commented 7 months ago

I found the way to make it work finally!

I will write how on monday

StefanoTesla commented 7 months ago

So here I am.

Routes EN:

<?php

return [
    "prodotti_singoli"    =>  "products/{slug}",
];

Routes IT:

<?php

return [
    "prodotti_singoli"    =>  "prodotti/{slug}",
];

Web.php:

Route::get(LaravelLocalization::transRoute('routes.prodotti_singoli'),[ProductsController::class, 'show']);

Model Products:

<?php

namespace App\Models\Products;

class Product extends Model implements \Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable
{

 /* some methods */

    public function getLocalizedRouteKey($locale)
    {
        return $this->getTranslation('slug',$locale); <-methods to get other languages slug
    }

    public function resolveRouteBinding($value,  $field = null) <-methods to get the model by slug! (in the doc $filed is missing)
    {

        $field = $field ?? 'slug';
        $currentLocale = App()->getLocale();
        return $this->where("slug->{$currentLocale}", $value)->first() ?? abort(404);

    }

ProductController:


    public function show(Product $slug)
    {
        return view('product', compact('slug'));

    }

view:

<x-layouts.baselayout>
    <a rel="alternate" href="{{ LaravelLocalization::getLocalizedURL('en') }}">ENG</a>
    <a rel="alternate" href="{{ LaravelLocalization::getLocalizedURL('it') }}">ITA</a>
    <p>Nome: {{ $slug->name }}</p>
</x-layouts.baselayout>

Advisor: I'm using Mcamara to translate routes and spatie/laravle-translatable to get my site multilanguages.

My problem was find the way to overwrite the way as Laravel resolve the model url, and get the right "alternate" link.

First thing we need to care is the model shoud implement \Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable

❌❌❌❌❌❌ Worng way ❌❌❌❌❌❌

use \Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable;

class MyModel extend Model
   use LocalizedUrlRoutable

❌❌❌❌❌❌ Worng way ❌❌❌❌❌❌ You will get a fatal error where LocalizedUrlRoutable is not a trait. @mcamara we can do something?

✅✅✅✅✅ Correct Way ✅✅✅✅✅✅✅

class MyModel extend Model implement \Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable;
{

In the model we need olso two more methods, one is getLocalizedRouteKey

    public function getLocalizedRouteKey($locale)
    {
        return $this->getTranslation('slug',$locale);
    }

This metods is called when we call LaravelLocalization::getLocalizedURL('en') or any others locale, in my example is the way how I can get the translated version of the slug using spatie/laravel-translatable feel free to write your correct way.

And the laravel provided method resolveRouteBinding()

Always in the method we need to add this:

    public function resolveRouteBinding($value,  $field = null)
    {
        $field = $field ?? 'slug';
        $currentLocale = App()->getLocale();
        return $this->where("slug->{$currentLocale}", $value)->first() ?? abort(404);

    }

This method will be called from the controller to get the right model,

<?php

namespace App\Http\Controllers;

use App\Models\Products\Product;

class ProductsController extends Controller
{
    public function show(Product $slug)
    {
        return view('product', compact('slug'));
    }

But we need to do some consideration before, The controller method should have the the Model as input parameter, the variable should be named as the model column we want to find.

You can put a dd() inside the resolveRouteBinding to ensure that is fired.

StefanoTesla commented 7 months ago

The problem noy is how to get two nested dynamics url :(

fxcjahid commented 1 month ago

I see

class ProductsController extends Controller {

        public function show(Product $slug)
        {
            return view('product', compact('slug'));
        }

 }

if we can't use it like this then the transable file is not translated

well, In case it is resolved. But, I am looking for like this :

        public function show($slug)
        {
            return Product::findBySlug($slug);
        }

Anyone can give me a solution how can I solve this?

fxcjahid commented 1 month ago

@mcamara Pls feedback