# General Translation Knowledge Base: react-intl alternatives: General Translation vs. react-intl
URL: https://generaltranslation.com/en-US/kb/general-translation-vs-react-intl.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: General Translation lets React teams keep ICU message syntax while adding translation generation, shared terminology, and Dashboard review. react-intl supplies formatting and FormatJS catalog tooling; General Translation produces the translations too.
Category: Internationalization
Last updated: 2026-10-16
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-16

react-intl is the [React library from FormatJS](https://formatjs.github.io/docs/react-intl). You write each message inline as a `defaultMessage` in ICU MessageFormat, add a `description` for translators, collect every message into a JSON catalog with `formatjs extract`, and render translated catalogs through `IntlProvider`. It doesn't translate anything: the extracted catalog goes to you, your translators, or a translation management system (TMS), and translated files come back to be compiled. General Translation's libraries render ICU messages too, and General Translation also generates the translations.

## Video

The video is narrated in English, with English captions.

[react-intl alternatives: General Translation vs. react-intl](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-general-translation-vs-react-intl.mp4) (47 sec)

General Translation lets React teams keep ICU message syntax while adding translation generation, shared terminology, and Dashboard review; react-intl supplies formatting and catalog tooling. Move each message into useGT with its description as $context, run `npx gt translate` to extract and translate every catalog in one command, and let reviewers edit the results in the Dashboard with your Glossary and Custom Prompts.

## What react-intl does well

- **ICU MessageFormat throughout.** [Plurals with `#` and exact matches such as `=0`, `select`, and `selectordinal`](https://formatjs.github.io/docs/core-concepts/icu-syntax), built on the browser's `Intl` APIs.
- **Inline source text.** FormatJS [recommends writing `defaultMessage` and `description` inline](https://formatjs.github.io/docs/getting-started/message-declaration) and letting `babel-plugin-formatjs` or `@swc/plugin-formatjs` generate message IDs, so nobody invents keys.
- **Tooling for a TMS workflow.** [`formatjs extract`](https://formatjs.github.io/docs/tooling/cli) writes the catalog, built-in formatters produce files for Crowdin, Lokalise, Smartling, and Transifex, `formatjs compile` pre-parses messages, and `formatjs verify` checks catalogs for missing or extra keys.
- **TypeScript.** [Version 12 can type each message's ICU arguments](https://formatjs.github.io/docs/react-intl/upgrade-guide-12.x).
- **Active maintenance.** [Version 12 shipped in September 2026](https://github.com/formatjs/formatjs/blob/main/packages/react-intl/CHANGELOG.md), under the BSD-3-Clause license.

## What react-intl leaves to you

Here's a small inbox with react-intl. The English stays in the component as `defaultMessage`:

```jsx title="Inbox.jsx"
import { FormattedMessage } from 'react-intl';

export function Inbox({ count }) {
  return (
    <section>
      <h1>
        <FormattedMessage defaultMessage="Inbox" description="Heading of the inbox page" />
      </h1>
      <p>
        <FormattedMessage
          defaultMessage="You have {count, plural, one {# unread message} other {# unread messages}}."
          description="Number of unread messages in the inbox"
          values={{ count }}
        />
      </p>
    </section>
  );
}
```

`formatjs extract` turns those messages into a catalog keyed by generated IDs:

```json title="lang/en.json"
{
  "U5vJOY": {
    "defaultMessage": "You have {count, plural, one {# unread message} other {# unread messages}}.",
    "description": "Number of unread messages in the inbox"
  },
  "gBGgGs": {
    "defaultMessage": "Inbox",
    "description": "Heading of the inbox page"
  }
}
```

Each target language needs translated messages with their ICU syntax intact. `IntlProvider` accepts message strings or precompiled messages; `formatjs compile` prepares the latter. The extracted descriptors carry each message and its description. For the generated IDs in this example, configure the Babel or SWC plugin in your build. In the [Next.js App Router](https://formatjs.github.io/docs/guides/nextjs-app-router), react-intl's components run in client components while server code formats messages through `createIntl` from `react-intl/server`.

## Keep ICU messages and generate the translations

General Translation's libraries do the same job as react-intl: they render ICU messages, apply each locale's plural rules, and format numbers, currencies, and dates. Your ICU strings move almost unchanged, because [`useGT`](/docs/react/reference/hooks/use-gt) takes the same syntax:

```tsx title="Inbox.tsx"
import { useGT } from 'gt-react';

export function Inbox({ count }: { count: number }) {
  const gt = useGT();
  return (
    <section>
      <h1>{gt('Inbox', { $context: 'Heading of the inbox page' })}</h1>
      <p>
        {gt('You have {count, plural, one {# unread message} other {# unread messages}}.', {
          count,
          $context: 'Number of unread messages in the inbox',
        })}
      </p>
    </section>
  );
}
```

[`npx gt translate`](/docs/cli/reference/commands/translate) extracts these strings, generates translations using their context notes, and writes the target catalogs in one command. The example keeps both FormatJS descriptions as `$context`. Shared [Glossary terms and Custom Prompts](/docs/platform/dashboard/guides/defining-context-for-translations) guide terminology and tone, and reviewers edit results in the [Dashboard](/docs/platform/dashboard/guides/reviewing-translations).

The `#` is formatted for each locale, so a count of 12345 reads "12,345" in English and "12.345" in Spanish. For JSX with markup, [`<T>`](/docs/react/reference/components/t) translates the whole marked block, elements included. In `gt-next`, it works directly in Server Components.

Ramp's dashboard, landing page, and iOS app ship in 11+ locales with General Translation. (See [production deployments](https://generaltranslation.com/enterprise).)

## react-intl vs. General Translation at a glance

| Feature | react-intl | General Translation |
| --- | --- | --- |
| How you write copy | Inline `defaultMessage` in ICU, extracted to a JSON catalog | Inline JSX in [`<T>`](/docs/react/reference/components/t), or ICU strings in [`useGT`](/docs/react/reference/hooks/use-gt) |
| Translates your content | No | Yes, with [`npx gt translate`](/docs/cli/reference/commands/translate) |
| Catalog workflow | Extract messages, translate through your chosen workflow, optionally precompile; plugin generates IDs | [`npx gt translate`](/docs/cli/reference/commands/translate) extracts and translates before your build |
| Translation context | The message and its description | ICU strings with `$context`; marked JSX structure with inline components; shared Glossary and Custom Prompts |
| Next.js App Router | Components in client components; `createIntl` on the server | [`<T>`](/docs/react/reference/components/t) in Server and Client Components |
| License | [BSD-3-Clause](https://github.com/formatjs/formatjs/blob/main/packages/react-intl/LICENSE.md) | MIT-licensed JavaScript libraries and CLI |

Keep react-intl when your ICU catalogs and TMS formatters already work, when you rely on its typed message arguments or `formatjs verify`, or when you use FormatJS outside React. Choose General Translation to keep ICU authoring while making translation generation and review part of your development workflow.

## Moving from react-intl

Move one component or route at a time. Replace each `<FormattedMessage>` with a [`useGT`](/docs/react/reference/hooks/use-gt) call that keeps its ICU string and passes its description as `$context`, as shown above. For rich JSX, use [`<T context="…">`](/docs/react/reference/components/t#context). Keep loading existing react-intl catalogs for components you have not moved. Once the last component has moved, remove the FormatJS plugin and the extract and compile scripts. (See [Migrating i18n libraries](/docs/react/guides/migrating-i18n-libraries).)

## Other react-intl alternatives

Teams moving off react-intl also compare these libraries:

- **i18next:** renders keyed catalogs with plural selection, and with react-i18next and next-i18next is a common choice for React and Next.js apps. (See [General Translation vs. i18next](/kb/general-translation-vs-i18next).)
- **Lingui:** keeps copy inline and compiles messages into catalogs with a small runtime. (See [General Translation vs. Lingui](/kb/general-translation-vs-lingui).)
- **next-intl:** renders catalog messages in Next.js App Router apps, including Server Components. (See [next-intl vs. gt-next](/kb/next-intl-vs-gt-next).)
- **Paraglide JS:** compiles catalogs into typed, tree-shakable message functions. (See [General Translation vs. Paraglide JS](/kb/general-translation-vs-paraglide).)
- **Intlayer:** keeps each component's content in a typed declaration file with every language side by side. (See [General Translation vs. Intlayer](/kb/general-translation-vs-intlayer).)

## Key takeaways

- react-intl formats ICU messages and supplies catalog tooling; translation generation comes from a separate workflow.
- General Translation extracts and translates in one CLI command, preserving description context and giving reviewers a Dashboard editor.
- Your ICU strings move almost unchanged into [`useGT`](/docs/react/reference/hooks/use-gt), one component at a time.

## Related questions

- [General Translation vs. i18next, react-intl, and next-intl: which i18n library should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-i18n-libraries.mdx): Open-source libraries such as i18next, react-intl, and next-intl don't translate anything. They display translations you supply in a catalog file for each language, written by you, your translators, or a separate service. General Translation's libraries are open source too and do the same job, and General Translation also does the translating, with your code as context.
- [i18next alternatives: General Translation vs. i18next](https://generaltranslation.com/en-US/kb/general-translation-vs-i18next.mdx): Choose General Translation to keep copy inline in React components and generate translations with its JSX structure and product context. You can also keep i18next and use General Translation to translate existing catalogs. i18next supplies message rendering and plural selection; translation generation comes from a separate service.
- [General Translation vs. Lingui: which should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-lingui.mdx): Choose General Translation to keep copy inline like Lingui and generate the translations with your JSX structure as context. Lingui extracts inline messages into catalogs for your translators or a connected service to translate. General Translation's CLI updates translations as your code changes, and your team reviews them in the Dashboard.
- [General Translation vs. vue-i18n: which should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-vue-i18n.mdx): General Translation lets Vue teams write source copy directly in templates and generate translations with the CLI. Its gt-vue plugin renders that content with locale-aware plural and number formatting. Choose it to remove keyed source-file maintenance; vue-i18n remains a fit for teams using Nuxt's i18n module and an established catalog workflow.
- [How do I handle plurals in React?](https://generaltranslation.com/en-US/kb/how-to-handle-plurals-in-react.mdx): Handle plurals in React by giving each language one sentence per plural form and picking it with that language's plural rules, since English has 2 forms, Russian has 4, and Arabic has 6. General Translation's `<Plural>` component in gt-react and gt-next takes your source forms, and General Translation generates the forms each target language needs.

## Previous and next questions

- Previous question: [Phrase alternatives: General Translation vs. Phrase](https://generaltranslation.com/en-US/kb/general-translation-vs-phrase.mdx)
- Next question: [Should you build your own i18n or use General Translation?](https://generaltranslation.com/en-US/kb/general-translation-vs-in-house-i18n.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/en-US/kb/sitemap.md) for every article.
