Skip to content

Commit

Permalink
docs: Clarify using params in sitemap (#1275)
Browse files Browse the repository at this point in the history
Fixes #1274
  • Loading branch information
amannn authored Aug 21, 2024
1 parent 6662ba1 commit e47a693
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 54 deletions.
69 changes: 44 additions & 25 deletions docs/pages/docs/environments/actions-metadata-route-handlers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,7 @@ Next.js supports providing alternate URLs per language via the [`alternates` ent
<Tabs items={['Shared pathnames', 'Localized pathnames']}>
<Tab>

If you're use the same pathnames for all locales (i.e. you're not using the [`pathnames`](/docs/routing#pathnames) setting), you can iterate over an array of pathnames that your app supports and generate a sitemap entry for each pathname.

**Example:**
If you're use the same pathnames for all locales (i.e. you're not using the [`pathnames`](/docs/routing#pathnames) setting), you can assemble the sitemap based on the pathnames that your app supports.

```tsx
import {MetadataRoute} from 'next';
Expand All @@ -170,59 +168,80 @@ const defaultLocale = 'en' as const;
const locales = ['en', 'de'] as const;

// Adapt this as necessary
const pathnames = ['/', '/about'];
const host = 'https://acme.com';

export default function sitemap(): MetadataRoute.Sitemap {
function getUrl(pathname: string, locale: string) {
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
// Adapt this as necessary
return [
getEntry('/'),
getEntry('/users'),
getEntry('/users/1'),
getEntry('/users/2')
];
}

return pathnames.map((pathname) => ({
function getEntry(pathname: string) {
return {
url: getUrl(pathname, defaultLocale),
lastModified: new Date(),
alternates: {
languages: Object.fromEntries(
locales.map((locale) => [locale, getUrl(pathname, locale)])
)
}
}));
};
}

function getUrl(pathname: string, locale: string) {
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
```

</Tab>
<Tab>

If you're using the [`pathnames`](/docs/routing#pathnames) setting, you can use the keys of your already declared `pathnames` and generate an entry for each locale via the [`getPathname`](/docs/routing/navigation#getpathname) function.
If you're using the [`pathnames`](/docs/routing#pathnames) setting, you can generate sitemap entries for each locale by using the [`getPathname`](/docs/routing/navigation#getpathname) function.

```tsx
import {MetadataRoute} from 'next';
import {locales, pathnames, defaultLocale} from '@/config';
import {locales, defaultLocale} from '@/config';
import {getPathname} from '@/navigation';

// Adapt this as necessary
const host = 'https://acme.com';

export default function sitemap(): MetadataRoute.Sitemap {
const keys = Object.keys(pathnames) as Array<keyof typeof pathnames>;

function getUrl(
key: keyof typeof pathnames,
locale: (typeof locales)[number]
) {
const pathname = getPathname({locale, href: key});
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
// Adapt this as necessary
return [
getEntry('/'),
getEntry('/users'),
getEntry({
pathname: '/users/[id]',
params: {id: '1'}
}),
getEntry({
pathname: '/users/[id]',
params: {id: '2'}
})
];
}

return keys.map((key) => ({
url: getUrl(key, defaultLocale),
lastModified: new Date(),
type Href = Parameters<typeof getPathname>[0]['href'];

function getEntry(href: Href) {
return {
url: getUrl(href, defaultLocale),
alternates: {
languages: Object.fromEntries(
locales.map((locale) => [locale, getUrl(key, locale)])
locales.map((locale) => [locale, getUrl(href, locale)])
)
}
}));
};
}

function getUrl(href: Href, locale: (typeof locales)[number]) {
const pathname = getPathname({locale, href});
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
```

Expand Down
11 changes: 4 additions & 7 deletions docs/pages/docs/routing/navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,10 @@ const router = useRouter();
const params = useParams();

router.replace(
{
pathname,
// @ts-expect-error -- TypeScript will validate that only known `params`
// are used in combination with a given `pathname`. Since the two will
// always match for the current route, we can skip runtime checks.
params
},
// @ts-expect-error -- TypeScript will validate that only known `params`
// are used in combination with a given `pathname`. Since the two will
// always match for the current route, we can skip runtime checks.
{pathname, params},
{locale: 'de'}
);
```
Expand Down
27 changes: 14 additions & 13 deletions examples/example-app-router/src/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import {MetadataRoute} from 'next';
import {locales, pathnames, defaultLocale, host} from '@/config';
import {locales, defaultLocale, host} from '@/config';
import {getPathname} from '@/navigation';

export default function sitemap(): MetadataRoute.Sitemap {
const keys = Object.keys(pathnames) as Array<keyof typeof pathnames>;
return [getEntry('/'), getEntry('/pathnames')];
}

function getUrl(
key: keyof typeof pathnames,
locale: (typeof locales)[number]
) {
const pathname = getPathname({locale, href: key});
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
type Href = Parameters<typeof getPathname>[0]['href'];

return keys.map((key) => ({
url: getUrl(key, defaultLocale),
function getEntry(href: Href) {
return {
url: getUrl(href, defaultLocale),
alternates: {
languages: Object.fromEntries(
locales.map((locale) => [locale, getUrl(key, locale)])
locales.map((locale) => [locale, getUrl(href, locale)])
)
}
}));
};
}

function getUrl(href: Href, locale: (typeof locales)[number]) {
const pathname = getPathname({locale, href});
return `${host}/${locale}${pathname === '/' ? '' : pathname}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,10 @@ export default function LocaleSwitcherSelect({
const nextLocale = event.target.value as Locale;
startTransition(() => {
router.replace(
{
pathname,
// @ts-expect-error -- TypeScript will validate that only known `params`
// are used in combination with a given `pathname`. Since the two will
// always match for the current route, we can skip runtime checks.
params
},
// @ts-expect-error -- TypeScript will validate that only known `params`
// are used in combination with a given `pathname`. Since the two will
// always match for the current route, we can skip runtime checks.
{pathname, params},
{locale: nextLocale}
);
});
Expand Down
8 changes: 6 additions & 2 deletions examples/example-app-router/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import {Pathnames, LocalePrefix} from 'next-intl/routing';
export const defaultLocale = 'en' as const;
export const locales = ['en', 'de'] as const;

export const pathnames: Pathnames<typeof locales> = {
export const pathnames = {
'/': '/',
'/pathnames': {
en: '/pathnames',
de: '/pfadnamen'
},
'/users/[id]': {
en: '/users/[id]',
de: '/benutzer/[id]'
}
};
} satisfies Pathnames<typeof locales>;

export const localePrefix: LocalePrefix<typeof locales> = 'always';

Expand Down

0 comments on commit e47a693

Please sign in to comment.