Skip to content

Commit 774460d

Browse files
authored
docs: Fix sitemap example (#1712)
[(ref)](#629 (reply in thread)) As a side note, it seems like currently all pages of the app router example are indexed correctly: ![Screenshot 2025-02-13 at 09 54 35](https://github.com/user-attachments/assets/0cfdc805-2c93-4ce0-bd1e-506990ae25c8) Let's check this again after some time to verify this is still the case.
1 parent 190ee1e commit 774460d

File tree

3 files changed

+31
-16
lines changed

3 files changed

+31
-16
lines changed

docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx

+14-9
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ If you're using a sitemap to inform search engines about all pages of your site,
169169

170170
Note that by default, `next-intl` returns [the `link` response header](/docs/routing#alternate-links) to instruct search engines that a page is available in multiple languages. While this sufficiently links localized pages for search engines, you may choose to provide this information in a sitemap in case you have more specific requirements.
171171

172-
Next.js supports providing alternate URLs per language via the [`alternates` entry](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-localized-sitemap) as of version 14.2. You can use your default locale for the main URL and provide alternate URLs based on all locales that your app supports. Keep in mind that also the default locale should be included in the `alternates` object.
172+
Next.js supports providing alternate URLs per language via the [`alternates` entry](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-localized-sitemap). You can construct a list of entries for each pathname and locale as follows:
173173

174174
```tsx filename="app/sitemap.ts" {4-5,8-9}
175175
import {MetadataRoute} from 'next';
@@ -180,20 +180,20 @@ const host = 'https://acme.com';
180180

181181
export default function sitemap(): MetadataRoute.Sitemap {
182182
// Adapt this as necessary
183-
return [getEntry('/'), getEntry('/users')];
183+
return [...getEntries('/'), ...getEntries('/users')];
184184
}
185185

186186
type Href = Parameters<typeof getPathname>[0]['href'];
187187

188-
function getEntry(href: Href) {
189-
return {
190-
url: getUrl(href, routing.defaultLocale),
188+
function getEntries(href: Href) {
189+
return routing.locales.map((locale) => ({
190+
url: getUrl(href, locale),
191191
alternates: {
192192
languages: Object.fromEntries(
193-
routing.locales.map((locale) => [locale, getUrl(href, locale)])
193+
routing.locales.map((cur) => [cur, getUrl(href, cur)])
194194
)
195195
}
196-
};
196+
}));
197197
}
198198

199199
function getUrl(href: Href, locale: (typeof routing.locales)[number]) {
@@ -206,15 +206,20 @@ Depending on if you're using the [`pathnames`](/docs/routing#pathnames) setting,
206206

207207
```tsx
208208
// 1. A final string (when not using `pathnames`)
209-
getEntry('/users/1');
209+
getEntries('/users/1');
210210

211211
// 2. An object (when using `pathnames`)
212-
getEntry({
212+
getEntries({
213213
pathname: '/users/[id]',
214214
params: {id: '1'}
215215
});
216216
```
217217

218+
**Keep in mind**:
219+
220+
- Each pathname should have a separate entry for every locale that your app supports.
221+
- Also the locale of a given pathname should be included in the `alternates` object.
222+
218223
([working implementation](https://github.com/amannn/next-intl/blob/main/examples/example-app-router/src/app/sitemap.ts))
219224

220225
### Route Handlers

examples/example-app-router/src/app/sitemap.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ import {host} from '@/config';
33
import {Locale, getPathname, routing} from '@/i18n/routing';
44

55
export default function sitemap(): MetadataRoute.Sitemap {
6-
return [getEntry('/'), getEntry('/pathnames')];
6+
return [...getEntries('/'), ...getEntries('/pathnames')];
77
}
88

99
type Href = Parameters<typeof getPathname>[0]['href'];
1010

11-
function getEntry(href: Href) {
12-
return {
13-
url: getUrl(href, routing.defaultLocale),
11+
function getEntries(href: Href) {
12+
return routing.locales.map((locale) => ({
13+
url: getUrl(href, locale),
1414
alternates: {
1515
languages: Object.fromEntries(
16-
routing.locales.map((locale) => [locale, getUrl(href, locale)])
16+
routing.locales.map((cur) => [cur, getUrl(href, cur)])
1717
)
1818
}
19-
};
19+
}));
2020
}
2121

2222
function getUrl(href: Href, locale: Locale) {

examples/example-app-router/tests/main.spec.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {test as it, expect} from '@playwright/test';
1+
import {expect, test as it} from '@playwright/test';
22

33
it('handles i18n routing', async ({page}) => {
44
await page.goto('/');
@@ -111,10 +111,20 @@ it('serves a sitemap.xml', async ({page}) => {
111111
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de" />
112112
</url>
113113
<url>
114+
<loc>http://localhost:3000/de</loc>
115+
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en" />
116+
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de" />
117+
</url>
118+
<url>
114119
<loc>http://localhost:3000/en/pathnames</loc>
115120
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/pathnames" />
116121
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de/pfadnamen" />
117122
</url>
123+
<url>
124+
<loc>http://localhost:3000/de/pfadnamen</loc>
125+
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/pathnames" />
126+
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de/pfadnamen" />
127+
</url>
118128
</urlset>
119129
`
120130
);

0 commit comments

Comments
 (0)