Skip to content

feat(i18n): adopt next/root-params - #9105

Open
amannn wants to merge 1 commit into
nodejs:mainfrom
amannn:feat/next-root-params
Open

feat(i18n): adopt next/root-params#9105
amannn wants to merge 1 commit into
nodejs:mainfrom
amannn:feat/next-root-params

Conversation

@amannn

@amannn amannn commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Description

Next.js 16.3 ships with next/root-params, which is a significant improvement for users of next-intl.

See the introductory blog post: Using next/root-params in Next.js 16.3

I went ahead to see how this integrates with nodejs.org, and it seems to work well!

Validation

I checked various languages and also different 404 states.

Related Issues

None.

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run pnpm format to ensure the code follows the style guide.
  • I have run pnpm test to check if all tests are passing.
  • I have run pnpm build to check if the website builds without errors.
  • I've covered new added functionality with unit tests if necessary.

@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nodejs-org Ready Ready Preview Aug 14, 2026 1:35pm

Request Review


// Gets the current full pathname for a given path
const [locale, pathname] = basePage.getLocaleAndPath(path, routeLocale);
const [locale, pathname] = await basePage.getLocaleAndPath(path);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No need to pass the routeLocale anymore since we can read from next/root-params within getLocaleAndPath.

const RootLayout: FC<RootLayoutProps> = async ({ children, params }) => {
const { locale } = await params;
const RootLayout: FC<PropsWithChildren> = async ({ children }) => {
const locale = await getLocale();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Using await getLocale() returns the returned locale from i18n.tsx—including potential defaults.

Comment thread apps/site/i18n.tsx
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());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the key: requestLocale is no longer needed, but we can read from next/root-params.

I've kept the behavior to read an override from a call site though, as this can be handy for Server Actions and Route Handlers (where next/root-params is not yet supported).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

noice !

// Forces the current locale to be the Default Locale
setRequestLocale(defaultLocale.code);
export const getLocaleAndPath = async (path = []) => {
const locale = (await getRootLocale()) ?? defaultLocale.code;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've considered reading from await getLocale() here, but that would internally apply defaults. Might be safer to keep an additional call to next/root-params here so the validation below continues to work as-is.

}

// Configures the current Locale to be the given Locale of the Request
setRequestLocale(locale);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No longer needed.

@amannn
amannn force-pushed the feat/next-root-params branch from 32f79c9 to a3cfe02 Compare August 14, 2026 12:45
@amannn
amannn marked this pull request as ready for review August 14, 2026 12:52
@amannn
amannn requested a review from a team as a code owner August 14, 2026 12:52
@amannn amannn changed the title feat(i18n): adopt next/root-params feat(i18n): adopt next/root-params Aug 14, 2026
@amannn

amannn commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@ovflowd @AugustinMauroy I thought you might be interested in adopting next/root-params so I took the liberty to open a PR—hope this looks useful to you!

On a related note, I've been working on a new tool called eloqnt/cli that is a linter to spot i18n issues. I found quite a few issues to address in this repo and added another PR here: #9106

@AugustinMauroy

Copy link
Copy Markdown
Member
  1. that seem good I need to read next docs first
  2. could you rebase and remove Claude co-author since https://openjsf.cdn.prismic.io/openjsf/acqiJpGXnQHGZGtq_OpenJSAICodingAssistantsPolicy.pdf

@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.13%. Comparing base (27ec25e) to head (7bcaf09).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9105      +/-   ##
==========================================
+ Coverage   86.01%   86.13%   +0.12%     
==========================================
  Files          86       86              
  Lines        6099     6051      -48     
  Branches      358      357       -1     
==========================================
- Hits         5246     5212      -34     
+ Misses        849      835      -14     
  Partials        4        4              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Next.js 16.3 exposes the `[locale]` root segment to Server Components via
`next/root-params`, which next-intl reads directly as of 4.13. That removes the
`setRequestLocale` bookkeeping the app needed for static rendering, along with
the locale threading through every page's `params`.

- `i18n.tsx` resolves the locale from the root param, so `requestLocale` is no
  longer needed. An explicit locale passed by a call site still wins, which
  stays useful for Server Actions and Route Handlers, where `next/root-params`
  is not supported yet
- the root layout reads the locale via `getLocale()`, which returns the already
  validated value from `i18n.tsx`, and no longer receives `params`
- `generateMetadata` and `getLocaleAndPath` read `next/root-params` directly
  rather than `getLocale()`, because they need the raw segment: `getLocale()`
  returns the already defaulted value, which would change the metadata emitted
  for unknown and disabled locales and make the notFound/redirect validation in
  `getLocaleAndPath` unreachable
@github-actions

Copy link
Copy Markdown
Contributor

📦 Build Size Comparison

Summary

Metric Value
Old Total First Load JS 7.06 MB
New Total First Load JS 7.06 MB
Delta 0 B (0.00%)

@amannn

amannn commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@AugustinMauroy

could you rebase and remove Claude co-author since
https://openjsf.cdn.prismic.io/openjsf/acqiJpGXnQHGZGtq_OpenJSAICodingAssistantsPolicy.pdf

Done!

@AugustinMauroy AugustinMauroy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM that make thing cleaner

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants