Skip to content

Commit

Permalink
feat: support next@15 (#426)
Browse files Browse the repository at this point in the history
Co-authored-by: Tom Lienard <tom.lienrd@gmail.com>
  • Loading branch information
blechatellier and QuiiBz authored Oct 28, 2024
1 parent a049386 commit c332633
Show file tree
Hide file tree
Showing 14 changed files with 415 additions and 148 deletions.
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dependencies": {
"@vercel/analytics": "^1.1.1",
"@vercel/speed-insights": "^1.0.2",
"next": "^14.0.4",
"next": "^15.0.0",
"nextra": "^2.13.2",
"nextra-theme-docs": "^2.13.2",
"react": "^18.2.0",
Expand Down
6 changes: 5 additions & 1 deletion docs/pages/docs/app-setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ Move all your routes inside an `app/[locale]/` folder. For Client Components, wr
import { ReactElement } from 'react'
import { I18nProviderClient } from '../../locales/client'

export default function SubLayout({ params: { locale }, children }: { params: { locale: string }, children: ReactElement }) {
// If you are using Next.js < 15, you don't need to await `params`:
// export default function SubLayout({ params: { locale }, children }: { params: { locale: string }, children: ReactElement }) {
export default function SubLayout({ params, children }: { params: Promise<{ locale: string }>, children: ReactElement }) {
const { locale } = await params

return (
<I18nProviderClient locale={locale}>
{children}
Expand Down
5 changes: 4 additions & 1 deletion docs/pages/docs/app-static-rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ Inside all pages that you want to be statically rendered, call this `setStaticPa
// app/[locale]/page.tsx and any other page
import { setStaticParamsLocale } from 'next-international/server'

export default function Page({ params: { locale } }: { params: { locale: string } }) {
// If you are using Next.js < 15, you don't need to await `params`:
// export default function Page({ params: { locale } }: { params: { locale: string } }) {
export default function Page({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params
setStaticParamsLocale(locale)

return (
Expand Down
11 changes: 9 additions & 2 deletions docs/pages/docs/rtl-support.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ If you want to support the `dir` attribute in your `<html>` tag, you'll need to

```tsx {3,6}
// app/[locale]/layout.tsx
export default function Layout({ children, params: { locale } }: { children: ReactElement, params: { locale: string } }) {

// If you are using Next.js < 15, you don't need to await `params`:
// export default function Layout({ children, params: { locale } }: { children: ReactElement, params: { locale: string } }) {
export default function Layout({ children, params }: { children: ReactElement, params: Promise<{ locale: string }> }) {
const { locale } = await params
const dir = new Intl.Locale(locale).getTextInfo().direction

return (
Expand Down Expand Up @@ -56,7 +60,10 @@ Then, use it instead of the native `Intl.Locale.prototype.getTextInfo` API:
// app/[locale]/layout.tsx
import Locale from 'intl-locale-textinfo-polyfill'
export default function Layout({ children, params: { locale } }: { children: ReactElement, params: { locale: string } }) {
// If you are using Next.js < 15, you don't need to await `params`:
// export default function Layout({ children, params: { locale } }: { children: ReactElement, params: { locale: string } }) {
export default function Layout({ children, params }: { children: ReactElement, params: Promise<{ locale: string }> }) {
const { locale } = await params
const { direction: dir } = new Locale(locale).textInfo
return (
Expand Down
10 changes: 9 additions & 1 deletion examples/next-app/app/[locale]/client/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import type { ReactNode } from 'react';
import { Provider } from '../provider';

export default function Layout({ params: { locale }, children }: { params: { locale: string }; children: ReactNode }) {
export default async function Layout({
params,
children,
}: {
params: Promise<{ locale: string }>;
children: ReactNode;
}) {
const { locale } = await params;

return <Provider locale={locale}>{children}</Provider>;
}
4 changes: 3 additions & 1 deletion examples/next-app/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { Provider } from './provider';
// }

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default async function Home({ params: { locale } }: { params: { locale: string } }) {
export default async function Home({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params;

// Uncomment to test Static Generation
// setStaticParamsLocale(locale);

Expand Down
3 changes: 2 additions & 1 deletion examples/next-app/app/[locale]/subpage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { getI18n } from '../../../locales/server';
// }

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default async function Subpage({ params: { locale } }: { params: { locale: string } }) {
export default async function Subpage({ params }: { params: Promise<{ locale: string }> }) {
// Uncomment to test Static Generation
// const { locale } = await params;
// setStaticParamsLocale(locale);

const t = await getI18n();
Expand Down
2 changes: 1 addition & 1 deletion examples/next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"next": "^14.0.4",
"next": "^15.0.0",
"next-international": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/next-pages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"next": "^14.0.4",
"next": "^15.0.0",
"next-international": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/next-international/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-international",
"version": "1.2.4",
"version": "1.3.0",
"description": "Type-safe internationalization (i18n) for Next.js",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -50,7 +50,7 @@
},
"devDependencies": {
"@types/react": "^18.2.45",
"next": "^14.0.4",
"next": "^15.0.0",
"react": "^18.2.0",
"tsup": "^8.0.1"
},
Expand Down
29 changes: 16 additions & 13 deletions packages/next-international/src/app/server/create-get-i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,30 @@ export function createGetI18n<Locales extends ImportedLocales, Locale extends Ba
locales: Locales,
config: I18nServerConfig,
) {
const localeCache = new Map<string, ReturnType<typeof createT<Locale, undefined>>>();
const localeCache = new Map<string, Promise<ReturnType<typeof createT<Locale, undefined>>>>();

return async function getI18n() {
const locale = getLocaleCache();
const locale = await getLocaleCache();
const cached = localeCache.get(locale);

if (cached) {
return cached;
return await cached;
}

const localeFn = createT(
{
localeContent: flattenLocale((await locales[locale]()).default),
fallbackLocale: config.fallbackLocale ? flattenLocale(config.fallbackLocale) : undefined,
locale,
} as LocaleContext<Locale>,
undefined,
);
const localeFnPromise = (async () => {
const localeModule = await locales[locale]();
return createT(
{
localeContent: flattenLocale(localeModule.default),
fallbackLocale: config.fallbackLocale ? flattenLocale(config.fallbackLocale) : undefined,
locale,
} as LocaleContext<Locale>,
undefined,
);
})();

localeCache.set(locale, localeFn);
localeCache.set(locale, localeFnPromise);

return localeFn;
return await localeFnPromise;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,33 @@ export function createGetScopedI18n<Locales extends ImportedLocales, Locale exte
locales: Locales,
config: I18nServerConfig,
) {
const localeCache = new Map<string, ReturnType<typeof createT<Locale, undefined>>>();
const localeCache = new Map<string, Promise<ReturnType<typeof createT<Locale, undefined>>>>();

return async function getScopedI18n<Scope extends Scopes<Locale>>(
scope: Scope,
): Promise<ReturnType<typeof createT<Locale, Scope>>> {
const locale = getLocaleCache();
const locale = await getLocaleCache();
const cacheKey = `${locale}-${scope}`;
const cached = localeCache.get(cacheKey);

if (cached) {
return cached;
return (await cached) as ReturnType<typeof createT<Locale, Scope>>;
}

const localeFn = createT(
{
localeContent: flattenLocale((await locales[locale]()).default),
fallbackLocale: config.fallbackLocale ? flattenLocale(config.fallbackLocale) : undefined,
locale,
} as LocaleContext<Locale>,
scope,
);
const localeFnPromise = (async () => {
const localeModule = await locales[locale]();
return createT(
{
localeContent: flattenLocale(localeModule.default),
fallbackLocale: config.fallbackLocale ? flattenLocale(config.fallbackLocale) : undefined,
locale,
} as LocaleContext<Locale>,
scope,
);
})();

localeCache.set(cacheKey, localeFn);
localeCache.set(cacheKey, localeFnPromise);

return localeFn;
return await localeFnPromise;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ export const setStaticParamsLocale = (value: string) => {
getLocale().current = value;
};

export const getLocaleCache = cache(() => {
export const getLocaleCache = cache(async () => {
let locale: string | undefined | null;

locale = getStaticParamsLocale();

if (!locale) {
try {
locale = headers().get(LOCALE_HEADER);
locale = (await headers()).get(LOCALE_HEADER);

if (!locale) {
locale = cookies().get(LOCALE_COOKIE)?.value;
locale = (await cookies()).get(LOCALE_COOKIE)?.value;
}
} catch (e) {
throw new Error(
Expand Down
Loading

0 comments on commit c332633

Please sign in to comment.