Multi-language URL structure: /fr/page-name instead of /page-name-fr

3 replies
Last updated: May 31, 2021
Hi!I was wondering for multi-language - Is there a way where I can make the URL
domain.com/fr/page-name ? Currently we our translations is pretty much like a new page/post/etc and the name would be something like Page Name Fr which makes the URL, domain.com/page-name-fr Thanks for any insight!
AI Update

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:

  1. Use the same slug across translations - Instead of naming your French page "Page Name Fr" with slug page-name-fr, just use page-name for both the English and French versions. Store the language as a separate field (like language: 'fr' or language: 'en').

  2. 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].js or use the built-in i18n routing.

  3. 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 thread
3 replies
I haven’t done much work with i18n, but you have 2 options: either translations on the field level (each input can be translated) or on the document. However, on the document you’d want to have them grouped rather than as completely separate pages with FR in the title.

There’s a plugin that helps with the above, I haven’t used it though so can’t tell you much more about it. If you check in the localization channel you might get more help by someone with more experience in i18n than me.
good to know, thank you!
Hey Clara! Internationalisation is a tricky domain, there are so many aspects to consider. Also, think about how you want to handle SEO for your pages. this is where a distinct path (i.e. /fr/) or a subdomain (fr.websitename.com ) will come in handy. Max tip with the plug-in is the best way to get started

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.

Was this answer helpful?