Nuxt i18n
Guide

New features

What's new in v10

Custom routes via definePageMeta()

We have added support for setting custom routes for pages using the definePageMeta() API, which is now the recommended way to set custom routes for pages. This method is enabled by setting customRoutes: 'meta' in the module options.

To migrate from the defineI18nRoute() macro, you can simply replace it with definePageMeta() and set the i18n property with the same options:

pages/about.vue
<script setup>
definePageMeta({
  i18n: {
    paths: {
      en: '/about-us',
      fr: '/a-propos',
    }
  }
})
</script>

Nitro-side language detection and redirection

Language detection and redirection has been reimplemented to be handled from the Nitro server, this allows us to redirect requests earlier in the request lifecycle which improves performance.

The previous implementation did not work correctly when combined with prerendering which this new implementation does.

While this change makes detection and redirection more accurate and should better match the documented behavior, if this causes issues in your project it can be disabled by setting experimental.nitroContextDetection: false in the module options. The option to disable this feature is temporary and will be removed in a future version.

Experimental strict SEO mode

We have added a new experimental option strictSeo that enables strict SEO mode, which changes the way i18n head tags are handled.

With strict SEO mode enabled, the i18n head tags are managed internally, this allows for some much requested improvements:

  • The module will no longer add alternate tags for unsupported locales when setting localized dynamic route params.
  • Unsupported locale links used with <SwitchLocalePathLink> are disabled, their links will be set to '#' and will have a data-i18n-disabled attribute for styling purposes.
  • The useLocaleHead() is no longer needed in strict SEO mode, i18n tags are automatically set by the module and usage will throw an error.
  • Canonical query parameters are configured globally with experimental.strictSeo.canonicalQueryParams.
  • The useSetI18nParams() inherits the global canonical query parameter config which can be overridden through its options parameter.

If this mode proves stable it will become the default in v11, please try it out and report any issues you encounter.

Compact routes

We have added a new experimental option compactRoutes that changes how locale-prefixed routes are generated. Instead of creating a separate route for every locale, eligible routes are compacted into a single route using a regex parameter for the locale segment.

For example, with three locales (en, fr, ja) and the prefix strategy, the /about page would normally produce three routes:

/en/about
/fr/about
/ja/about

With compactRoutes enabled, these are compacted into a single route:

/:locale(en|fr|ja)/about

This can be enabled in nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  i18n: {
    experimental: {
      compactRoutes: true
    }
  }
})

Why this is an improvement:

  • Fewer routes — Applications with many pages and locales can generate a large number of routes (pages × locales). Compact routes significantly reduces this, resulting in a smaller route table and faster route matching.
  • Smaller bundle size — The router configuration shipped to the client is more compact, which reduces the JavaScript payload.
  • Better scalability — The number of routes stays proportional to the number of pages rather than growing multiplicatively with the number of locales.

How it works with different strategies:

  • prefix — All locales are compacted into a single route.
  • prefix_except_default — The default locale keeps its unprefixed route, while all other locales are compacted into a single route.
  • prefix_and_default — The default locale keeps its unprefixed route, and all locales (including the default) are compacted into a single route.

When routes cannot be compacted:

Not all routes are eligible for compaction. A route will still be generated per locale when:

  • It has custom per-locale paths defined (e.g., /about in English but /a-propos in French).
  • It is not available for all configured locales (e.g., a route is disabled for certain locales).

In these cases, the module automatically falls back to the standard per-locale route generation for that specific route, while still compacting all eligible routes.

This option is opt-in for now but is expected to become the default in v11. Please try it out and report any issues you encounter.
This option is not compatible with no_prefix strategy, differentDomains, or multiDomainLocales.
Copyright © 2026