diff --git a/apps/site/app/[locale]/[...path]/page.tsx b/apps/site/app/[locale]/[...path]/page.tsx index aecb38f3da63f..a00ca2242133e 100644 --- a/apps/site/app/[locale]/[...path]/page.tsx +++ b/apps/site/app/[locale]/[...path]/page.tsx @@ -61,10 +61,10 @@ export const generateStaticParams = async () => { // finally it returns (if the locale and route are valid) the React Component with the relevant context // and attached context providers for rendering the current page const getPage: FC = async props => { - const { path, locale: routeLocale } = await props.params; + const { path } = await props.params; // Gets the current full pathname for a given path - const [locale, pathname] = basePage.getLocaleAndPath(path, routeLocale); + const [locale, pathname] = await basePage.getLocaleAndPath(path); // Gets the Markdown content and context const [content, context] = await basePage.getMarkdownContext({ diff --git a/apps/site/app/[locale]/blog/[...path]/page.tsx b/apps/site/app/[locale]/blog/[...path]/page.tsx index 2a11e65becc46..6003b05197b73 100644 --- a/apps/site/app/[locale]/blog/[...path]/page.tsx +++ b/apps/site/app/[locale]/blog/[...path]/page.tsx @@ -41,10 +41,10 @@ export const generateStaticParams = async () => { // finally it returns (if the locale and route are valid) the React Component with the relevant context // and attached context providers for rendering the current page const getPage: FC = async props => { - const { path, locale: routeLocale } = await props.params; + const { path } = await props.params; // Gets the current full pathname for a given path - const [locale, pathname] = basePage.getLocaleAndPath(path, routeLocale); + const [locale, pathname] = await basePage.getLocaleAndPath(path); // Verifies if the current route is a dynamic route const isDynamicRoute = BLOG_DYNAMIC_ROUTES.some(r => r.includes(pathname)); diff --git a/apps/site/app/[locale]/download/archive/[version]/page.tsx b/apps/site/app/[locale]/download/archive/[version]/page.tsx index 1cc23837ccdf1..cf3a343578e2b 100644 --- a/apps/site/app/[locale]/download/archive/[version]/page.tsx +++ b/apps/site/app/[locale]/download/archive/[version]/page.tsx @@ -43,10 +43,10 @@ export const generateStaticParams = async () => { // finally it returns (if the locale and route are valid) the React Component with the relevant context // and attached context providers for rendering the current page const getPage: FC = async props => { - const { version, locale: routeLocale } = await props.params; + const { version } = await props.params; // Gets the current full pathname for a given path - const [locale, pathname] = basePage.getLocaleAndPath(version, routeLocale); + const [locale, pathname] = await basePage.getLocaleAndPath(version); if (version === 'current') { const releaseData = await provideReleaseData(); diff --git a/apps/site/app/[locale]/layout.tsx b/apps/site/app/[locale]/layout.tsx index 7b905a0fd03a3..3e1c358b1103f 100644 --- a/apps/site/app/[locale]/layout.tsx +++ b/apps/site/app/[locale]/layout.tsx @@ -2,6 +2,7 @@ import PlatformAnalytics from '#platform/analytics'; import { availableLocales, defaultLocale } from '@node-core/website-i18n'; import classNames from 'classnames'; import { NextIntlClientProvider } from 'next-intl'; +import { getLocale } from 'next-intl/server'; import BaseLayout from '#site/layouts/Base'; import { IBM_PLEX_MONO, OPEN_SANS } from '#site/next.fonts'; @@ -13,12 +14,8 @@ import '#site/styles/index.css'; const fontClasses = classNames(IBM_PLEX_MONO.variable, OPEN_SANS.variable); -type RootLayoutProps = PropsWithChildren<{ - params: Promise<{ locale: string }>; -}>; - -const RootLayout: FC = async ({ children, params }) => { - const { locale } = await params; +const RootLayout: FC = async ({ children }) => { + const locale = await getLocale(); const { langDir, hrefLang } = availableLocales.find(l => l.code === locale) || defaultLocale; diff --git a/apps/site/app/[locale]/page.tsx b/apps/site/app/[locale]/page.tsx index 711e785a9a8fb..706f2fab1bdd7 100644 --- a/apps/site/app/[locale]/page.tsx +++ b/apps/site/app/[locale]/page.tsx @@ -50,10 +50,10 @@ export const generateStaticParams = async () => { // finally it returns (if the locale and route are valid) the React Component with the relevant context // and attached context providers for rendering the current page const getPage: FC = async props => { - const { path, locale: routeLocale } = await props.params; + const { path } = await props.params; // Gets the current full pathname for a given path - const [locale, pathname] = basePage.getLocaleAndPath(path, routeLocale); + const [locale, pathname] = await basePage.getLocaleAndPath(path); // Gets the Markdown content and context const [content, context] = await basePage.getMarkdownContext({ diff --git a/apps/site/i18n.tsx b/apps/site/i18n.tsx index 0991c705247e8..81cd89498c27f 100644 --- a/apps/site/i18n.tsx +++ b/apps/site/i18n.tsx @@ -1,5 +1,6 @@ import { availableLocaleCodes, defaultLocale } from '@node-core/website-i18n'; import defaultMessages from '@node-core/website-i18n/locales/en.json'; +import { locale as getRootLocale } from 'next/root-params'; import { getRequestConfig } from 'next-intl/server'; import { deepMerge } from './util/objects'; @@ -25,9 +26,10 @@ const loadLocaleDictionary = async (locale: string) => { }; // Provides `next-intl` configuration for RSC/SSR -export default getRequestConfig(async ({ requestLocale }) => { - // This typically corresponds to the `[locale]` segment - let locale = await requestLocale; +export default getRequestConfig(async params => { + // An explicit locale passed to an awaitable API like `getTranslations({ locale })` + // wins, otherwise we read the `[locale]` segment of the root layout + let locale = params.locale ?? (await getRootLocale()); // Ensure that the incoming locale is valid if (!locale || !availableLocaleCodes.includes(locale)) { diff --git a/apps/site/next.dynamic.page.mjs b/apps/site/next.dynamic.page.mjs index 08cd8f6118c3f..246477af72228 100644 --- a/apps/site/next.dynamic.page.mjs +++ b/apps/site/next.dynamic.page.mjs @@ -6,7 +6,7 @@ import { availableLocaleCodes, } from '@node-core/website-i18n'; import { notFound, redirect } from 'next/navigation'; -import { setRequestLocale } from 'next-intl/server'; +import { locale as getRootLocale } from 'next/root-params'; import { setClientContext } from '#site/client-context'; import WithLayout from '#site/components/withLayout'; @@ -28,11 +28,13 @@ export const generateViewport = () => ({ ...PAGE_VIEWPORT }); * * @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata * - * @param {{ params: Promise<{ path: Array; locale: string }>, prefix?: string }} props + * @param {{ params: Promise<{ path: Array }>, prefix?: string }} props * @returns {Promise} the metadata for the page */ export const generateMetadata = async ({ params, prefix }) => { - const { path = [], locale = defaultLocale.code } = await params; + const { path = [] } = await params; + + const locale = (await getRootLocale()) ?? defaultLocale.code; const pathname = dynamicRouter.getPathname(path); @@ -46,15 +48,16 @@ export const generateMetadata = async ({ params, prefix }) => { /** * This method is used for retrieving the current locale and pathname from the request * + * The locale comes from the `[locale]` root param, so pages don't have to read it + * from their own `params` and hand it over. + * * @param {string|Array} path - * @param {string} locale - * @returns {[string, string]} the locale and pathname for the request + * @returns {Promise<[string, string]>} the locale and pathname for the request */ -export const getLocaleAndPath = (path = [], locale = defaultLocale.code) => { - if (!availableLocaleCodes.includes(locale)) { - // Forces the current locale to be the Default Locale - setRequestLocale(defaultLocale.code); +export const getLocaleAndPath = async (path = []) => { + const locale = (await getRootLocale()) ?? defaultLocale.code; + if (!availableLocaleCodes.includes(locale)) { if (!allLocaleCodes.includes(locale)) { // when the locale is not listed in the locales, return NotFound return notFound(); @@ -66,9 +69,6 @@ export const getLocaleAndPath = (path = [], locale = defaultLocale.code) => { return redirect(`/${defaultLocale.code}/${pathname}`); } - // Configures the current Locale to be the given Locale of the Request - setRequestLocale(locale); - // Gets the current full pathname for a given path return [locale, dynamicRouter.getPathname(path)]; };