Blog/Webfejlesztés
Többnyelvű SEO Nuxt i18n-nel: URL-stratégia, hreflang, canonical és sitemap
Így állítsd be a Nuxt i18n modult, hogy a keresők minden nyelvet indexeljenek: útvonal-stratégia, useLocaleHead, hreflang, részleges fordítás, sitemap.
Balázs Csorba··8 perc olvasás
- Nuxt
- i18n
- SEO
- hreflang
- Multilingual

A lényeg röviden
- Minden nyelvnek legyen saját URL-je; a Google ezt ajánlja a sütik vagy a böngészőbeállítások helyett, a Googlebot pedig nem küld Accept-Language fejlécet.
- A @nuxtjs/i18n-ben minden locale-nál add meg a language értéket és az éles baseUrl-t, a useLocaleHead pedig lang, hreflang, og:locale és canonical tageket ad.
- A hreflang-készlet minden változaton azonos legyen, tartalmazza magát az oldalt, teljes URL-eket és érvényes ISO-nyelvkódokat használjon.
- A kevesebb nyelven létező oldalaknál csak a valódi fordításokat sorold fel, a lefordítatlan másolatok canonicalja pedig az eredetire mutasson.
- Ne irányíts át a böngésző nyelve alapján; adj valódi linkekből álló nyelvválasztót, és a hreflang vigye a keresőket a megfelelő változatra.
Egy többnyelvű Nuxt-oldal a látogatóknak tökéletesnek tűnhet, a keresőmotorok számára mégis félig láthatatlan lehet: a német oldalak nincsenek indexelve, a Google a magyar keresőknek az angol oldalt mutatja, vagy két nyelvi változat versenyez ugyanarra a keresésre. Az ok szinte mindig az oldal headjében van: hiányzó vagy ellentmondásos hreflang linkek, rossz nyelvre mutató canonical, vagy olyan URL-stratégia, amely sütik mögé rejti a nyelveket.
A cikk egy olyan @nuxtjs/i18n beállítást mutat be, amelyet a keresők értenek, ezt az oldalt használva példaként: statikusan generálódik angolul, németül és magyarul. Szó lesz az útvonal-stratégiáról, a useLocaleHead-ről, a Google dokumentációjának hreflang-szabályairól, a csak egyes nyelveken létező oldalakról, a sitemapekről, és arról, miért árt az automatikus nyelvi átirányítás.
Milyen URL-stratégiát használjon egy többnyelvű Nuxt-oldal?
A Google többnyelvű oldalakra vonatkozó ajánlása egyértelmű: minden nyelvi változatnak legyen saját URL-je, sütik vagy böngészőbeállítások helyett. Ha egy URL-en a nyelv szerint változik a tartalom, a Google nem biztos, hogy minden változatot megtalál, mert a Googlebot általában az USA-ból, Accept-Language fejléc nélkül kér le oldalakat. A Nuxt i18n négy útvonal-stratégiát kínál:
| Stratégia | URL-ek | SEO-szempontból |
|---|---|---|
prefix_except_default | /blog, /de/blog, /hu/blog | Jó alapértelmezés; a fő nyelv tiszta URL-eket kap |
prefix | /en/blog, /de/blog, /hu/blog | Jó; szimmetrikus, a gyökérhez átirányítás vagy nyelvválasztó kell |
prefix_and_default | /blog and /en/blog, /de/blog | Működik, de duplikátumokat hoz létre; a canonical az előtag nélküli URL-re mutat |
no_prefix | /blog for all | Nyilvános tartalomnál kerüld; egy URL csak egy nyelven indexelhető |
Az egy domainen belüli alkönyvtárak üzemeltetése is a legolcsóbb. Külön országos domain akkor indokolt, ha az üzlet országonként valóban különálló; egy második nyelv kiszolgálásához nem kell.
Hogyan konfiguráld a @nuxtjs/i18n modult SEO-hoz?
Két beállítás kell ahhoz, hogy az SEO-funkciók helyes kimenetet adjanak: minden locale-nak kell egy language címke, ebből lesz a hreflang értéke és a <html lang>, a baseUrl pedig az éles origin legyen, mert a hreflang és a canonical URL-eknek teljesnek kell lenniük. Ennek az oldalnak a konfigurációja:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
baseUrl: 'https://balazscsorba.com',
strategy: 'prefix_except_default',
defaultLocale: 'en',
locales: [
{ code: 'en', language: 'en-US', name: 'English', file: 'en.json' },
{ code: 'de', language: 'de-AT', name: 'Deutsch', file: 'de.json' },
{ code: 'hu', language: 'hu-HU', name: 'Magyar', file: 'hu.json' },
],
// No automatic redirect by browser language; the switcher links to every version.
detectBrowserLanguage: false,
},
})
Mit tesz a useLocaleHead az oldal headjébe?
A useLocaleHead() olyan head-metaadatot ad vissza, amelyet a useHead-nek adsz át: a <html> lang attribútumát, minden beállított locale-hoz egy hreflang-os alternate linket, og:locale és og:locale:alternate metatageket, valamint egy canonical linket. Hívd meg egyszer az app.vue-ban, így minden oldal megkapja.
<!-- app.vue -->
<script setup lang="ts">
const i18nHead = useLocaleHead({ dir: true, seo: true })
useHead(() => ({
htmlAttrs: { lang: i18nHead.value.htmlAttrs?.lang },
link: [...(i18nHead.value.link ?? [])],
meta: [...(i18nHead.value.meta ?? [])],
}))
</script>
Egy /de/blog/post oldalon a renderelt head ekkor tartalmazza a <html lang="de-AT"> elemet, egy canonical linket a német URL-re, és alternate linkeket az en-US, de-AT és hu-HU értékekre. A modul nyelvcsoportonként egy gyűjtő linket is hozzáad, például hreflang="en", valamint egy x-default-ot. Oldaltípusonként egyszer nézd meg a generált HTML-t; könnyű azt hinni, hogy a head rendben van, csak mert a modul telepítve van.
Mely hreflang-szabályokat rontják el gyakran?
A Google hreflang-dokumentációja rövid, és az auditokban talált hibák többsége ezek közül sért meg egyet:
- Az oldal önmagát is sorolja fel. Minden változat változatonként egy linket tartalmaz, önmagát is, és a készlet minden változaton azonos.
- Teljes URL-eket használj, protokollal és hoszttal. A relatív href többnyire hiányzó
baseUrlkövetkezménye. - Érvényes kódokat használj: ISO 639-1 szerinti nyelvet, opcionálisan ISO 3166-1 szerinti régióval (
de-AT). A régió önmagában nem működik, az olyan kódok pedig, mint azes-419, nem támogatottak. - Adj hozzá
x-default-ot azoknak a felhasználóknak, akiknek a nyelve egyik változathoz sem illik; ez általában az alapértelmezett nyelvű oldal. - A canonical minden nyelvi változaton önmagára mutasson. Egy német oldal, amelynek canonicalja az angolra mutat, azt üzeni a Google-nek, hogy hagyja el a németet.
Még egy fontos tény: a Google szerint sem a hreflangot, sem a lang attribútumot nem használja az oldal nyelvének felismerésére, hanem a tartalomból ismeri fel. Egy lefordított sablon lefordítatlan szövegtörzzsel továbbra is angol oldal.
Mi a helyzet a csak egyes nyelveken létező oldalakkal?
A prefix_except_default stratégiával a Nuxt minden locale-hoz útvonalat generál, így egy csak angol cikk is megjelenik a /de/blog/post címen, német navigációval és angol szöveggel. Ha nem nyúlsz hozzá, a useLocaleHead német fordításként hirdeti, a német másolat canonicalja pedig önmagára mutat. Ez az oldal mindkettőt az app.vue-ban javítja: a kevesebb nyelven létező oldal bejelenti a nyelveit, a hreflang ekkor csak ezeket sorolja fel, a lefordítatlan másolatok canonicalja pedig az angol eredetire mutat.
// app.vue (excerpt): pageLocales is set by pages that exist in fewer languages
const headLinks = computed(() => {
const links = i18nHead.value.link ?? []
const only = pageLocales.value
if (!only || only.path !== route.path) return links
return links
.filter((l) => l.rel !== 'alternate' || !l.hreflang || l.hreflang === 'x-default'
|| only.locales.some((c) => l.hreflang.startsWith(c)))
.map((l) => (l.rel === 'canonical' && !only.translated
? { ...l, href: `${siteUrl}${switchLocalePath('en')}` }
: l))
})
A másik lehetőség, hogy a lefordítatlan útvonalakat egyáltalán nem generálod, hanem 404-et vagy az eredetire mutató átirányítást adsz. Ez a keresőknek tisztább, de rosszabb annak a látogatónak, aki németre állította a felületet, és úgy is akarja hagyni. Mindkettő működik, amíg a head igazat mond arról, mely fordítások léteznek.
A hreflang a sitemapbe is kerüljön?
A Google három helyen fogadja el a hreflangot – HTML-tagekben, HTTP-fejlécekben és a sitemapben –, egyenértékűnek tekinti őket, és szerinte több módszer együtt nem ad előnyt a keresésben, csak a karbantartást nehezíti. A HTTP-fejléc főleg nem HTML-fájloknál, például PDF-eknél hasznos. Ez az oldal head-tageket és sitemap-bejegyzéseket is kiad, mert mindkettő buildkor ugyanabból a bejegyzésadatból készül, így nem tudnak elcsúszni egymástól. Ha nálad különböző kódutakból jönnek, válassz egyet.
<url>
<loc>https://balazscsorba.com/de/blog/agent-loop-explained</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://balazscsorba.com/blog/agent-loop-explained"/>
<xhtml:link rel="alternate" hreflang="de" href="https://balazscsorba.com/de/blog/agent-loop-explained"/>
<xhtml:link rel="alternate" hreflang="hu" href="https://balazscsorba.com/hu/blog/agent-loop-explained"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://balazscsorba.com/blog/agent-loop-explained"/>
</url>
Miért ne irányítsd át a látogatókat a böngésző nyelve szerint?
A Google nem javasolja, hogy a feltételezett nyelvük alapján irányítsd át a felhasználókat egy nyelvi változatra, mert ez megakadályozhatja, hogy a felhasználók és a keresők minden változatot elérjenek. A Nuxt i18n detectBrowserLanguage beállítása az első látogatáskor átirányíthat; nyilvános oldalon kikapcsolom, és helyette két dologra építek: a hreflangra, amely a találati oldalról közvetlenül a megfelelő változatra viszi a keresőket, és egy valódi linkekből álló nyelvválasztóra, amelyet a crawlerek is követhetnek.
Mit kell még lefordítani a többnyelvű SEO-hoz?
- Címek és meta-leírások locale-onként. Ezeket olvassák a keresők a találatok között; egy angol című német oldal kattintásokat veszít.
- Strukturált adat
inLanguageértékkel, amely illik az oldalhoz, hogy az AI-keresés és a bővített találatok a megfelelő változatot idézzék. Erről az oldal GEO-auditjában írtam. - Képek alt szövege és az Open Graph-képek lokalizált szöveggel, ha a kép szavakat tartalmaz.
- A belső linkek maradjanak a nyelven belül. Mindenhol
localePath()-ot használj, hogy egy német cikk német oldalakra hivatkozzon, és ne terelje vissza a látogatókat az angolra.
A teljesítmény minden nyelven ugyanannyira számít; ugyanazok a szabályok érvényesek, mint a Core Web Vitals Nuxthoz cikkben, a locale-onként lustán betöltött üzenetfájlok pedig kicsiben tartják a bundle-t.
Hogyan ellenőrizd a beállítást?
Kérd le oldaltípusonként és nyelvenként egy oldal generált HTML-jét, és hasonlítsd össze a linkkészleteket; egy rövid szkript elkapja a szokásos hibákat, mielőtt a Search Console hetekkel később tenné.
// check-hreflang.mjs: every version must list the same set, including itself
const pages = ['/blog/agent-loop-explained', '/de/blog/agent-loop-explained', '/hu/blog/agent-loop-explained']
const base = 'https://balazscsorba.com'
const sets = await Promise.all(pages.map(async (p) => {
const html = await (await fetch(base + p)).text()
const attr = (tag, name) => tag.match(new RegExp(` ${name}="([^"]+)"`))?.[1]
const tags = html.match(/<link[^>]*>/g) ?? []
const links = tags.filter((t) => attr(t, 'rel') === 'alternate' && attr(t, 'hreflang'))
.map((t) => [attr(t, 'hreflang'), attr(t, 'href')])
const canonical = attr(tags.find((t) => attr(t, 'rel') === 'canonical') ?? '', 'href')
if (canonical !== base + p) console.warn(`${p}: canonical is ${canonical}`)
if (!links.some(([, href]) => href === base + p)) console.warn(`${p}: does not list itself`)
return links.map(([lang, href]) => `${lang} ${href}`).sort().join('\n')
}))
console.log(new Set(sets).size === 1 ? 'hreflang sets match' : 'hreflang sets differ')
Források
Gyakori kérdések
Melyik Nuxt i18n útvonal-stratégia a legjobb SEO-hoz?
A prefix_except_default és a prefix is saját URL-t ad minden nyelvnek, ahogy a Google ajánlja. A prefix_except_default az alapértelmezett nyelvet előtag nélkül hagyja. Nyilvános tartalomnál kerüld a no_prefix stratégiát, mert minden nyelv ugyanazon az URL-en osztozik, és a keresők csak az egyiket tudják indexelni.
A useLocaleHead automatikusan előállítja a hreflangot?
Igen. Visszaadja a html elem lang attribútumát, minden beállított locale-hoz egy hreflang-os alternate linket, az og:locale tageket és egy canonical linket. Ehhez minden locale-nak kell egy language érték, a modulnak pedig baseUrl, hogy az URL-ek teljesek legyenek.
Kell x-default?
Ajánlott. A Google az x-default változatot azoknak a felhasználóknak mutatja, akiknek a nyelve egyik változathoz sem illik. A legtöbb oldalon az alapértelmezett nyelvű változatra vagy egy nyelvválasztó oldalra mutat.
A hreflang a HTML headbe vagy a sitemapbe kerüljön?
Bármelyikbe. A Google egyenértékűnek tekinti a HTML-tageket, a HTTP-fejléceket és a sitemap-bejegyzéseket, és szerinte több módszer együtt nem ad pluszt. Azt válaszd, amelyiket helyesen tudod tartani; egy adatforrásból generált statikus oldalnál mindkettő jöhet ugyanabból a kódból.
Használja a Google a hreflangot az oldal nyelvének felismerésére?
Nem. A Google szerint a nyelvet saját algoritmusaival a tartalomból ismeri fel; a hreflang csak azt mondja meg, mely URL-ek ugyanannak az oldalnak a lokalizált változatai. Egy angol szöveggel teli „német” oldal a Google számára attól még angol.