๐ SEO Guide for Nuxt I18n Micro โ
๐ Introduction โ
Effective SEO (Search Engine Optimization) is essential for ensuring that your multilingual site is accessible and visible to users worldwide through search engines. Nuxt I18n Micro simplifies the process of managing SEO for multilingual sites by automatically generating essential meta tags and attributes that inform search engines about the structure and content of your site.
This guide explains how Nuxt I18n Micro handles SEO to enhance your site's visibility and user experience without requiring additional configuration.
โ๏ธ Automatic SEO Handling โ
SEO Meta Generation Flow โ
Generated tags:
| Tag | Example |
|---|---|
| HTML attributes | <html lang="en" dir="ltr"> |
| Canonical | <link rel="canonical" href="..."> |
| hreflang | <link rel="alternate" hreflang="en" href="..."> |
| x-default | <link rel="alternate" hreflang="x-default" href="..."> |
| Open Graph | <meta property="og:locale" content="en_US"> |
og per locale (og:locale vs BCP 47) โ
<html lang> and hreflang use BCP 47 via locale.iso (e.g. ar-AE).
Open Graph requires language_TERRITORY with an underscore (ar_AE), per the OG protocol.
By default, og:locale is derived from iso when the mapping is unambiguous (en-US โ en_US).
Set an explicit og string when you need a custom value (e.g. zh-Hans โ zh_CN).
If neither og nor a convertible iso is available, og:locale tags are not generated โ in development you get a console warning (respects missingWarn).
i18n: {
meta: true,
locales: [
{ code: 'ar', iso: 'ar-AE', og: 'ar_AE', dir: 'rtl' },
{ code: 'en', iso: 'en-US' }, // og:locale โ en_US
{ code: 'zh', iso: 'zh-Hans', og: 'zh_CN' }, // script tags need explicit og
],
}๐ Key SEO Features โ
When the meta option is enabled in Nuxt I18n Micro, the module automatically manages the following SEO aspects:
๐ Language and Direction Attributes:
- The module sets the
langanddirattributes on the<html>tag according to the current locale and text direction (e.g.,ltrfor English orrtlfor Arabic).
- The module sets the
๐ Canonical URLs:
- The module generates a canonical link (
<link rel="canonical">) for each page, ensuring that search engines recognize the primary version of the content.
- The module generates a canonical link (
๐ Alternate Language Links (
hreflang):- The module automatically generates
<link rel="alternate" hreflang="">tags for all available locales. This helps search engines understand which language versions of your content are available, improving the user experience for global audiences. - Each locale emits one tag:
hreflang = iso || code. Whenisois set, routingcodeis never used ashreflang(so market keys likemxdo not become invalid language tags). - Optional
hreflangBaseLanguage: truealso emits a bare-language tag derived fromiso(e.g.es-ESโes), claimed by the first regional locale inlocales.
- The module automatically generates
๐
x-defaultHreflang:- The module automatically generates a
<link rel="alternate" hreflang="x-default">tag pointing to the default locale's URL. This tells search engines which URL to show users whose language doesn't match any of the defined locales. No additional configuration is required โ it works automatically whenmeta: trueis set.
- The module automatically generates a
๐ Open Graph Metadata:
- The module generates Open Graph meta tags (
og:locale,og:url, etc.) for each locale, which is particularly useful for social media sharing and search engine indexing.
- The module generates Open Graph meta tags (
๐ ๏ธ Configuration โ
To enable these SEO features, ensure the meta option is set to true in your nuxt.config.ts file:
export default defineNuxtConfig({
modules: ['nuxt-i18n-micro'],
i18n: {
locales: [
{ code: 'en', iso: 'en-US', dir: 'ltr' },
{ code: 'fr', iso: 'fr-FR', dir: 'ltr' },
{ code: 'ar', iso: 'ar-SA', dir: 'rtl' },
],
defaultLocale: 'en',
translationDir: 'locales',
meta: true, // Enables automatic SEO management
},
})๐ Dynamic metaBaseUrl for Multi-Domain Deployments โ
When metaBaseUrl is unset, absolute SEO URLs resolve in this order (#240):
site.urlfromnuxt-site-config(if that module is present โ e.g. via@nuxtjs/seo)- Otherwise the hostname from the current request (
useRequestURL()/window.location.origin)
The request-origin fallback respects reverse-proxy headers (X-Forwarded-Host, X-Forwarded-Proto), so it works correctly behind nginx, Cloudflare, AWS ALB, and similar proxies.
That means apps already setting site.url for sitemap / robots / schema.org do not need a second metaBaseUrl declaration:
export default defineNuxtConfig({
site: {
url: process.env.NUXT_SITE_URL, // also used by micro for canonical / og:url / hreflang
},
i18n: {
meta: true,
// metaBaseUrl omitted โ picks up site.url, then request origin
},
})Without site.url, a single application instance can still serve multiple domains with correct SEO tags for each via the request origin:
export default defineNuxtConfig({
i18n: {
meta: true,
// metaBaseUrl is undefined by default โ resolved dynamically from the request
},
})For example, a request to https://site-a.com/en/about will produce:
<link rel="canonical" href="https://site-a.com/en/about" /> <meta property="og:url" content="https://site-a.com/en/about" />While the same app serving https://site-b.com/en/about will produce:
<link rel="canonical" href="https://site-b.com/en/about" /> <meta property="og:url" content="https://site-b.com/en/about" />If you need a fixed base URL that always wins over site.url, pass a static string:
metaBaseUrl: 'https://example.com'๐ Canonical Query Whitelist โ
By default, query parameters are stripped from canonical and og:url to avoid duplicate content. You can whitelist specific query parameters that should be preserved:
i18n: {
canonicalQueryWhitelist: ['page', 'sort', 'filter', 'search', 'q', 'query', 'tag']
}Only parameters listed in canonicalQueryWhitelist will appear in canonical URLs. All other query parameters (e.g. tracking, session IDs) are removed.
๐ซ Disabling Meta Tags Per Page โ
You can disable SEO meta tag generation for specific pages using defineI18nRoute():
<script setup>
// Disable all SEO meta tags for this page
defineI18nRoute({
disableMeta: true,
})
</script>You can also disable meta only for specific locales:
<script setup>
// Disable meta tags only for English locale on this page
defineI18nRoute({
disableMeta: ['en'],
})
</script>When disableMeta is active, no hreflang, canonical, og:locale, og:url, or x-default tags are generated for the affected page/locale.
๐ Disabled Locales โ
Locales with disabled: true are automatically excluded from all SEO tag generation โ no hreflang, og:locale:alternate, or alternate links are created for them:
i18n: {
locales: [
{ code: 'en', iso: 'en-US' },
{ code: 'fr', iso: 'fr-FR', disabled: true }, // excluded from SEO tags
]
}๐ Opt-out locales (seo: false) โ
For locales that should remain routable and translated but should not appear in cross-locale discovery tags, set seo: false. Those locales are omitted from hreflang alternates and og:locale:alternate. If your configured default locale has seo: false, the x-default link is not emitted either.
i18n: {
locales: [
{ code: 'en', iso: 'en-US' },
{ code: 'ru', iso: 'ru-RU', seo: false }, // internal / non-indexed locale
]
}๐ Strategy-Specific Behavior โ
| Strategy | hreflang links | x-default | canonical | og:url |
|---|---|---|---|---|
prefix | โ All locales | โ Default locale URL | โ Current URL | โ |
prefix_except_default | โ All locales | โ Unprefixed URL | โ Current URL | โ |
prefix_and_default | โ All locales | โ Default locale URL | โ Current URL | โ |
no_prefix | โ Not generated | โ Not generated | โ Current URL | โ |
For the no_prefix strategy, only canonical, og:url, og:locale, and html attributes (lang, dir) are generated. Alternate language links (hreflang) and x-default are not generated because there are no distinct URLs per locale.
Page-level overrides (useI18nHead) โ
For articles, guides, or any CMS content where not every locale exists or URLs come from an API, use useI18nHead on the page instead of a custom i18n head plugin.
Article with partial translations โ
<script setup lang="ts">
const article = await loadArticle()
// article.locales = { en: '...', de: '...' } โ only translated locales
useI18nHead({
meta: [{ property: 'og:title', content: article.title }],
replace: {
hreflang: Object.entries(article.locales).map(([locale, href]) => ({
rel: 'alternate',
hreflang: locale,
href,
})),
ogAlternates: Object.keys(article.locales),
},
})
</script>Per-locale slugs with $setI18nRouteParams โ
When slugs differ per language, set route params first, then override alternates with real URLs:
<script setup lang="ts">
const { $defineI18nRoute, $setI18nRouteParams } = useNuxtApp()
const { data: article } = await useFetch(`/api/articles/${slug}`)
$defineI18nRoute({
localeRoutes: { en: '/blog/[slug]', de: '/de/blog/[slug]' },
})
$setI18nRouteParams({
en: { slug: article.value.slugEn },
de: { slug: article.value.slugDe },
})
useI18nHead({
replace: {
hreflang: ['en', 'de'].map((locale) => ({
rel: 'alternate',
hreflang: locale,
href: article.value.urls[locale],
})),
ogAlternates: ['en', 'de'],
},
})
</script>HTTPS origin behind a proxy โ
For correct absolute URLs on SSR without a custom origin composable:
i18n: {
meta: true,
metaBaseUrl: undefined,
metaTrustForwardedHost: true,
metaTrustForwardedProto: true,
}More examples (canonical override, x-default, reactive fetch, shared helpers): useI18nHead composable.
โ ๏ธ Trailing Slash โ
The module generates canonical and hreflang URLs based on the actual path from useRoute().fullPath. If your application uses trailing slashes (e.g., via Nuxt's router.options), the generated URLs will reflect this. However, $switchLocalePath may normalize paths and remove trailing slashes. If trailing slash consistency is critical for your SEO, verify the generated URLs match your application's URL structure.
๐ฏ Benefits โ
By enabling the meta option, you benefit from:
- ๐ Improved Search Engine Rankings: Search engines can better index your site, understanding the relationships between different language versions.
- ๐ฅ Better User Experience: Users are served the correct language version based on their preferences, leading to a more personalized experience.
- ๐ง Reduced Manual Configuration: The module handles SEO tasks automatically, freeing you from the need to manually add SEO-related meta tags and attributes.
๐ Nuxt SEO (@nuxtjs/seo) โ
@nuxtjs/seo bundles sitemap, robots, schema.org, OG images, and related modules. It integrates with nuxt-i18n-micro through nuxt-site-config (v4+).
Requirements โ
@nuxtjs/seo3+ (current releases usenuxt-site-config4+, which registers thenuxt-site-config:i18nplugin for micro)i18n.meta: true(recommended โ micro supplies locale-aware head tags; Nuxt SEO adds sitemap, schema.org, etc.)
Module order โ
List nuxt-i18n-micro before @nuxtjs/seo so site config can read your locale setup:
export default defineNuxtConfig({
modules: ['nuxt-i18n-micro', '@nuxtjs/seo'],
site: {
url: 'https://example.com',
name: 'My Site',
},
i18n: {
meta: true,
defaultLocale: 'en',
locales: [
{ code: 'en', iso: 'en-US' },
{ code: 'de', iso: 'de-DE' },
],
},
})Translated site name & description โ
Nuxt Site Config reads optional translation keys from your locale files:
{
"nuxtSiteConfig": {
"name": "My Site",
"description": "My site description"
}
}Per-locale values in locales/en.json, locales/de.json, etc. are picked up automatically.
Troubleshooting โ
If you see Plugin nuxt-seo:defaults depends on nuxt-site-config:i18n but they are not registered, upgrade @nuxtjs/seo to 3+ (see issue #133). Older nuxt-site-config 3.x only wired i18n for @nuxtjs/i18n, not micro.