Translatable slugs | laravel-sluggable | Spatie

 SPATIE

  Laravel Sluggable
====================

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Laravel-sluggable](https://spatie.be/docs/laravel-sluggable/v4)  Translatable slugs

 Version   v4

 Other versions for crawler [v4](https://spatie.be/docs/laravel-sluggable/v4)

  Translatable slugs
- [ Introduction ](https://spatie.be/docs/laravel-sluggable/v4/introduction)
- [ Requirements ](https://spatie.be/docs/laravel-sluggable/v4/requirements)
- [ Installation &amp; setup ](https://spatie.be/docs/laravel-sluggable/v4/installation-setup)
- [ Translatable slugs ](https://spatie.be/docs/laravel-sluggable/v4/translatable-slugs)
- [ Laravel Boost skill ](https://spatie.be/docs/laravel-sluggable/v4/laravel-boost-skill)
- [ Changelog ](https://spatie.be/docs/laravel-sluggable/v4/changelog)
- [ Questions and issues ](https://spatie.be/docs/laravel-sluggable/v4/questions-issues)
- [ Support us ](https://spatie.be/docs/laravel-sluggable/v4/support-us)
- [ Upgrading ](https://spatie.be/docs/laravel-sluggable/v4/upgrading)

Basic usage
-----------

- [ Generating your first slug ](https://spatie.be/docs/laravel-sluggable/v4/basic-usage/getting-started)
- [ Using the Sluggable attribute ](https://spatie.be/docs/laravel-sluggable/v4/basic-usage/using-the-attribute)
- [ Using the HasSlug trait ](https://spatie.be/docs/laravel-sluggable/v4/basic-usage/using-the-has-slug-trait)
- [ Finding models by slug ](https://spatie.be/docs/laravel-sluggable/v4/basic-usage/finding-models-by-slug)
- [ Self-healing URLs ](https://spatie.be/docs/laravel-sluggable/v4/basic-usage/self-healing-urls)

Advanced usage
--------------

- [ Combining multiple source columns ](https://spatie.be/docs/laravel-sluggable/v4/advanced-usage/source-fields)
- [ Tuning the uniqueness suffix ](https://spatie.be/docs/laravel-sluggable/v4/advanced-usage/uniqueness)
- [ Overriding the underlying actions ](https://spatie.be/docs/laravel-sluggable/v4/advanced-usage/overriding-actions)

 Translatable slugs
==================

###  On this page

1. [ Generating slugs from a callable per locale ](#content-generating-slugs-from-a-callable-per-locale)
2. [ Routing ](#content-routing)
3. [ Finding models by slug ](#content-finding-models-by-slug)
4. [ Self-healing URLs ](#content-self-healing-urls)
5. [ Getting the route key for a specific locale ](#content-getting-the-route-key-for-a-specific-locale)

Use the `HasTranslatableSlug` trait together with `spatie/laravel-translatable` to store one slug per locale.

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\Sluggable\HasTranslatableSlug;
use Spatie\Sluggable\SlugOptions;
use Spatie\Translatable\HasTranslations;

class Article extends Model
{
    use HasTranslations;
    use HasTranslatableSlug;

    public $translatable = ['title', 'slug'];

    public function getSlugOptions(): SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('title')
            ->saveSlugsTo('slug');
    }
}
```

The slug column must hold a JSON value; every translatable attribute in `$translatable` (including the slug itself) is stored as a locale-keyed object.

Generating slugs from a callable per locale
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

When using a callable, instantiate `SlugOptions` with `createWithLocales()`. The callable receives the model and the current locale.

```
public function getSlugOptions(): SlugOptions
{
    return SlugOptions::createWithLocales(['en', 'nl'])
        ->generateSlugsFrom(fn (Article $article, string $locale) => "{$locale} {$article->id}")
        ->saveSlugsTo('slug');
}
```

Routing
-----------------------------------------------------------------------------

Use Laravel's implicit route model binding, pointing at the slug column.

```
Route::get('/articles/{article:slug}', fn (Article $article) => $article);
```

`HasTranslatableSlug` handles the locale-aware JSON lookup in `resolveRouteBindingQuery()`.

Finding models by slug
--------------------------------------------------------------------------------------------------------------------------

`HasTranslatableSlug` ships its own `findBySlug()` that searches the current locale and the application fallback locale.

```
$article = Article::findBySlug('my-article');
```

Self-healing URLs
-----------------------------------------------------------------------------------------------------------

`selfHealing()` works with the translatable trait. The route key uses the slug for the current locale; stale slugs trigger the same redirect flow described in [Self-healing URLs](/docs/laravel-sluggable/v4/basic-usage/self-healing-urls).

Getting the route key for a specific locale
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Use `getLocalizedRouteKey()` to retrieve the route key for a given locale without permanently changing the model's active locale.

```
$article->getLocalizedRouteKey('nl'); // "nederlandse-titel-5"
```

The method swaps in the requested locale, calls `getRouteKey()`, and restores the original locale via `try/finally`, so the model is always left as it was found, including when `getRouteKey()` throws.

 A good
match?
-------------

### What we do best

- All things Laravel
- Custom frontend components
- Building APIs
- AI-powered features
- Simplifying things
- Clean solutions
- Integrating services

### Not our cup of tea

- WordPress themes
- Cutting corners
- Free mockups to win a job
- "Just execute the briefing"

 In short: we'd like to be a **substantial part** of your project.

 [ Get in touch via email ](mailto:info@spatie.be?subject=A%20good%20match%21&body=Tell%20us%20as%20much%20as%20you%20can%20about%0A-%20your%20online%20project%0A-%20your%20planning%0A-%20your%20budget%0A-%20%E2%80%A6%0A%0AAnything%20that%20helps%20us%20to%20start%20straightforward%21)
