Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Clarify using params in sitemap #1275

Merged
merged 2 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading