npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mf2react

v0.1.12

Published

MessageFormat v2 postProcessor for i18next/react-i18next

Downloads

29

Readme

mf2react

This guide explains how to localize React applications with MessageFormat 2 (MF2), using the mf2react package.

The library builds ontop of i18next and react-i18next, popular internationalization frameworks for JavaScript and React.

The package contains a post-processor plugin for i18next that compiles MF2 messages and converts lightweight curly-tag markup into safe HTML tags, which react-i18next can render as JSX. For example the message {#bold}Hello{/bold}, {$name}! becomes <strong>Hello</strong>, {$name}! when rendered.

MF2 features such as pluralization, select, and conditional logic are fully supported. For example, the following MF2 message:

.match {$count: number}
one    {{You have {$count} message}}
*      {{You have {$count} messages}}

Can be used in a React component like this:

import { Trans } from "react-i18next";
export default function MessagesComponent({ count }: { count: number }) {
  return <Trans i18nKey="messages" values={{ count }} />;
}

Introduction

This guide assumes you have a basic understanding of React and i18next / react-i18next.

Installation and setup

In an existing React project, install the mf2react package, along with the i18next, and react-i18next dependencies:

npm install mf2react i18next react-i18next

You can also use a different package manager, such as yarn, pnpm, or deno to install the packages.

Defining your catalogs (translations)

Create JSON files for each locale you want to support. For example, create a locales/en/translation.json file for English translations:

{
  "welcome": "Welcome to our application!",
  "goodbye": "Goodbye!",
  "greeting": "Hello, {$name}!",
  "apples": ".input {$value :number}\n.match $value\none   {{{#bold}1{/bold} apple}}\n*     {{{#bold}{$value}{/bold} apples}}"
}

And a locales/no/translation.json file for Norwegian translations:

{
  "welcome": "Velkommen til vår applikasjon!",
  "goodbye": "Ha det!",
  "greeting": "Hei, {$name}!",
  "apples": ".input {$value :number}\n.match $value\none   {{{#bold}1{/bold} eple}}\n*     {{{#bold}{$value}{/bold} epler}}"
}

Setting up i18next

Create a i18n.ts file in your project to configure i18next.

// i18n.ts
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import { MF2PostProcessor, MF2ReactPreset } from "mf2react";

import en from "./locales/en/translation.json";
import no from "./locales/no/translation.json";

if (!i18n.isInitialized) {
  i18n
    .use(MF2PostProcessor) // Enable the post-processor
    .use(MF2ReactPreset) // Enable curly-tag -> JSX conversion
    .use(initReactI18next)
    .init({
      lng: "en",
      postProcess: ["mf2"], // Apply MF2 to all translations
      resources: {
        // Reference the translation files
        en: { translation: en },
        no: { translation: no },
      },
    });
}

export default i18n;

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, i18next-resources-to-backend. Additionally you may want to auto-detect the user's locale using i18next-browser-languagedetector.

Wrapping your application with I18nextProvider

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.

"use client";

import { I18nextProvider } from "react-i18next";
import { i18n } from "./i18n";

export default function AppLayout({ children }: { children: React.ReactNode }) {
  return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
}

Good to know: because I18nextProvider uses React context, it can only be used in a client component.

Choosing where to place the provider

Where you place the provider affects what becomes client-rendered. You may either wrap your whole application in the provider, or each component that uses translations. This is because I18nextProvider must be used in a client component. Choose the placement based on how much of your UI should be client-rendered.

Using translations in components

Now you can use the <Trans> component from react-i18next to render translations in your React components. For example:

import { Trans } from "react-i18next";
export default function WelcomeComponent() {
  return (
    <div>
      <h1>
        <Trans i18nKey="welcome" />
      </h1>
      <p>
        <Trans i18nKey="goodbye" />
      </p>
    </div>
  );
}

You can read more about the Trans component in the react-i18next documentation

Passing variables to translations

You can also pass variables to your translations using the values prop of the <Trans> component. For example, if you have a translation that includes a variable:

{
  "greeting": "Hello, {$name}!"
}

You can use it in your component like this:

import { Trans } from "react-i18next";
export default function GreetingComponent({ name }: { name: string }) {
  return <Trans i18nKey="greeting" values={{ name }} />;
}

This also works for MF2 messages with pluralization and formatting:

import { Trans } from "react-i18next";
export default function ApplesComponent({ count }: { count: number }) {
  return <Trans i18nKey="apples" values={{ value: count }} />;
}

Output when count is 1: 1 apple

Output when count is 5: 5 apples

Markup with curly-tags

You can use curly-tags in your translations to add formatting. For example, in your translation file:

{
  "bold": "This is {#bold}bold text{/bold}."
}

You can render it in your component like this:

import { Trans } from "react-i18next";
export default function BoldComponent() {
  return <Trans i18nKey="bold" />;
}

Output: This is bold text.

This works because the mf2react post-processor converts the curly-tags into safe HTML tags, which react-i18next can render as JSX. The following tags are supported:

{#bold}…{/bold}
{#strong}…{/strong}
{#i}…{/i}
{#em}…{/em}
{#u}…{/u}
{#s}…{/s}
{#small}…{/small}
{#code}…{/code}

Notes and limitations

  • i18next post-processors must return strings. The JSX conversion happens inside <Trans>.
  • Messages are compiled and cached per language for performance.
  • The curly-tag conversion is intentionally minimal and safe. It only recognizes tags defined in the alias list.
  • If you switch languages at runtime, the plugin automatically reuses or recompiles as needed.
  • Unsupported MF2 syntax will fall back gracefully to raw string + curly tag conversion.

Acknowledgements