HomeSandboxShowcaseAppDocBlog
    • EnglishEnglish
      EN
    • русскийRussian
      RU
    • 日本語Japanese
      JA
    • françaisFrench
      FR
    • 한국어Korean
      KO
    • 中文Chinese
      ZH
    • españolSpanish
      ES
    • DeutschGerman
      DE
    • العربيةArabic
      AR
    • italianoItalian
      IT
    • British EnglishBritish English
      EN-GB
    • portuguêsPortuguese
      PT
    • हिन्दीHindi
      HI
    • TürkçeTurkish
      TR
    • polskiPolish
      PL
    • IndonesiaIndonesian
      ID
    • Tiếng ViệtVietnamese
      VI
    • українськаUkrainian
      UK
    /
    Filter docs by framework
    Alt+←
    Why Intlayer ?
    Get Started
    Concept
    • How Intlayer Works
    • Configuration
    • TestFillBuildWatchExtractLoginPushPullConfigurationListVersionEditorLiveDebugDoc ReviewDoc TranslateSDK
    • Visual Editor
    • CMS
    • CI/CD Integration
    • TranslationPluralEnumerationConditionGenderInsertionFileNestingMarkdownHTMLFunction Fetching
    • Per Locale File
    • Compiler
    • Auto Fill
    • Testing
    • Bundle Optimization
    Environment
    • Next.js 14 and App Router
      Next.js 15
      Next.js no locale path
      Next.js and Page Router
      Compiler
    • Tanstack Start Solid
    • Astro and React
      Astro and Svelte
      Astro and Vue
      Astro and Solid
      Astro and Preact
      Astro and Lit
      Astro and Vanilla JS
    • React Router v7
      React Router v7 (fs-routes)
      Compiler
    • Nuxt and Vue
    • Vite and Solid
    • SvelteKit
    • Vite and Preact
    • Vite and Vanilla JS
    • Vite and Lit
    • Angular 19 (Webpack)
      Analog
    • React CRA
    • React Native and Expo
    • Express.js
      NestJS
      Fastify
      Hono
      Adonis
    • Lynx and React
    Plugins
    • JSON
    • gettext (.po)
    VS Code Extension
    Agent
    • MCP Server
    • Agent skills
    Releases
    • v8
    • v7
    • v6
    Benchmark
    • Next.js
    • TanStack
    • Vue
    • Solid
    • Svelte
    Blog
    Ask a question
    1. Documentation
    2. Concept
    3. Custom_url_rewrites
    \n\n ```\n\n \n \n \n ```tsx\n import { useRewriteURL } from \"solid-intlayer\";\n\n const Layout = (props) => {\n useRewriteURL();\n return <>{props.children};\n };\n ```\n\n \n \n \n ```svelte\n \n\n ```\n\n \n\n\n## Router Integration & Proxies\n\nIntlayer's server-side proxies (Vite & Next.js) automatically handle custom rewrites to ensure SEO consistency.\n\n1. **Internal Rewrites**: When a user visits `/fr/a-propos`, the proxy internally maps it to `/fr/about` so your framework matches the correct route.\n2. **Authoritative Redirects**: If a user manually types in `/fr/about`, the proxy issues a 301/302 redirect to `/fr/a-propos`, ensuring search engines only index one version of the page.\n\n### Next.js Integration\n\nNext.js integration is fully handled via the `intlayerProxy` middleware.\n\n```typescript fileName=\"middleware.ts\"\nimport { intlayerProxy } from \"next-intlayer/middleware\";\nimport { NextRequest } from \"next/server\";\n\nexport function middleware(request: NextRequest) {\n return intlayerProxy(request);\n}\n```\n\n### Vite Integration\n\nFor SolidJS, Vue, and Svelte, the `intlayerProxy` Vite plugin manages the rewrites during development.\n\n```typescript fileName=\"vite.config.ts\"\nimport { defineConfig } from \"vite\";\nimport { intlayerProxy } from \"vite-intlayer\";\n\nexport default defineConfig({\n plugins: [intlayerProxy()],\n});\n```\n\n## Key Features\n\n### 1. Multi-Context Rewrites\n\nEach formatter generates a `RewriteObject` containing specialised rules for different consumers:\n\n- `url`: Optimised for client-side URL generation (strips locale segments).\n- `nextjs`: Preserves `[locale]` for Next.js middleware.\n- `vite`: Preserves `:locale` for Vite proxies.\n\n### 2. Automatic Pattern Normalisation\n\nIntlayer internally normalises all pattern syntaxes (e.g., converting `[param]` to `:param`) so that matching remains consistent regardless of the source framework.\n\n### 3. SEO Authoritative URLs\n\nBy enforcing redirects from canonical paths to prettier aliases, Intlayer prevents duplicate content issues and improves site discoverability.\n\n## Core Utilities\n\n- `getLocalizedUrl(url, locale)`: Generates a localised URL respecting rewrite rules.\n- `getCanonicalPath(path, locale)`: Resolves a localised URL back to its internal canonical path.\n- `getRewritePath(pathname, locale)`: Detects whether a pathname needs to be corrected to its prettier localised alias.\n","about":"Learn how to configure and use custom URL rewrites in Intlayer to define locale-specific paths.","url":"https://intlayer.org/en-GB/doc/concept/custom_url_rewrites","datePublished":"13-08-2024","dateModified":"26-01-2026","keywords":"Custom URL Rewrites, Routing, Internationalisation, i18n","license":"https://raw.githubusercontent.com/aymericzip/intlayer/refs/heads/main/LICENSE","audience":{"@type":"Audience","audienceType":"Developers, Content Managers"}}
    Creation:2024-08-13Last update:2026-01-26
    Reference this doc to your favorite AI assistant
    ChatGPT
    Claude
    DeepSeek
    Google AI mode
    Gemini
    Perplexity
    Mistral
    Grok

    Ask your question and get a summary of the document by referencing this page and the AI provider of your choice

    Version History

    1. "Implement centralized URL rewrites with framework-specific formatters and the useRewriteURL hook."
      v8.0.025/01/2026

    The content of this page was translated using an AI.

    See the last version of the original content in English
    Edit this doc

    If you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.

    GitHub link to the documentation
    Copy

    Copy doc Markdown to clipboard

    Custom URL Rewrites Implementation

    Intlayer supports custom URL rewrites, allowing you to define locale-specific paths that differ from the standard /locale/path structure. This enables URLs like /about for English and /a-propos for French while keeping the internal application logic canonical.

    Configuration

    Custom rewrites are configured in the routing section of your intlayer.config.ts file using framework-specific formatters. These formatters provide the correct syntax for your chosen router.

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { nextjsRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-no-default",    rewrite: nextjsRewrite({      "/[locale]/about": {        fr: "/[locale]/a-propos",        es: "/[locale]/acerca-de",      },      "/[locale]/products/[id]": {        fr: "/[locale]/produits/[id]",        es: "/[locale]/productos/[id]",      },    }),  },};export default config;
    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { reactRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: reactRouterRewrite({      "/:locale/about": {        fr: "/:locale/a-propos",        es: "/:locale/acerca-de",      },      "/:locale/products/:id": {        fr: "/:locale/produits/:id",        es: "/:locale/productos/:id",      },    }),  },};export default config;
    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { tanstackRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: tanstackRouterRewrite({      "/$locale/about": {        fr: "/$locale/a-propos",        es: "/$locale/acerca-de",      },      "/$locale/products/$id": {        fr: "/$locale/produits/$id",        es: "/$locale/productos/$id",      },    }),  },};export default config;
    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { vueRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: vueRouterRewrite({      "/:locale/about": {        fr: "/:locale/a-propos",        es: "/:locale/acerca-de",      },      "/:locale/products/:id": {        fr: "/:locale/produits/:id",        es: "/:locale/productos/:id",      },    }),  },};export default config;
    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { svelteKitRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: svelteKitRewrite({      "/[locale]/about": {        fr: "/[locale]/a-propos",        es: "/[locale]/acerca-de",      },      "/[locale]/products/[id]": {        fr: "/[locale]/produits/[id]",        es: "/[locale]/productos/[id]",      },    }),  },};export default config;
    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { solidRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: solidRouterRewrite({      "/:locale/about": {        fr: "/:locale/a-propos",        es: "/:locale/acerca-de",      },      "/:locale/products/:id": {        fr: "/:locale/produits/:id",        es: "/:locale/productos/:id",      },    }),  },};export default config;
    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";import { nuxtRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: nuxtRewrite({      "/[locale]/about": {        fr: "/[locale]/a-propos",        es: "/[locale]/acerca-de",      },      "/[locale]/products/[id]": {        fr: "/[locale]/produits/[id]",        es: "/[locale]/productos/[id]",      },    }),  },};export default config;

    Available Formatters

    Intlayer provides formatters for all popular frameworks:

    • nextjsRewrite: For Next.js App Router. Supports [slug], [...slug] (1+), and [[...slug]] (0+).
    • svelteKitRewrite: For SvelteKit. Supports [slug], [...path] (0+), and [[optional]] (0-1).
    • reactRouterRewrite: For React Router. Supports :slug and * (0+).
    • vueRouterRewrite: For Vue Router 4. Supports :slug, :slug? (0-1), :slug* (0+), and :slug+ (1+).
    • solidRouterRewrite: For Solid Router. Supports :slug and *slug (0+).
    • tanstackRouterRewrite: For TanStack Router. Supports $slug and * (0+).
    • nuxtRewrite: For Nuxt 3. Supports [slug] and [...slug] (0+).
    • viteRewrite: Generic formatter for any Vite-based project. Normalises syntax for the Vite proxy.

    Advanced patterns

    Intlayer internally normalises these patterns to a unified syntax, allowing sophisticated path matching and generation:

    • Optional segments: [[optional]] (SvelteKit) or :slug? (Vue/React) are supported.
    • Catch-all (zero or more): [[...slug]] (Next.js), [...path] (SvelteKit/Nuxt), or * (React/TanStack) allow matching multiple segments.
    • Mandatory catch-all (one or more): [...slug] (Next.js) or :slug+ (Vue) ensure at least one segment is present.

    Client-side URL correction: useRewriteURL

    To ensure that the browser's address bar always reflects the "pretty" localised URL, Intlayer provides the useRewriteURL hook. This hook silently updates the URL using window.history.replaceState when a user lands on a canonical path.

    Usage in Frameworks

    tsx
    Copy code

    Copy the code to the clipboard

    'use client';import { useRewriteURL } from "next-intlayer";const MyLayout = ({ children }) => {  useRewriteURL(); // Automatically corrects /fr/about to /fr/a-propos  return <>{children}</>;};
    tsx
    Copy code

    Copy the code to the clipboard

    'use client';import { useRewriteURL } from "react-intlayer";const MyLayout = ({ children }) => {  useRewriteURL(); // Automatically corrects /fr/about to /fr/a-propos  return <>{children}</>;};
    vue
    Copy code

    Copy the code to the clipboard

    <script setup>import { useRewriteURL } from "vue-intlayer";useRewriteURL();</script>
    tsx
    Copy code

    Copy the code to the clipboard

    import { useRewriteURL } from "solid-intlayer";const Layout = (props) => {  useRewriteURL();  return <>{props.children}</>;};
    svelte
    Copy code

    Copy the code to the clipboard

    <script>import { useRewriteURL } from "svelte-intlayer";useRewriteURL();</script>

    Router Integration & Proxies

    Intlayer's server-side proxies (Vite & Next.js) automatically handle custom rewrites to ensure SEO consistency.

    1. Internal Rewrites: When a user visits /fr/a-propos, the proxy internally maps it to /fr/about so your framework matches the correct route.
    2. Authoritative Redirects: If a user manually types in /fr/about, the proxy issues a 301/302 redirect to /fr/a-propos, ensuring search engines only index one version of the page.

    Next.js Integration

    Next.js integration is fully handled via the intlayerProxy middleware.

    middleware.ts
    Copy code

    Copy the code to the clipboard

    import { intlayerProxy } from "next-intlayer/middleware";import { NextRequest } from "next/server";export function middleware(request: NextRequest) {  return intlayerProxy(request);}

    Vite Integration

    For SolidJS, Vue, and Svelte, the intlayerProxy Vite plugin manages the rewrites during development.

    vite.config.ts
    Copy code

    Copy the code to the clipboard

    import { defineConfig } from "vite";import { intlayerProxy } from "vite-intlayer";export default defineConfig({  plugins: [intlayerProxy()],});

    Key Features

    1. Multi-Context Rewrites

    Each formatter generates a RewriteObject containing specialised rules for different consumers:

    • url: Optimised for client-side URL generation (strips locale segments).
    • nextjs: Preserves [locale] for Next.js middleware.
    • vite: Preserves :locale for Vite proxies.

    2. Automatic Pattern Normalisation

    Intlayer internally normalises all pattern syntaxes (e.g., converting [param] to :param) so that matching remains consistent regardless of the source framework.

    3. SEO Authoritative URLs

    By enforcing redirects from canonical paths to prettier aliases, Intlayer prevents duplicate content issues and improves site discoverability.

    Core Utilities

    • getLocalizedUrl(url, locale): Generates a localised URL respecting rewrite rules.
    • getCanonicalPath(path, locale): Resolves a localised URL back to its internal canonical path.
    • getRewritePath(pathname, locale): Detects whether a pathname needs to be corrected to its prettier localised alias.
    Why Intlayer ?
    Alt+→

    On this page

      Discussions are anonymous and regularly reviewed to address common issues. Feel free to share feature ideas, feedback on the documentation, or anything related to Intlayer, we use this input to shape our roadmap and improve the product.

      import { Locales, type IntlayerConfig } from "intlayer";import { nextjsRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-no-default",    rewrite: nextjsRewrite({      "/[locale]/about": {        fr: "/[locale]/a-propos",        es: "/[locale]/acerca-de",      },      "/[locale]/products/[id]": {        fr: "/[locale]/produits/[id]",        es: "/[locale]/productos/[id]",      },    }),  },};export default config;
      import { Locales, type IntlayerConfig } from "intlayer";import { reactRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: reactRouterRewrite({      "/:locale/about": {        fr: "/:locale/a-propos",        es: "/:locale/acerca-de",      },      "/:locale/products/:id": {        fr: "/:locale/produits/:id",        es: "/:locale/productos/:id",      },    }),  },};export default config;
      import { Locales, type IntlayerConfig } from "intlayer";import { tanstackRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: tanstackRouterRewrite({      "/$locale/about": {        fr: "/$locale/a-propos",        es: "/$locale/acerca-de",      },      "/$locale/products/$id": {        fr: "/$locale/produits/$id",        es: "/$locale/productos/$id",      },    }),  },};export default config;
      import { Locales, type IntlayerConfig } from "intlayer";import { vueRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: vueRouterRewrite({      "/:locale/about": {        fr: "/:locale/a-propos",        es: "/:locale/acerca-de",      },      "/:locale/products/:id": {        fr: "/:locale/produits/:id",        es: "/:locale/productos/:id",      },    }),  },};export default config;
      import { Locales, type IntlayerConfig } from "intlayer";import { svelteKitRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: svelteKitRewrite({      "/[locale]/about": {        fr: "/[locale]/a-propos",        es: "/[locale]/acerca-de",      },      "/[locale]/products/[id]": {        fr: "/[locale]/produits/[id]",        es: "/[locale]/productos/[id]",      },    }),  },};export default config;
      import { Locales, type IntlayerConfig } from "intlayer";import { solidRouterRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: solidRouterRewrite({      "/:locale/about": {        fr: "/:locale/a-propos",        es: "/:locale/acerca-de",      },      "/:locale/products/:id": {        fr: "/:locale/produits/:id",        es: "/:locale/productos/:id",      },    }),  },};export default config;
      import { Locales, type IntlayerConfig } from "intlayer";import { nuxtRewrite } from "intlayer/routing";const config: IntlayerConfig = {  // ...  routing: {    mode: "prefix-all",    rewrite: nuxtRewrite({      "/[locale]/about": {        fr: "/[locale]/a-propos",        es: "/[locale]/acerca-de",      },      "/[locale]/products/[id]": {        fr: "/[locale]/produits/[id]",        es: "/[locale]/productos/[id]",      },    }),  },};export default config;
      'use client';import { useRewriteURL } from "next-intlayer";const MyLayout = ({ children }) => {  useRewriteURL(); // Automatically corrects /fr/about to /fr/a-propos  return <>{children}</>;};
      'use client';import { useRewriteURL } from "react-intlayer";const MyLayout = ({ children }) => {  useRewriteURL(); // Automatically corrects /fr/about to /fr/a-propos  return <>{children}</>;};
      <script setup>import { useRewriteURL } from "vue-intlayer";useRewriteURL();</script>
      import { useRewriteURL } from "solid-intlayer";const Layout = (props) => {  useRewriteURL();  return <>{props.children}</>;};
      <script>import { useRewriteURL } from "svelte-intlayer";useRewriteURL();</script>
      import { intlayerProxy } from "next-intlayer/middleware";import { NextRequest } from "next/server";export function middleware(request: NextRequest) {  return intlayerProxy(request);}
      import { defineConfig } from "vite";import { intlayerProxy } from "vite-intlayer";export default defineConfig({  plugins: [intlayerProxy()],});