Multi-language URL structure: /fr/page-name instead of /page-name-fr
I totally understand your challenge! You want cleaner URLs with the language code as a directory (like /fr/page-name) instead of appending it to the slug (like /page-name-fr). This is definitely achievable with Sanity, and it's actually a common pattern for multilingual sites.
The key is understanding that Sanity stores your content, but your frontend application (like Next.js, Nuxt, or whatever you're using) determines the actual URL structure. Here's how to approach this:
The Solution: Handle URLs in Your Frontend
When using document-level internationalization (which sounds like what you're doing), each language version is a separate document. You'll want to:
Use the same slug across translations - Instead of naming your French page "Page Name Fr" with slug
page-name-fr, just usepage-namefor both the English and French versions. Store the language as a separate field (likelanguage: 'fr'orlanguage: 'en').Structure your frontend routes - Set up your routing to include the language code in the path. For example, in Next.js, you'd create a file structure like
pages/[lang]/[slug].jsor use the built-in i18n routing.Query by language and slug - When someone visits
/fr/page-name, your frontend extracts both the language (fr) and slug (page-name), then queries Sanity for the document matching both criteria:
*[_type == "page" && slug.current == $slug && language == $lang][0]Implementation Example
Your document structure would look like:
- English page:
{ title: "Page Name", slug: "page-name", language: "en" } - French page:
{ title: "Nom de la page", slug: "page-name", language: "fr" }
Notice both use the same slug, but different language codes. Your frontend routing handles the /fr/ or /en/ prefix, while Sanity just stores the base slug.
This approach gives you the clean URL structure you want (domain.com/fr/page-name) while keeping your content organized in Sanity. The @sanity/document-internationalization plugin can help manage these relationships and make it easier for editors to navigate between translations in the Studio.
This is similar to how WordPress plugins like Polylang and WPML handle the "same slug across languages" feature - the CMS allows duplicate slugs differentiated by language, and the frontend routing adds the language directory prefix. For more details on document-level localization, check out Sanity's localization documentation!
Show original thread3 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.