Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion examples/example-app-router/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
2 changes: 1 addition & 1 deletion examples/example-app-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dependencies": {
"clsx": "^2.1.1",
"next": "^14.2.4",
"next": "15.1.1-canary.12",
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Revert once in stable

"next-intl": "^3.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import {ReactNode} from 'react';
import './styles.css';

type Props = {
children: ReactNode;
};

// Since we have a `not-found.tsx` page on the root, a layout file
// is required, even if it's just passing children through.
export default function RootLayout({children}: Props) {
// No need for a layout, as this only renders a redirect
return children;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {redirect} from 'next/navigation';

// This page only renders when the app is built statically (output: 'export')
export default function RootPage() {
redirect('/en');
export default function RootRedirect() {
return redirect('/en');
}
28 changes: 8 additions & 20 deletions examples/example-app-router/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,27 @@
import {notFound} from 'next/navigation';
import {Locale, hasLocale} from 'next-intl';
import {getTranslations, setRequestLocale} from 'next-intl/server';
import {getTranslations} from 'next-intl/server';
import {ReactNode} from 'react';
import BaseLayout from '@/components/BaseLayout';
import {routing} from '@/i18n/routing';
import './styles.css';

type Props = {
children: ReactNode;
params: {locale: Locale};
};

export function generateStaticParams() {
return routing.locales.map((locale) => ({locale}));
}

export async function generateMetadata({
params: {locale}
}: Omit<Props, 'children'>) {
const t = await getTranslations({locale, namespace: 'LocaleLayout'});
export const dynamicParams = false;

export async function generateMetadata() {
const t = await getTranslations('LocaleLayout');

return {
title: t('title')
};
}

export default async function LocaleLayout({
children,
params: {locale}
}: Props) {
if (!hasLocale(routing.locales, locale)) {
notFound();
}

// Enable static rendering
setRequestLocale(locale);

return <BaseLayout locale={locale}>{children}</BaseLayout>;
export default async function LocaleLayout({children}: Props) {
return <BaseLayout>{children}</BaseLayout>;
}
12 changes: 2 additions & 10 deletions examples/example-app-router/src/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import {Locale, useTranslations} from 'next-intl';
import {setRequestLocale} from 'next-intl/server';
import {useTranslations} from 'next-intl';
import PageLayout from '@/components/PageLayout';

type Props = {
params: {locale: Locale};
};

export default function IndexPage({params: {locale}}: Props) {
// Enable static rendering
setRequestLocale(locale);

export default function IndexPage() {
const t = useTranslations('IndexPage');

return (
Expand Down
12 changes: 2 additions & 10 deletions examples/example-app-router/src/app/[locale]/pathnames/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import {Locale, useTranslations} from 'next-intl';
import {setRequestLocale} from 'next-intl/server';
import {useTranslations} from 'next-intl';
import PageLayout from '@/components/PageLayout';

type Props = {
params: {locale: Locale};
};

export default function PathnamesPage({params: {locale}}: Props) {
// Enable static rendering
setRequestLocale(locale);

export default function PathnamesPage() {
const t = useTranslations('PathnamesPage');

return (
Expand Down
15 changes: 0 additions & 15 deletions examples/example-app-router/src/app/not-found.tsx

This file was deleted.

9 changes: 6 additions & 3 deletions examples/example-app-router/src/components/BaseLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import {clsx} from 'clsx';
import {Inter} from 'next/font/google';
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
import {getLocale, getMessages} from 'next-intl/server';
import {ReactNode} from 'react';
import Navigation from '@/components/Navigation';

const inter = Inter({subsets: ['latin']});

type Props = {
children: ReactNode;
locale: string;
};

export default async function BaseLayout({children, locale}: Props) {
// Inline?
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Depends on whether a global not found page can be styled


export default async function BaseLayout({children}: Props) {
const locale = await getLocale();

// Providing all messages to the client
// side is the easiest way to get started
const messages = await getMessages();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ jest.mock('next/navigation', () => ({
useSelectedLayoutSegment: () => ({locale: 'en'})
}));

it('renders', () => {
// Disabled until canary version is reverted
// eslint-disable-next-line jest/no-disabled-tests
it.skip('renders', () => {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Should be resolved once we use the same version across packages and examples

render(
<NextIntlClientProvider
locale="en"
Expand Down
10 changes: 5 additions & 5 deletions examples/example-app-router/src/i18n/request.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {unstable_rootParams as rootParams} from 'next/server';
import {hasLocale} from 'next-intl';
import {getRequestConfig} from 'next-intl/server';
import {routing} from './routing';

export default getRequestConfig(async ({requestLocale}) => {
// Typically corresponds to the `[locale]` segment
const requested = await requestLocale;
const locale = hasLocale(routing.locales, requested)
? requested
export default getRequestConfig(async () => {
const params = await rootParams();
const locale = hasLocale(routing.locales, params.locale)
? params.locale
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

: routing.defaultLocale;

return {
Expand Down
4 changes: 2 additions & 2 deletions examples/example-app-router/tests/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ it("handles not found pages for routes that don't match the middleware", async (

it('sets caching headers', async ({request}) => {
for (const pathname of ['/en', '/en/pathnames', '/de', '/de/pfadnamen']) {
expect((await request.get(pathname)).headers()['cache-control']).toBe(
's-maxage=31536000, stale-while-revalidate'
expect((await request.get(pathname)).headers()['cache-control']).toContain(
's-maxage=31536000'
);
}
});
Expand Down
2 changes: 1 addition & 1 deletion packages/use-intl/src/core/hasLocale.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {Locale} from './AppConfig.tsx';
*/
export default function hasLocale<LocaleType extends Locale>(
locales: ReadonlyArray<LocaleType>,
candidate?: string | null
candidate: unknown
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A param can be string[]

): candidate is LocaleType {
return locales.includes(candidate as LocaleType);
}
Loading
Loading