From c482acd6d052fbf1b266bc49293a9db2cdc1406a Mon Sep 17 00:00:00 2001 From: Adriano Raiano Date: Wed, 4 Nov 2026 15:00:18 +0100 Subject: [PATCH 1/3] React guide: fix the MF2 example, install command and provider note --- docs/frameworks/react.md | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/docs/frameworks/react.md b/docs/frameworks/react.md index d42c887..bc01bd6 100644 --- a/docs/frameworks/react.md +++ b/docs/frameworks/react.md @@ -6,7 +6,7 @@ sidebar_title: React This guide explains how to localize React applications with MessageFormat 2 (MF2), using the `mf2react` package. -The library builds ontop of [i18next](https://www.i18next.com/) and +The library builds on top of [i18next](https://www.i18next.com/) and [react-i18next](https://react.i18next.com/), popular internationalization frameworks for JavaScript and React. @@ -21,7 +21,8 @@ MF2 features such as pluralization, select, and conditional logic are fully supported. For example, the following MF2 message: ```mf2 -.match {$count: number} +.input {$count :number} +.match $count one {{You have {$count} message}} * {{You have {$count} messages}} ``` @@ -43,10 +44,12 @@ export default function MessagesComponent({ count }: { count: number }) { ## Installation and setup In an existing React project, install the `mf2react` package, along with the -`i18next`, and `react-i18next` dependencies: +`i18next`, and `react-i18next` dependencies. `mf2react` 0.1.12 lists i18next 25 +and react-i18next 16 as peer dependencies, so npm refuses to install it next to +i18next 26 or react-i18next 17: ```bash -npm install mf2react i18next react-i18next +npm install mf2react i18next@25 react-i18next@16 ``` You can also use a different package manager, such as `yarn`, `pnpm`, or `deno` @@ -114,17 +117,20 @@ export default i18n; > Additionally you may want to auto-detect the user's locale using > [i18next-browser-languagedetector](https://github.com/i18next/i18next-browser-languagedetector). -### Wrapping your application with I18nextProvider +### Wrapping your application with I18nextProvider (optional) -To use translations in your React components, you need to wrap your application -with the `I18nextProvider` from `react-i18next`. This is typically done in your -main application file or layout component. +`initReactI18next` already makes the i18next instance available to +`useTranslation` and ``, so the provider is not required. Wrap your +application with the `I18nextProvider` from `react-i18next` if you want to pass +the instance through React context instead, for example when you use more than +one i18next instance. This is typically done in your main application file or +layout component. -```ts +```tsx "use client"; import { I18nextProvider } from "react-i18next"; -import { i18n } from "./i18n"; +import i18n from "./i18n"; export default function AppLayout({ children }: { children: React.ReactNode }) { return {children}; @@ -248,10 +254,13 @@ supported: recompiles as needed. - Unsupported MF2 syntax will fall back gracefully to raw string + curly tag conversion. +- Placeholders such as `{$name}` are wrapped in the invisible bidi isolation + characters U+2068 and U+2069, which `messageformat` adds by default. They show + up when you compare rendered strings, for example in tests. ## Acknowledgements -- [i18next](https://www.i18next.com/) - the internalization framework +- [i18next](https://www.i18next.com/) - the internationalization framework - [react-i18next](https://react.i18next.com/) - React bindings for i18next -- [@messageformat/core](https://github.com/messageformat/messageformat) - - MessageFormat2 engine used for compiling and evaluating MF2 syntax. +- [messageformat](https://github.com/messageformat/messageformat) - the MF2 + engine used for compiling and evaluating MF2 syntax. From c1e8fe4888c15c7b73aed40960f981b75f00abd1 Mon Sep 17 00:00:00 2001 From: Adriano Raiano Date: Wed, 4 Nov 2026 15:00:19 +0100 Subject: [PATCH 2/3] React guide: add a section on i18next-mf2 --- docs/frameworks/react.md | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/frameworks/react.md b/docs/frameworks/react.md index bc01bd6..50c9b55 100644 --- a/docs/frameworks/react.md +++ b/docs/frameworks/react.md @@ -258,6 +258,64 @@ supported: characters U+2068 and U+2069, which `messageformat` adds by default. They show up when you compare rendered strings, for example in tests. +## Using i18next-mf2 instead + +i18next also has its own MF2 plugin, +[i18next-mf2](https://github.com/i18next/i18next-mf2). It is an `i18nFormat` +plugin rather than a post-processor: `messageformat` formats the whole message, +and i18next's own interpolation, plural and context handling are not used. + +```bash +npm install i18next i18next-mf2 react-i18next +``` + +```ts +// i18n.ts +import i18n from "i18next"; +import MF2 from "i18next-mf2"; +import { initReactI18next } from "react-i18next"; + +i18n + .use(MF2) + .use(initReactI18next) + .init({ + lng: "en", + resources: { + en: { + translation: { + apples: + ".input {$value :number}\n.match $value\none {{<0>1 apple}}\n* {{<0>{$value} apples}}", + }, + }, + }, + }); + +export default i18n; +``` + +MF2 markup such as `{#bold}…{/bold}` is dropped when a message is formatted to a +string. For rich text, use numbered tags like `<0>…`, which MF2 treats as +plain text, and pass the elements to ``: + +```tsx +import { Trans } from "react-i18next"; +export default function ApplesComponent({ count }: { count: number }) { + return ( + ]} + /> + ); +} +``` + +> Output when `count` is 5: **5** apples + +The [Using ICU or MF2](https://www.i18next.com/how-to/using-icu-or-mf2) page in +the i18next docs lists which i18next features keep working with the plugin, and +covers type-checked message arguments and extraction with i18next-cli. + ## Acknowledgements - [i18next](https://www.i18next.com/) - the internationalization framework From c3d694321f4e20db20402d01c1ff3c22cb308dd7 Mon Sep 17 00:00:00 2001 From: Adriano Raiano Date: Wed, 4 Nov 2026 15:07:14 +0100 Subject: [PATCH 3/3] React guide: import i18n.ts in the entry file --- docs/frameworks/react.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/frameworks/react.md b/docs/frameworks/react.md index 50c9b55..c71e3a1 100644 --- a/docs/frameworks/react.md +++ b/docs/frameworks/react.md @@ -110,6 +110,10 @@ i18n export default i18n; ``` +Import this file once in your application's entry file, for example +`import "./i18n";` in `main.tsx`, so the configuration runs before your +components render. + > Instead of defining the selected locale (`lng`) and `resources` directly in > the `init` function, you may also choose to load them dynamically, e.g. via > [i18next-http-backend](https://github.com/i18next/i18next-http-backend),