In some cases, you might want to translate URLs in addition to having them prefixed with the locale code. There are two methods of configuring custom paths, through Module configuration or from within each Page component.
Which method is used is configured by setting the customRoutes
options this is set to 'page'
by default. Using both methods at the same time is not possible.
'no_prefix'
strategy unless combined with differentDomains
.Make sure you set the customRoutes
option to 'config'
and add your custom paths in the pages
option:
export default defineNuxtConfig({
i18n: {
customRoutes: 'config', // disable custom route with page components
pages: {
about: {
en: '/about-us', // -> accessible at /about-us (no prefix since it's the default locale)
fr: '/a-propos', // -> accessible at /fr/a-propos
es: '/sobre' // -> accessible at /es/sobre
}
}
}
})
Note that each key within the pages
object should correspond to the route name of the route to localize.
Customized route paths must start with a /
and must not include the locale prefix.
You can now use the localePath()
function or the <NuxtLinkLocale>
component but be sure to use named routes. For example route '/services/advanced'
should be 'services-advanced'
:
<script setup>
const { t } = useI18n()
</script>
<template>
<NuxtLinkLocale to="about"> {{ t('about') }} </NuxtLinkLocale>
<NuxtLinkLocale to="services-advanced"> {{ t('advanced') }} </NuxtLinkLocale>
</template>
Or:
<script setup>
const { t } = useI18n()
const localePath = useLocalePath()
</script>
<template>
<NuxtLink :to="localePath('about')"> {{ t('about') }} </NuxtLink>
<NuxtLink :to="localePath('services-advanced')"> {{ t('advanced') }} </NuxtLink>
</template>
localePath()
is currently not supported.You have some routes with the following pages
directory:
-| pages/
---| me.vue
---| about.vue
---| services/
-----| index.vue
-----| advanced.vue
You would need to set up your pages
property as follows:
export default defineNuxtConfig({
i18n: {
customRoutes: 'config',
pages: {
me: {
fr: '/moi',
},
about: {
fr: '/a-propos',
},
services: {
fr: '/offres',
},
'services-advanced': {
fr: '/offres/avancee',
}
}
}
})
/
You have some routes with the following pages
directory:
-| pages/
---| about.vue
---| services/
-----| index.vue
-----| coaching.vue
-----| development/
-------| app.vue
-------| index.vue
-------| website.vue
You would need to set up your pages
property as follows:
export default defineNuxtConfig({
i18n: {
customRoutes: 'config',
pages: {
about: {
fr: '/a-propos'
},
services: {
fr: '/offres'
},
'services-development': {
fr: '/offres/developement'
},
'services-development-app': {
fr: '/offres/developement/app'
},
'services-development-website': {
fr: '/offres/developement/site-web'
},
'services-coaching': {
fr: '/offres/formation'
}
}
}
})
If a custom path is missing for one of the locales, the defaultLocale
custom path is used, if set.
Say you have some dynamic routes like:
-| pages/
---| blog/
-----| [date]/
-------| [slug].vue
Here's how you would configure these particular pages in the configuration:
export default defineNuxtConfig({
i18n: {
customRoutes: 'config',
pages: {
'blog-date-slug': {
// params need to be put back here as you would with Nuxt Dynamic Routes
// https://nuxt.com/docs/guide/directory-structure/pages#dynamic-routes
ja: '/blog/tech/[date]/[slug]'
// ...
}
}
}
})
v8.0.1
or higher
'/example/:param'
should now be '/example/[param]'
)You can use the defineI18nRoute()
compiler macro to set custom paths for each page component.
<script setup>
defineI18nRoute({
paths: {
en: '/about-us', // -> accessible at /about-us (no prefix since it's the default locale)
fr: '/a-propos', // -> accessible at /fr/a-propos
es: '/sobre' // -> accessible at /es/sobre
}
})
</script>
To configure a custom path for a dynamic route, you need to use it in double square brackets in the paths similarly to how you would do it in Nuxt Dynamic Routes:
<script setup>
defineI18nRoute({
paths: {
en: '/articles/[name]',
es: '/artículo/[name]'
}
})
</script>
defineI18nRoute()
compiler macro is tree-shaken out at build time and is not included in the dist files.Dealing with dynamic route parameters requires a bit more work because you need to provide parameters translations to Nuxt i18n module. The composable useSetI18nParams
can be used to set translations for route parameters, this is used to set SEO tags as well as changing the routes returned by switchLocalePath
.
switchLocalePathLinkSSR
feature, which combined with the <SwitchLocalePathLink>
component, correctly renders links during SSR regardless of where and when it is used.An example (replace slug
with the applicable route parameter):
<script setup>
// fetch product from API... (red mug)
const setI18nParams = useSetI18nParams()
setI18nParams({
en: { slug: data.slugs.en }, // slug: 'red-mug'
nl: { slug: data.slugs.nl } // slug: 'rode-mok'
})
const switchLocalePath = useSwitchLocalePath()
switchLocalePath('en') // /products/red-mug
switchLocalePath('nl') // /nl/products/rode-mok
</script>
<template>
<!-- pages/products/[slug].vue -->
</template>
Note that for the special case of a catch-all route named like [...pathMatch].vue
, the key of the object needs to say pathMatch
. For example:
<script>
const setI18nParams = useSetI18nParams()
setI18nParams({
en: { pathMatch: ['not-found-my-post'] },
fr: { pathMatch: ['not-found-mon-article'] }
})
</script>
<template>
<!-- pages/[...pathMatch].vue -->
</template>
Note that a catch all route is defined as an array. In this case, there is only one element, but if you want to use a sub-path, for example '/not-found/post'
, define multiple elements as in ['not-found', 'post']
. You will need to define more than one, e.g. ['not-found', 'post']
.
definePageMeta({ name: '...' })
caveatBy default Nuxt overwrites generated route values at build time which breaks custom named routes (setting name
with definePageMeta()
) when resolving localized paths.
Nuxt v3.10 introduced the experimental feature scanPageMeta
, this needs to be enabled for custom named routes to work when using Nuxt I18n.
This experimental feature can be enabled as shown here:
export default defineNuxtConfig({
experimental: {
scanPageMeta: true,
}
})