laravellaravel-11

Change the first segment of the current URL


I have a multilanguage site: en, hu, ro atm. The base URL is example.com/{locale} e.g. example.com/en. The language detection is just checking the locale parameter of the route. I want it to stay this way.

I have a language selector where all locales can be selected and for every page I have link rel alternate for the crawlers to avoid duplicate content problems. So when I visit example.com/en/products/1 the language selector in the layout should have example.com/hu/products/1 and example.com/ro/products/1 as well. I think I should make these URIs in the language middleware and send it to the layout with View::share.

I could build these URIs using the current URI and a simple preg replace or str replace on the first segment, but I guess there is a better way in Laravel. I found that \Illuminate\Support\Facades\Request::segment(1) is good for getting the first segment and the route pattern is usually /{locale}/sthg/{sthg} appended with query string, but I cannot find a Laravel solution for replacing the first segment. Is there such a thing?


Solution

  • if you want to build all language options, and pass them to your views, you can use a view composer:

    class LocalesComposer
    {
      // inject current request into the ViewComposer
      public function __construct(protected Request $request)
      {}
    
      public function compose(View $view)
      {
         // filter valid locales, assuming config('app.locales') is an array of all supported locales in this application
         $locales = collect(config('app.locales'))
            ->reject(fn ($locale) => $locale == app()->getLocale());
    
         $routeName = $this->request->route()->getName();
         $routeParams = $this->request->route()->parameters();
    
         $languageSelectOptions = $locales->map(function (string $locale) use ($routeName, $routeParams) {
           $routeParams['locale'] = $locale;
           return route($routeName, $routeParams); // return a url for this route
         );
    
         // pass URLs array to the view
         $view->with('languageSelectOptions', $languageSelectOptions);
      }