0% прочитано

Laravel Multilingual URLs: Shared Slug vs Translated Slugs for Localized Pages

In ICanUp, Posts and Categories use one shared slug while localized URLs differ through the locale prefix and localized content. I explain why I moved away from translated slugs, how the shared-slug model simplified routing, hreflang, sitemaps, and IndexNow, and when language-specific slugs can still be the better choice.

9 вересня 2026 р. 9 хв читанняLaravel

In a multilingual Laravel application, it is easy to assume that every language should automatically have its own slug.

In ICanUp, I eventually chose a different model: Posts and Categories use one shared slug, while the locale controls the URL prefix and localized content without becoming part of the entity identity.

That decision affected much more than routing. It simplified hreflang, sitemaps, IndexNow, internal links, and the contract between the backend and frontend.

Shared slugs and translated slugs are not a right-versus-wrong choice. They are two different routing contracts. For ICanUp, stable entity identity became more valuable than a language-specific slug.
До
Laravel multilingual routing with separate translated slugs for UK and EN localized URLs
Після
Laravel multilingual routing with one shared slug used across UK and EN localized URLs

The Current Contract in ICanUp

In the current ICanUp model, the slug belongs directly to the Post or Category.

Validation checks its uniqueness without a locale dimension, and model lookup uses one shared value.

A translation changes the content, but it does not create another route identity for the same entity.

Simplified current content model
posts  id  slug UNIQUE  ... categories  id  slug UNIQUE  ... translations  locale  localized content  localized SEO fields

This contract is enforced not only by application validation but also by unique constraints on the shared slug in the database.

PHP - Shared slug uniqueness
Rule::unique('posts', 'slug'); Rule::unique('categories', 'slug');

Shared Slugs and Translated Slugs Create Different URL Models

Model

UK URL

EN URL

Shared slug

/posts/laravel-localization

/en/posts/laravel-localization

Translated slugs

/posts/laravel-lokalizatsiia

/en/posts/laravel-localization

With a shared slug, the locale changes the route namespace while the content identifier stays the same.

With translated slugs, the locale becomes part of the lookup contract because a slug alone is no longer enough to resolve the entity.

Why I Chose a Shared Slug

  • One entity has one stable route identity.
  • Slug lookup does not depend on translation storage.
  • Changing one translation does not change another locale URL.
  • Frontend and backend use the same logical route contract.
  • Sitemaps, hreflang, and IndexNow work from one entity and generate its locale-aware URLs.
  • Internal links are easier to build without resolving a separate slug for every target language.

This naturally continues the approach I described in my article about logical route names and localized URLs in Laravel.

I want application code to think in terms of a logical destination while the localization layer decides which locale prefix belongs in the public URL.

A Default Locale and Shared Slug Do Not Mean Identical URLs

Locale-aware public URLs
UK default locale:https://icanup.com.ua/posts/example-slug EN locale:https://icanup.com.ua/en/posts/example-slug

In ICanUp, UK is the default locale, so its URL has no additional prefix.

The English URL receives /en, while the slug remains the same.

URL localization comes from the routing layer, not from translating the slug itself.

Route Lookup Becomes Simpler

With a shared slug, the entity can be resolved independently of the currently active locale.

PHP - Look up a Post by shared slug
$post = Post::query()    ->where('slug', $slug)    ->firstOrFail();

With translated slugs, lookup usually has to include the locale or a translation relation.

That is not inherently wrong, but the locale becomes part of identity resolution, which means it follows routing, validation, redirects, caching, and tests.

Localized Content Still Remains Fully Localized

A shared slug does not mean that every language gets the same page.

Titles, short text, content blocks, SEO metadata, and other localized values can still differ completely between UK and EN.

I simply separate content translation from route identity.

Field

Shared

Localized

Post ID

Yes

No

Slug

Yes

No

Title

No

Yes

Content

No

Yes

Meta Title

No

Yes

Meta Description

No

Yes

Public URL prefix

No

Yes

A Shared Slug Does Not Create SEO Duplicates

The same slug fragment in two locale URLs does not automatically make them duplicate content.

Search engines see separate URLs with localized content, a self-canonical, and the correct hreflang relationship.

I covered that infrastructure separately in my article about Laravel hreflang and canonical URLs.

The English page should not canonicalize to the UK page just because the slug is shared. Each locale URL has its own self-canonical, while hreflang connects the language versions.

Sitemaps and IndexNow Benefit from Stable Identity Too

When the SEO layer receives a Post, it does not need to search the translation table for a route slug.

It starts with one entity and generates the required locale-aware URLs through the routing and localization contract.

I use the same principle in my IndexNow implementation and my locale-aware sitemap lastmod implementation.

  • HreflangService generates URLs for available locales.
  • The sitemap works with the same entity identity.
  • IndexNow receives current public URLs instead of implementing its own slug logic.
  • Changing visible translated content does not require a different slug lookup contract.

What Would Change with Translated Slugs

Translated slugs can produce more natural language-specific paths, but they move part of the complexity into infrastructure.

One entity now has several route identifiers, and each one can change independently.

The slug becomes localized content with routing consequences.

Concern

Shared slug

Translated slugs

Lookup

slug

locale + translated slug

Uniqueness

global slug

usually locale + slug

Slug change

one route identity

independent per locale

Redirects

one shared history

history per locale

Internal links

shared entity slug

resolve target-locale slug

SEO URL generation

route + locale

route + locale + translated slug

Redirect History Becomes Locale-Specific

If the EN slug changes while the UK slug stays the same, only the English URL needs a redirect.

If the UK slug changes later, another redirect history starts there.

For a project where URLs change frequently, this becomes a separate domain concern that has to be stored and tested.

Admin Validation Becomes More Complex Too

A shared slug has one uniqueness rule.

With translated slugs, I need to decide whether a slug is globally unique, unique only inside one locale, or unique within a content type and locale.

I also need a rule for translations that exist while their localized slug is still empty.

When Translated Slugs Can Be the Better Choice

  • The URL should read naturally in every language.
  • The locales use different alphabets and the slug is an important part of the user experience.
  • Keyword strategy differs significantly between locales.
  • The project already has reliable locale-specific redirect history.
  • CMS editors expect full URL control for each language.
  • Routing infrastructure was designed around locale + slug identity from the beginning.
I would not move to translated slugs only because the URL looks more translated. It should be an intentional architecture decision because the change affects the entire routing contract, not only the visible path.

For ICanUp, the Trade-Off Favored a Shared Slug

For my blog, stable routing, multilingual SEO, and using the same content identity across services are more important than translating every path segment.

A shared slug gives up some localization flexibility, but it reduces the number of places where the application has to understand translated route keys.

For ICanUp, that trade-off has been the better fit.

I localize the content and URL namespace without duplicating entity identity unless I actually need to.

What I Verify in This Contract

  • Post slug is unique at the posts level.
  • Category slug is unique at the categories level.
  • UK and EN URLs use the same shared slug.
  • The default locale does not receive an unnecessary locale prefix.
  • The EN URL receives the /en prefix.
  • Hreflang uses the current shared slug.
  • A disabled or unavailable locale is not advertised as an alternate.
  • Sitemap and IndexNow use the same canonical public URLs.
  • Legacy translated slugs do not return to the routing contract.

What I Kept for Next Time

  • Define entity identity before deciding whether the slug should be localized.
  • Do not automatically mix content translation with route identity.
  • Plan redirect history before introducing translated slugs.
  • Use one URL generation contract for routing, hreflang, sitemaps, RSS, and IndexNow.
  • Do not let an SEO service independently decide how a localized route should look.
  • Test unavailable locales separately from enabled locales.

Conclusion

A shared slug in a multilingual Laravel application can initially look less localized than a separate slug for every language.

But once routing is consumed by the frontend, hreflang, sitemaps, IndexNow, RSS, and internal links, the real cost of route identity becomes much clearer.

In ICanUp, I kept the slug shared and moved localization into the locale-aware routing and content layers.

For me, that created a simpler contract: one entity, one slug identity, and multiple fully localized public URLs.