Skip to content

Commit 7e16aec

Browse files
ap-artoapavlovskyBobbieGoede
authored
fix: differentDomains with no_prefix missing alternate links (#3493)
* respect differentDomains in getHreflangLinks * fix: do not append domain to baseurl * test: assert correct domain is used --------- Co-authored-by: apavlovsky <apavlovsky@greengeeks.com> Co-authored-by: Bobbie Goede <bobbiegoede@gmail.com>
1 parent f6f2a47 commit 7e16aec

7 files changed

Lines changed: 122 additions & 9 deletions

File tree

pnpm-lock.yaml

Lines changed: 12 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

specs/fixtures/domain-ssg/app.vue

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<template>
2+
<Html :lang="head.htmlAttrs.lang" :dir="head.htmlAttrs.dir">
3+
<Head>
4+
<Title>Test</Title>
5+
<template v-for="link in head.link" :key="link.hid">
6+
<Link :id="link.hid" :rel="link.rel" :href="link.href" :hreflang="link.hreflang" />
7+
</template>
8+
<template v-for="meta in head.meta" :key="meta.hid">
9+
<Meta :id="meta.hid" :property="meta.property" :content="meta.content" />
10+
</template>
11+
</Head>
12+
<Body>
13+
<NuxtPage />
14+
</Body>
15+
</Html>
16+
</template>
17+
18+
<script setup lang="ts">
19+
const head = useLocaleHead()
20+
</script>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// https://nuxt.com/docs/api/configuration/nuxt-config
2+
export default defineNuxtConfig({
3+
modules: ['@nuxtjs/i18n'],
4+
5+
i18n: {
6+
strategy: 'no_prefix',
7+
defaultLocale: 'en',
8+
differentDomains: true,
9+
locales: [
10+
{ code: 'en', language: 'en-US', name: 'English', domain: 'localhost:7786', isCatchallLocale: true },
11+
{ code: 'es', language: 'es-ES', name: 'Español', domain: 'localhost:7787' }
12+
],
13+
baseUrl: 'http://localhost:3333',
14+
detectBrowserLanguage: false
15+
},
16+
17+
compatibilityDate: '2025-03-30'
18+
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "fixture-domain-ssg",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"build": "nuxi build",
7+
"dev": "nuxi dev",
8+
"generate": "nuxi generate",
9+
"preview": "nuxi preview"
10+
},
11+
"devDependencies": {
12+
"@nuxtjs/i18n": "latest",
13+
"nuxt": "latest"
14+
}
15+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<div>Hello</div>
3+
</template>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { test, expect } from 'vitest'
2+
import { fileURLToPath } from 'node:url'
3+
import { setup, $fetch } from '../utils'
4+
import { getDom } from '../helper'
5+
6+
await setup({
7+
rootDir: fileURLToPath(new URL(`../fixtures/domain-ssg`, import.meta.url)),
8+
browser: true,
9+
prerender: true,
10+
// overrides
11+
nuxtConfig: {},
12+
port: [7787, 7786]
13+
})
14+
15+
test('`differentDomains` with `no_prefix` has hreflang links', async () => {
16+
const html = await $fetch('/')
17+
const dom = getDom(html)
18+
expect(
19+
Array.from(dom.querySelectorAll(`[rel="alternate"]`)).map(x => ({
20+
// @ts-expect-error untyped var
21+
id: x.getAttribute('id'),
22+
// @ts-expect-error untyped var
23+
href: x.getAttribute('href')
24+
}))
25+
).toMatchInlineSnapshot(`
26+
[
27+
{
28+
"href": "http://localhost:7786",
29+
"id": "i18n-xd",
30+
},
31+
{
32+
"href": "http://localhost:7786",
33+
"id": "i18n-alt-en",
34+
},
35+
{
36+
"href": "http://localhost:7786",
37+
"id": "i18n-alt-en-US",
38+
},
39+
{
40+
"href": "http://localhost:7787",
41+
"id": "i18n-alt-es",
42+
},
43+
{
44+
"href": "http://localhost:7787",
45+
"id": "i18n-alt-es-ES",
46+
},
47+
]
48+
`)
49+
})

src/runtime/routing/head.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,10 @@ function _localeHead(common: CommonComposableOptions, options: Required<I18nHead
187187
}
188188

189189
function getHreflangLinks(common: CommonComposableOptions, ctx: HeadContext) {
190-
const { defaultLocale, strategy } = ctx.runtimeI18n
190+
const { defaultLocale, strategy, differentDomains } = ctx.runtimeI18n
191191
const links: MetaAttrs[] = []
192192

193-
if (strategy === 'no_prefix') return links
193+
if (strategy === 'no_prefix' && !differentDomains) return links
194194

195195
const localeMap = new Map<string, LocaleObject>()
196196
for (const locale of ctx.locales) {
@@ -219,10 +219,9 @@ function getHreflangLinks(common: CommonComposableOptions, ctx: HeadContext) {
219219
const localePath = switchLocalePath(common, mapLocale.code, routeWithoutQuery)
220220
if (!localePath) continue
221221

222-
const href = withQuery(
223-
joinURL(ctx.baseUrl, localePath),
224-
strictCanonicals ? getCanonicalQueryParams(common, ctx) : {}
225-
)
222+
// localized paths with domain already contain baseUrl
223+
const fullPath = differentDomains && mapLocale.domain ? localePath : joinURL(ctx.baseUrl, localePath)
224+
const href = withQuery(fullPath, strictCanonicals ? getCanonicalQueryParams(common, ctx) : {})
226225

227226
links.push({ [ctx.key]: `i18n-alt-${language}`, rel: 'alternate', href, hreflang: language })
228227
if (defaultLocale && defaultLocale === mapLocale.code) {

0 commit comments

Comments
 (0)