Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translatable Routes Fail When Using Customizing the Key for translatable parameters #924

Open
iwasherefirst2 opened this issue Dec 17, 2024 · 1 comment

Comments

@iwasherefirst2
Copy link
Collaborator

iwasherefirst2 commented Dec 17, 2024

In a fresh Laravel 11 application using LaravelLocalization, translatable routes work as expected with:

  • Multiple parameters
  • Route Model Binding (including getRouteKeyName overwrite)
  • Regular route usage without customizations
  • customizing the key for route in routes.php

However, customizing the key for a translatable route causes the route to fail.

Example

<?php
// resources/lang/es/routes.php
return [
    "about"    =>  "acerca",
    "article"  =>  "articulo/{article}/{title}",
    "sublvl"    => "a/b/c",
    "user"    => "users/{user:slug}",
];

<?php
// routes/web.php
use Illuminate\Support\Facades\Route;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;

Route::group(['prefix' => LaravelLocalization::setLocale(), 'middleware' => ['localize']], function()
{
    Route::get(LaravelLocalization::transRoute('routes.user'), function (\App\Models\User $user) {
        return $user;
    });
});

Calling localhost/users/bernd won't resolve, even if a user with slug bernd is in db.

@Kapkam
Copy link

Kapkam commented Dec 18, 2024

Hello, I just solved the error that the package presents with the translations of the selected "slug" when using Route Model Binding. The error is simple to reproduce. In my case, I was using the language resource files of 'routes.php' to translate the routes up to the first parameter. Following the official Laravel documentation to use Route Model Binding, I only had to define the route translations this way:

'postDetail' => 'blog-detail/{post:slug}',

Of course, when using this but with the extra of selecting which model field to use as the 3rd parameter of the URL, the package did not detect it and could not resolve it, returning the route like this:

localhost/es/blog-detail/{post:slug}
Instead of
localhost/es/blog-detail/la-bioelectricidad-en-la-medicina-moderna

First of all, I experience this error when I want to translate the current URL using the language-switcher I developed, where I use the function LaravelLocalization::getURLFromRouteNameTranslated(). Investigating the vendor package files, I located the problem and was able to solve it easily. The problem arises because the package does not consider that with the use of Route Model Binding, you might select a specific attribute. This can be seen in this function: substituteAttributesInRoute(), which is called by getURLFromRouteNameTranslated() to substitute the slugs with the translated value. To solve it, you just need to tell it in the str_replace() to consider the possibility of selecting an attribute when defining the route. In my case, it had to consider '{post:slug}'. Here is the modified code with comments:

<?php
/**
 * Change route attributes for the ones in the $attributes array.
 *
 * @param $attributes array Array of attributes
 * @param string $route string route to substitute
 *
 * @return string route with attributes changed
 */
protected function substituteAttributesInRoute($attributes, $route, $locale = null)
{
    foreach ($attributes as $key => $value) {
        if ($value instanceOf Interfaces\LocalizedUrlRoutable) {
            $attributeName = $value->getRouteKeyName(); // need if you used route model binding
            $value = $value->getLocalizedRouteKey($locale);
        }
        elseif ($value instanceOf UrlRoutable) {
            $value = $value->getRouteKey();
        }
        $preRoute = $route;
        $search = array('{'.$key.'}', '{'.$key.'?}', '{'.$key.':'.$attributeName.'}'); // add the attribute name to the search array
        $route = str_replace($search, $value, $route);
    }

    // delete empty optional arguments that are not in the $attributes array
    $route = preg_replace('/\/{[^)]+\?}/', '', $route);

    return $route;
}

This works to solve when you only have one use of Route Model Binding in the route, but the Laravel documentation allows you to have multiple bindings in the same URL, so further investigation is needed to see if this can also be resolved. Example from the documentation for multiple bindings in the same URL:

Link to Lravel Docs

<?php
Route::scopeBindings()->group(function () {
    Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
        return $post;
    });
});

I hope my contribution helps improve the package for the community 😁✌️.

@iwasherefirst2 iwasherefirst2 changed the title Translatable Routes Fail When Customizing the Key Translatable Routes Fail When Using Customizing the Key for translatable parameters Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants