diff --git a/packages/next-intl/.size-limit.ts b/packages/next-intl/.size-limit.ts index ed9dac2c8..1ef0f0e13 100644 --- a/packages/next-intl/.size-limit.ts +++ b/packages/next-intl/.size-limit.ts @@ -33,7 +33,7 @@ const config: SizeLimitConfig = [ name: "import {createSharedPathnamesNavigation} from 'next-intl/navigation' (react-server)", path: 'dist/production/navigation.react-server.js', import: '{createSharedPathnamesNavigation}', - limit: '16.795 KB' + limit: '16.825 KB' }, { name: "import {createLocalizedPathnamesNavigation} from 'next-intl/navigation' (react-server)", @@ -45,7 +45,7 @@ const config: SizeLimitConfig = [ name: "import {createNavigation} from 'next-intl/navigation' (react-server)", path: 'dist/production/navigation.react-server.js', import: '{createNavigation}', - limit: '16.8 KB' + limit: '16.815 KB' }, { name: "import * from 'next-intl/server' (react-client)", @@ -71,7 +71,7 @@ const config: SizeLimitConfig = [ name: "import * from 'next-intl' (react-client, ESM)", path: 'dist/esm/index.react-client.js', import: '*', - limit: '14.245 kB' + limit: '14.345 kB' }, { name: "import {NextIntlProvider} from 'next-intl' (react-client, ESM)", diff --git a/packages/next-intl/src/react-client/useLocale.tsx b/packages/next-intl/src/react-client/useLocale.tsx index 1b4f4f98f..2c21738a7 100644 --- a/packages/next-intl/src/react-client/useLocale.tsx +++ b/packages/next-intl/src/react-client/useLocale.tsx @@ -3,6 +3,8 @@ import {useParams} from 'next/navigation'; import {useLocale as useBaseLocale} from 'use-intl/_useLocale'; import {LOCALE_SEGMENT_NAME} from '../shared/constants'; +let hasWarnedForParams = false; + export default function useLocale(): string { // The types aren't entirely correct here. Outside of Next.js // `useParams` can be called, but the return type is `null`. @@ -16,6 +18,12 @@ export default function useLocale(): string { locale = useBaseLocale(); } catch (error) { if (typeof params?.[LOCALE_SEGMENT_NAME] === 'string') { + if (process.env.NODE_ENV !== 'production' && !hasWarnedForParams) { + console.warn( + 'Deprecation warning: `useLocale` has returned a default from `useParams().locale` since no `NextIntlClientProvider` ancestor was found for the calling component. This behavior will be removed in the next major version. Please ensure all Client Components that use `next-intl` are wrapped in a `NextIntlClientProvider`.' + ); + hasWarnedForParams = true; + } locale = params[LOCALE_SEGMENT_NAME]; } else { throw error; diff --git a/packages/next-intl/src/server/react-server/getConfig.tsx b/packages/next-intl/src/server/react-server/getConfig.tsx index a5fbbe326..08d5e48ae 100644 --- a/packages/next-intl/src/server/react-server/getConfig.tsx +++ b/packages/next-intl/src/server/react-server/getConfig.tsx @@ -11,6 +11,8 @@ import {getRequestLocale as getRequestLocaleLegacy} from './RequestLocaleLegacy' import createRequestConfig from './createRequestConfig'; import {GetRequestConfigParams} from './getRequestConfig'; +let hasWarnedForMissingReturnedLocale = false; + // Make sure `now` is consistent across the request in case none was configured function getDefaultNowImpl() { return new Date(); @@ -64,15 +66,28 @@ See also: https://next-intl-docs.vercel.app/docs/usage/configuration#i18n-reques result = await result; } - const locale = result.locale || (await params.requestLocale); + let locale = result.locale; if (!locale) { - if (process.env.NODE_ENV !== 'production') { + if ( + !hasWarnedForMissingReturnedLocale && + process.env.NODE_ENV !== 'production' + ) { console.error( - `\nUnable to find \`next-intl\` locale because the middleware didn't run on this request and no \`locale\` was returned in \`getRequestConfig\`. See https://next-intl-docs.vercel.app/docs/routing/middleware#unable-to-find-locale. The \`notFound()\` function will be called as a result.\n` + `\nA \`locale\` is expected to be returned from \`getRequestConfig\`, but none was returned. This will be an error in the next major version of next-intl.\n\nSee: https://next-intl-docs.vercel.app/blog/next-intl-3-22#await-request-locale\n` ); + hasWarnedForMissingReturnedLocale = true; + } + + locale = await params.requestLocale; + if (!locale) { + if (process.env.NODE_ENV !== 'production') { + console.error( + `\nUnable to find \`next-intl\` locale because the middleware didn't run on this request and no \`locale\` was returned in \`getRequestConfig\`. See https://next-intl-docs.vercel.app/docs/routing/middleware#unable-to-find-locale. The \`notFound()\` function will be called as a result.\n` + ); + } + notFound(); } - notFound(); } return { diff --git a/packages/next-intl/src/server/react-server/getRequestConfig.tsx b/packages/next-intl/src/server/react-server/getRequestConfig.tsx index 127656ff5..1229470f9 100644 --- a/packages/next-intl/src/server/react-server/getRequestConfig.tsx +++ b/packages/next-intl/src/server/react-server/getRequestConfig.tsx @@ -2,14 +2,7 @@ import type {IntlConfig} from 'use-intl/core'; export type RequestConfig = Omit & { /** - * Instead of reading a `requestLocale` from the argument that's passed to the - * function within `getRequestConfig`, you can include a locale as part of the - * returned request configuration. - * - * This can be helpful for the following use cases: - * - Apps that only support a single language - * - Apps where the locale should be read from user settings instead of the pathname - * - Providing a fallback locale in case the locale was not matched by the middleware + * @see https://next-intl-docs.vercel.app/docs/usage/configuration#i18n-request **/ locale?: IntlConfig['locale']; };