Skip to content

Commit e4eaf31

Browse files
committed
update playground to nextjs 15 canary and rootparams
1 parent c2af326 commit e4eaf31

File tree

14 files changed

+135
-164
lines changed

14 files changed

+135
-164
lines changed

examples/example-app-router-playground/next-env.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
/// <reference types="next/image-types/global" />
33

44
// NOTE: This file should not be edited
5-
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
5+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

examples/example-app-router-playground/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@
1212
"storybook": "storybook dev -p 6006"
1313
},
1414
"dependencies": {
15-
"@mdx-js/react": "^3.0.1",
15+
"@mdx-js/react": "^3.1.0",
1616
"@radix-ui/react-dropdown-menu": "^2.1.1",
1717
"lodash": "^4.17.21",
1818
"ms": "2.1.3",
19-
"next": "^14.2.4",
19+
"next": "15.1.1-canary.12",
2020
"next-intl": "^3.0.0",
2121
"react": "^18.3.1",
2222
"react-dom": "^18.3.1",
2323
"zod": "^3.23.8"
2424
},
2525
"devDependencies": {
2626
"@jest/globals": "^29.7.0",
27-
"@mdx-js/loader": "^3.0.1",
28-
"@next/mdx": "^14.2.5",
27+
"@mdx-js/loader": "^3.1.0",
28+
"@next/mdx": "15.1.1-canary.12",
2929
"@playwright/test": "^1.48.1",
3030
"@storybook/nextjs": "^8.2.9",
3131
"@storybook/react": "^8.2.9",
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import {Locale} from 'next-intl';
1+
import {getLocale} from 'next-intl/server';
22

3-
type Props = {
4-
params: {
5-
locale: Locale;
6-
};
7-
};
8-
9-
export default async function AboutPage({params}: Props) {
10-
const Content = (await import(`./${params.locale}.mdx`)).default;
3+
export default async function AboutPage() {
4+
const locale = await getLocale();
5+
const Content = (await import(`./${locale}.mdx`)).default;
116
return <Content />;
127
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
import {NextRequest, NextResponse} from 'next/server';
2-
import {Locale} from 'next-intl';
32
import {getTranslations} from 'next-intl/server';
43

5-
type Props = {
6-
params: {
7-
locale: Locale;
8-
};
9-
};
10-
11-
export async function GET(request: NextRequest, {params: {locale}}: Props) {
4+
export async function GET(request: NextRequest) {
125
const name = request.nextUrl.searchParams.get('name');
136
if (!name) {
147
return new Response('Search param `name` was not provided.', {status: 400});
158
}
169

17-
const t = await getTranslations({locale, namespace: 'ApiRoute'});
10+
const t = await getTranslations('ApiRoute');
1811
return NextResponse.json({message: t('hello', {name})});
1912
}

examples/example-app-router-playground/src/app/[locale]/layout.tsx

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {Metadata} from 'next';
2-
import {notFound} from 'next/navigation';
3-
import {Locale, NextIntlClientProvider, hasLocale} from 'next-intl';
2+
import {NextIntlClientProvider, useLocale} from 'next-intl';
43
import {
54
getFormatter,
65
getNow,
@@ -11,18 +10,17 @@ import {ReactNode} from 'react';
1110
import {routing} from '@/i18n/routing';
1211
import Navigation from '../../components/Navigation';
1312

14-
type Props = {
15-
children: ReactNode;
16-
params: {locale: Locale};
17-
};
13+
export async function generateStaticParams() {
14+
return routing.locales.map((locale) => ({locale}));
15+
}
16+
17+
export const dynamicParams = false;
1818

19-
export async function generateMetadata({
20-
params: {locale}
21-
}: Omit<Props, 'children'>): Promise<Metadata> {
22-
const t = await getTranslations({locale, namespace: 'LocaleLayout'});
23-
const formatter = await getFormatter({locale});
24-
const now = await getNow({locale});
25-
const timeZone = await getTimeZone({locale});
19+
export async function generateMetadata(): Promise<Metadata> {
20+
const t = await getTranslations('LocaleLayout');
21+
const formatter = await getFormatter();
22+
const now = await getNow();
23+
const timeZone = await getTimeZone();
2624

2725
return {
2826
metadataBase: new URL('http://localhost:3000'),
@@ -35,10 +33,12 @@ export async function generateMetadata({
3533
};
3634
}
3735

38-
export default function LocaleLayout({children, params: {locale}}: Props) {
39-
if (!hasLocale(routing.locales, locale)) {
40-
notFound();
41-
}
36+
type Props = {
37+
children: ReactNode;
38+
};
39+
40+
export default function LocaleLayout({children}: Props) {
41+
const locale = useLocale();
4242

4343
return (
4444
<html lang={locale}>
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
11
import {Metadata} from 'next';
2-
import {Locale, useTranslations} from 'next-intl';
2+
import {useTranslations} from 'next-intl';
3+
import {getLocale} from 'next-intl/server';
4+
import {use} from 'react';
35
import {getPathname} from '@/i18n/routing';
46

57
type Props = {
6-
params: {
7-
locale: Locale;
8+
params: Promise<{
89
articleId: string;
9-
};
10+
}>;
1011
};
1112

1213
export async function generateMetadata({params}: Props): Promise<Metadata> {
14+
const {articleId} = await params;
15+
const locale = await getLocale();
16+
1317
return {
1418
alternates: {
1519
canonical: getPathname({
1620
href: {
1721
pathname: '/news/[articleId]',
18-
params: {articleId: params.articleId}
22+
params: {articleId}
1923
},
20-
locale: params.locale
24+
locale
2125
})
2226
}
2327
};
2428
}
2529

2630
export default function NewsArticle({params}: Props) {
31+
const {articleId} = use(params);
2732
const t = useTranslations('NewsArticle');
28-
return <h1>{t('title', {articleId: params.articleId})}</h1>;
33+
return <h1>{t('title', {articleId})}</h1>;
2934
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import {ImageResponse} from 'next/og';
2-
import {Locale} from 'next-intl';
32
import {getTranslations} from 'next-intl/server';
43

5-
type Props = {
6-
params: {
7-
locale: Locale;
8-
};
9-
};
10-
11-
export default async function Image({params: {locale}}: Props) {
12-
const t = await getTranslations({locale, namespace: 'OpenGraph'});
4+
export default async function Image() {
5+
const t = await getTranslations('OpenGraph');
136
return new ImageResponse(<div style={{fontSize: 128}}>{t('title')}</div>);
147
}

examples/example-app-router-playground/src/app/[locale]/page.tsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import Image from 'next/image';
22
import {useFormatter, useNow, useTimeZone, useTranslations} from 'next-intl';
3+
import {use} from 'react';
34
import DropdownMenu from '@/components/DropdownMenu';
45
import RichText from '@/components/RichText';
56
import {Link} from '@/i18n/routing';
6-
import AsyncComponent from '../../components/AsyncComponent';
7+
import AsyncComponent, {
8+
AsyncComponentGerman
9+
} from '../../components/AsyncComponent';
710
import AsyncComponentWithNamespaceAndLocale from '../../components/AsyncComponentWithNamespaceAndLocale';
811
import AsyncComponentWithoutNamespace from '../../components/AsyncComponentWithoutNamespace';
912
import AsyncComponentWithoutNamespaceAndLocale from '../../components/AsyncComponentWithoutNamespaceAndLocale';
@@ -16,7 +19,7 @@ import MessagesAsPropsCounter from '../../components/client/01-MessagesAsPropsCo
1619
import MessagesOnClientCounter from '../../components/client/02-MessagesOnClientCounter';
1720

1821
type Props = {
19-
searchParams: Record<string, string>;
22+
searchParams: Promise<Record<string, string>>;
2023
};
2124

2225
export default function Index({searchParams}: Props) {
@@ -55,11 +58,14 @@ export default function Index({searchParams}: Props) {
5558
</Link>
5659
</div>
5760
<ClientLink href="/">Link on client without provider</ClientLink>
58-
<p data-testid="SearchParams">{JSON.stringify(searchParams, null, 2)}</p>
61+
<p data-testid="SearchParams">
62+
{JSON.stringify(use(searchParams), null, 2)}
63+
</p>
5964
<p data-testid="HasTitle">{JSON.stringify(t.has('title'))}</p>
6065
<Image alt="" height={77} priority src="/assets/image.jpg" width={128} />
6166
<AsyncComponent />
6267
<AsyncComponentWithNamespaceAndLocale />
68+
<AsyncComponentGerman />
6369
<AsyncComponentWithoutNamespace />
6470
<AsyncComponentWithoutNamespaceAndLocale />
6571
<DropdownMenu />

examples/example-app-router-playground/src/app/layout.tsx

-11
This file was deleted.

examples/example-app-router-playground/src/app/not-found.tsx

-17
This file was deleted.

examples/example-app-router-playground/src/components/AsyncComponentWithNamespaceAndLocale.tsx

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import {getLocale, getTranslations} from 'next-intl/server';
1+
import {getTranslations} from 'next-intl/server';
22

33
export default async function AsyncComponentWithNamespaceAndLocale() {
4-
const locale = await getLocale();
5-
const t = await getTranslations({locale, namespace: 'AsyncComponent'});
4+
const t = await getTranslations('AsyncComponent');
65

76
return (
87
<div data-testid="AsyncComponentWithoutNamespaceAndLocale">
@@ -12,11 +11,10 @@ export default async function AsyncComponentWithNamespaceAndLocale() {
1211
}
1312

1413
export async function TypeTest() {
15-
const locale = await getLocale();
16-
const t = await getTranslations({locale});
14+
const t = await getTranslations();
1715

1816
// @ts-expect-error
19-
await getTranslations({locale, namespace: 'Unknown'});
17+
await getTranslations('Unknown');
2018

2119
// @ts-expect-error
2220
t('AsyncComponent.unknown');

examples/example-app-router-playground/src/components/AsyncComponentWithoutNamespaceAndLocale.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import {getLocale, getTranslations} from 'next-intl/server';
1+
import {getTranslations} from 'next-intl/server';
22

33
export default async function AsyncComponentWithoutNamespaceAndLocale() {
4-
const locale = await getLocale();
5-
const t = await getTranslations({locale});
4+
const t = await getTranslations();
65

76
return (
87
<div data-testid="AsyncComponentWithoutNamespaceAndLocale">
@@ -12,8 +11,7 @@ export default async function AsyncComponentWithoutNamespaceAndLocale() {
1211
}
1312

1413
export async function TypeTest() {
15-
const locale = await getLocale();
16-
const t = await getTranslations({locale});
14+
const t = await getTranslations();
1715

1816
// @ts-expect-error
1917
t('AsyncComponent.unknown');

examples/example-app-router-playground/src/i18n/request.tsx

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {headers} from 'next/headers';
2+
import {unstable_rootParams as rootParams} from 'next/server';
23
import {Formats, hasLocale} from 'next-intl';
34
import {getRequestConfig} from 'next-intl/server';
45
import defaultMessages from '../../messages/en.json';
@@ -30,15 +31,17 @@ export const formats = {
3031
}
3132
} satisfies Formats;
3233

33-
export default getRequestConfig(async ({requestLocale}) => {
34-
// Typically corresponds to the `[locale]` segment
35-
const requested = await requestLocale;
36-
const locale = hasLocale(routing.locales, requested)
37-
? requested
38-
: routing.defaultLocale;
34+
export default getRequestConfig(async ({locale}) => {
35+
if (!locale) {
36+
const params = await rootParams();
37+
locale = hasLocale(routing.locales, params.locale)
38+
? params.locale
39+
: routing.defaultLocale;
40+
}
3941

40-
const now = headers().get('x-now');
41-
const timeZone = headers().get('x-time-zone') ?? 'Europe/Vienna';
42+
const headersList = await headers();
43+
const now = headersList.get('x-now');
44+
const timeZone = headersList.get('x-time-zone') ?? 'Europe/Vienna';
4245
const localeMessages = (await import(`../../messages/${locale}.json`))
4346
.default;
4447
const messages = {...defaultMessages, ...localeMessages};

0 commit comments

Comments
 (0)