Skip to content

Compare · React Intl

For React teams that need ICU rigor in server components and want to remove Context-specific i18n plumbing from their application boundary.

Keep the ICU rigor. Lose the provider.

React Intl set the standard for ICU MessageFormat in JavaScript and we have no argument with the format — we have an argument with the plumbing. Resolving messages through React Context was the right call in 2014 and it is the reason React Server Components are a workaround here rather than a supported path.

Licence
BSD-3-Clause
Runtime
React Context
Server components
Not supported natively
Checked benchmark
5× slower

React Intl figures: react-intl 10.1.14, researched July 2026. Projects move; re-check before you decide.

01 — Decide

Choose the model that leaves you with less recurring work.

For the audience above, we recommend Palamedes. The alternative is not a disclaimer: if the right column describes your constraint, choose React Intl and do not think twice about it.

Pick Palamedes when…

  • You are on the App Router or another RSC-first framework and want i18n without a bypass.
  • You want .po catalogs instead of a custom JSON format.
  • Message edits should not risk orphaning translations.
  • You want less per-string boilerplate without giving up a single thing about ICU.

Pick React Intl when…

  • You need Intl.* polyfills for runtimes without full ECMA-402 support. This one is not close.
  • Your app is client-components-only and the Context model causes you no friction.
  • You rely on an established React Intl integration for your TMS.

02 — Daily work

What changes after the choice is made.

These are workflow consequences, not a feature inventory: fewer conventions to maintain, one catalog boundary to review, and one runtime model to carry through the supported hosts. Each point maps back to an inspectable artifact.

No Context means server components just work

React Intl resolves messages through React Context, which RSC cannot cross — App Router setups need a bypass. Palamedes resolves through getI18n(), backed by request-local async context on the server. The same component code runs in an RSC, a client island, or an Express route, and none of those cases is the special one.

Inspect the executable ICU source-to-runtime proof

Editing a string does not orphan its translations

In React Intl's generated-ID workflow, the extraction tooling derives message IDs from a content hash of the default message. Fixing a typo then changes the ID and can orphan existing translations unless your tooling diffs for it. Palamedes uses the source string plus context as identity and resolves updates through semantic catalog merging, which is built for exactly this — because typos get fixed.

Inspect the executable ICU source-to-runtime proof

Macros instead of component boilerplate

Palamedes macros compile away: you write a tagged template or a <Trans> with real JSX children, and the transform produces the runtime call. Same ICU output, none of the wrapper, and the file you actually read stays readable. The scaffolding was never the rigor.

Inspect the executable ICU source-to-runtime proof

03 — React Intl

Where the competitor is the stronger fit.

The strengths and trade-offs below are sourced from the dated research for React Intl. They explain why the right decision can genuinely be React Intl, even when Palamedes is our recommendation for the audience above.

Competitor strength

What React Intl earned

  • The reference implementation for ICU MessageFormat in JavaScript — plurals, select, selectordinal, rich text and full number and date skeletons, done properly.
  • Standards-based to the core: ICU and ECMA-402 are cross-platform, which keeps your translation vocabulary portable well beyond JavaScript.
  • Its own Intl.* polyfill packages, which still matter for runtimes with incomplete ECMA-402 support — something Palamedes does not offer at all.

Trade-off

What that architecture costs you

  • No React Server Components, structurally. The Context-based runtime is incompatible with RSC, so App Router and every other RSC-first framework need a manual workaround.
  • Boilerplate is the API. A <FormattedMessage> around every string is explicit and verbose, and the default non-precompiled path carries the ICU parser at runtime unless you opt into /no-parser plus AST precompilation.
  • Newer React meta-frameworks are on you: TanStack Start, SolidStart, Waku and React Router have no first-class integration, so their server and routing boundaries require application-level wiring.

04 — Proof in code

Same ICU semantics, different amount of scaffolding.

React Intl

<FormattedMessage
id="checkout.buy"
defaultMessage="Buy {seats} seats"
values={{ seats }}
/>

Palamedes

<Trans>Buy {seats} seats</Trans>

One benchmark caveat worth stating plainly: the React Intl extraction workflow writes a single aggregated message file, while the other tools also merge and update per-locale catalogs. It is doing less work in that row, and it is still slower.

05 — Side by side

The comparison, without the adjectives.

Where a row cites a measurement, it comes from the checked benchmark report in the repository. Where nothing was measured, the row says so.

CriteriaReact IntlPalamedes
ICU MessageFormatNative — the reference implementationNative, with a checked source-to-runtime proof
Server componentsNot supported natively (Context-based)First-class via request-local scope
Message identityExplicit IDs; generated hash IDs optionalmessage + context
Catalog formatCustom JSON plus TMS formatter adapters.po (gettext), FCL opt-in
Authoring<FormattedMessage> components and hooksCompile-time macros, erased at build
Extract + update, realistic corpus424 ms vs 73 ms5.85× faster on realistic extraction-only¹
Intl polyfillsShipped as separate packagesNone — modern runtimes only

¹ Median of 7 runs on the realistic corpus (1,500 files, ~400k lines, 6,000 messages — half the files carry no i18n marker), one machine-local run, same semantic validation for every tool. The full report and the harness are in the repository, and the site build fails if these numbers drift from it.

06 — The trade-off

React Intl has the deeper ICU pedigree and a polyfill story we simply do not have; if your runtime targets need those polyfills, stop reading here. Palamedes also supports fewer formatter kinds at runtime than full ICU — the compiler reports the unsupported ones as errors rather than failing quietly at 3am, but it is a smaller surface and you should check it against your catalog before switching.

07 — Evaluate

Prove catalog compatibility before changing runtime code

Start with a representative ICU fixture and run the checked proof alongside your existing catalog. Palamedes does not provide a universal React Intl migration guide; unsupported formatter kinds are a real compatibility check, not a detail to defer until rollout.

08 — Questions

Questions teams ask before leaving React Intl.

The migration, framework, catalog, runtime and trade-off boundaries are stated here and included in the page's structured data.

01Can we evaluate Palamedes without replacing React Intl everywhere?

Start with a representative ICU fixture and run the checked proof alongside your existing catalog. Palamedes does not provide a universal React Intl migration guide; unsupported formatter kinds are a real compatibility check, not a detail to defer until rollout.

02Does Palamedes make sense if we use only one framework?

Yes, if the source-string, catalog and runtime model is the fit. Framework breadth is proof that the supported adapters share one model, not a requirement that one application use several frameworks. Check the supported host and its documented boundary before adopting.

03Who owns the catalogs?

Palamedes keeps source-string-first PO catalogs in the repository. Extraction, catalog updates, audits, merging and compilation are local workflow steps; it does not provide a hosted TMS or machine translation service.

04What runtime code reaches the application?

Transformed code reaches the active Palamedes instance through getI18n(). The exact adapter and compiled artifact depend on the supported host; inspect the framework documentation and proof rather than treating this comparison as a bundle-size claim.

05What do we give up by choosing Palamedes over React Intl?

React Intl has the deeper ICU pedigree and a polyfill story we simply do not have; if your runtime targets need those polyfills, stop reading here. Palamedes also supports fewer formatter kinds at runtime than full ICU — the compiler reports the unsupported ones as errors rather than failing quietly at 3am, but it is a smaller surface and you should check it against your catalog before switching.

Make the next step match the decision you still need to make.