Skip to content

Conversation

@amannn
Copy link
Owner

@amannn amannn commented Nov 5, 2025

Discussion

TODO

  • Docs
  • Blog post

Note

Adds experimental message extraction (extractor, loaders, plugin options) and new useExtracted/getExtracted APIs, with docs and an example app.

  • APIs (runtime):
    • Add experimental useExtracted (client/server) and getExtracted utilities; fallback handling and tests; types exported to support usage.
  • Extractor & Build Integration (experimental):
    • Implement message extraction pipeline (src/extractor/**): compiler, catalog (JSON/PO) formatters/persistence, source scanning, utilities, tests.
    • Add Turbopack/Webpack loaders (next-intl/extractor/extractionLoader, .../catalogLoader) and wire via plugin options (extract, messages, srcPath) in createNextIntlPlugin/getNextConfig.
    • Expose new package exports and rollup bundles; add @swc/core; adjust size limits.
  • Docs:
    • New "Next.js plugin" docs (docs/src/pages/docs/usage/plugin.mdx), refine configuration docs, nav meta updates, minor footer/links tweaks.
  • Examples:
    • Add examples/example-app-router-extracted showcasing extraction (PO catalogs, tests); remove legacy examples/example-app-router-single-locale/next.config.mjs; bump examples/example-use-intl to use-intl@^4.
  • Tooling:
    • Generalize side‑effect import stripping in tools/src/getBuildConfig.js.

Written by Cursor Bugbot for commit c8efecc. This will update automatically on new commits. Configure here.

# Conflicts:
#	packages/next-intl/.size-limit.ts
#	packages/next-intl/__mocks__/react.tsx
#	packages/next-intl/src/navigation/shared/createSharedNavigationFns.tsx
#	packages/next-intl/src/react-server/index.test.tsx
#	packages/next-intl/src/server/react-server/RequestLocale.tsx
#	packages/next-intl/src/server/react-server/getConfig.tsx
In Next.js 15.3, [Turbopack config has become
stable](https://nextjs.org/blog/next-15-3#turbopack-configuration-in-nextconfigts-stable).
With this fix, the new option is used in order to avoid a deprecation
warning.
# Conflicts:
#	packages/next-intl/src/plugin/getNextConfig.tsx
…on APIs (#1922)

With #959, the middleware
already handled decoding of non-ASCII characters.

This allows you to define localized
[`pathnames`](https://next-intl.dev/docs/routing#pathnames) like so:

```tsx
import {defineRouting} from 'next-intl/routing';
 
export const routing = defineRouting({
  locales: ['en', 'ja'],
  defaultLocale: 'en',
  pathnames: {
    '/about': {
      'de': '/über-uns'
  }
}
```

Since Next.js automatically encodes incoming pathnames, this supports
incoming requests both for decoded pathnames (e.g. `/de/über-uns`), as
well as encoded ones (e.g. `/de/%C3%BCber-uns`).

One piece has been missing though: Pathnames returned from [navigation
APIs](https://next-intl.dev/docs/routing/navigation) should be turned
into an encoded form.

Now, `next-intl` handles this as well:

```tsx
import {Link, getPathname} from '@/i18n/navigation';

// href="/de/%C3%BCber-uns"
<Link href="/about" locale="de" />

// pathname = "/de/%C3%BCber-uns"
const pathname = getPathname({href: '/about', locale: 'de'});
```

This change brings the navigation APIs in line with [Google's
recommendation to encode non-ASCII
pathnames](https://developers.google.com/search/docs/crawling-indexing/url-structure).
# Conflicts:
#	examples/example-app-router-playground/tests/main.spec.ts
<!-- CURSOR_SUMMARY -->
> [!NOTE]
> Introduces an experimental message extraction pipeline (JSON/PO) with
new `useExtracted`/`getExtracted` APIs, Turbopack/Webpack loaders, and
an example app showcasing it.
> 
> - **Experimental extraction**:
> - Add extractor core (`src/extractor/*`): compiler, catalog
manager/locales/persister, save scheduler, SWC-based message extractor,
formatters (JSON/PO), utilities, and public export
`next-intl/extractor`.
> - New loaders: `extractor/extractionLoader` and
`extractor/catalogLoader` (+ `.d.ts` shims).
> - **Plugin/Config**:
> - Extend plugin to wire loaders and rules for Turbopack/Webpack; add
`experimental.srcPath`, `messages` and `extract` options; refactor next
flags (`hasStableTurboConfig`, `isNextJs16OrHigher`).
>   - Adjust rollup build and type exposure; size-limit tweaks.
> - **APIs**:
> - React: export `useExtracted` (client/server) and server
`getExtracted`; client re-exports from `use-intl/react`.
> - **Examples/Tests**:
> - New example `examples/example-app-router-extracted` demonstrating
extraction; extensive extractor tests.
>   - Bump `examples/example-use-intl` to `use-intl@^4`.
> - **Misc**:
> - Package metadata/exports/files updates; add `@swc/core` and
`@types/webpack` dev dep; remove obsolete example config.
>   - Tools: simplify side-effect import stripping in build script.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
db387c4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@vercel
Copy link

vercel bot commented Nov 5, 2025

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

Project Deployment Preview Comments Updated (UTC)
next-intl-docs Ready Ready Preview Comment Nov 5, 2025 10:11pm
next-intl-example-app-router Ready Ready Preview Comment Nov 5, 2025 10:11pm
next-intl-example-app-router-without-i18n-routing Ready Ready Preview Comment Nov 5, 2025 10:11pm

@amannn amannn marked this pull request as ready for review November 5, 2025 14:30
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on December 27

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.


// This message continues to exist in this file
const index = idsToRemove.indexOf(message.id);
if (index !== -1) idsToRemove.splice(index, 1);
Copy link

Choose a reason for hiding this comment

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

Bug

When a message is removed from a file, the code only deletes it from messagesById if it was in idsToRemove. However, this logic is flawed because a message might be used in multiple files. When removing a message from one file, the code should only delete it from messagesById if it's not used in any other file. Currently, if a message exists in File A and File B, and you remove it from File A, it will be incorrectly deleted from messagesById even though it's still used in File B. This will cause the message to disappear from the catalog entirely, breaking File B's translations.

The fix should check if the message ID exists in any other file before deleting from messagesById:

for (const id of idsToRemove) {
  // Only delete if not used in any other file
  let usedElsewhere = false;
  for (const [filePath, messages] of this.messagesByFile) {
    if (filePath !== absoluteFilePath && messages.has(id)) {
      usedElsewhere = true;
      break;
    }
  }
  if (!usedElsewhere) {
    this.messagesById.delete(id);
  }
}

Fix in Cursor Fix in Web

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