# General Translation Knowledge Base: General Translation vs. Lingui: which should you use?
URL: https://generaltranslation.com/en-US/kb/general-translation-vs-lingui.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 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.
Category: Internationalization
Last updated: 2026-10-16
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-16

Lingui's approach is close to General Translation's at the authoring end. You write `<Trans>Inbox</Trans>` in a component, Lingui's macros compile it to an ICU message with a generated ID, `lingui extract` writes PO catalogs, and `lingui compile` turns translated catalogs into small JavaScript modules. The step Lingui leaves out is the translation itself: its docs point to [editing catalogs by hand or syncing them with Crowdin or Translation.io](https://lingui.dev/tools/introduction). General Translation keeps copy inline too, and General Translation generates the translations.

## What Lingui does well

- **Inline source with macros.** The `<Trans>` macro and [Lingui's macros](https://lingui.dev/ref/macro) for plurals and plain strings keep English in the component and compile to ICU MessageFormat, so nobody writes keys.
- **A small runtime.** Messages are compiled ahead of time, and Lingui puts its runtime at [about 2 kB](https://lingui.dev/introduction) by its own measurement.
- **Gettext-friendly catalogs.** [PO is the default format](https://lingui.dev/ref/catalog-formats), `lingui extract` merges new messages into every locale and marks removed ones obsolete, and `context` and `comment` fields reach translators.
- **Server Components.** [Since version 4.10](https://lingui.dev/tutorials/react-rsc), `<Trans>` and `useLingui` work on the server once each page or layout calls `setI18n`.
- **Active development.** [Version 6 shipped in April 2026](https://lingui.dev/blog/2026/04/22/announcing-lingui-6.0) (ESM-only, Node.js 22.19 or later), under the MIT license.

## What Lingui leaves to you

Here's a small inbox with Lingui's React macros:

```jsx title="Inbox.jsx"
import { Trans, Plural } from '@lingui/react/macro';

export function Inbox({ count }) {
  return (
    <section>
      <h1>
        <Trans>Inbox</Trans>
      </h1>
      <p>
        <Trans>
          You have <Plural value={count} one="# unread message" other="# unread messages" />.
        </Trans>
      </p>
    </section>
  );
}
```

`lingui extract` adds new target-language messages to PO catalogs with empty translations. Your translators or a connected service fill those entries while preserving ICU syntax. Here's the Spanish catalog once that's done:

```text title="locales/es/messages.po"
#: src/Inbox.jsx:7
msgid "Inbox"
msgstr "Bandeja de entrada"

#: src/Inbox.jsx:10
msgid "You have {count, plural, one {# unread message} other {# unread messages}}."
msgstr "Tienes {count, plural, one {# mensaje sin leer} other {# mensajes sin leer}}."
```

Then [`lingui compile`](https://lingui.dev/ref/cli) turns the catalog into a module the app loads. That cycle of extract, translate, and compile repeats for every change, the macros need a [build transform](https://lingui.dev/installation) (Lingui's Babel plugin, its Vite plugin, or an experimental SWC plugin), and whoever translates works from the PO entry and its comments, not the component.

## Keep inline copy and let General Translation produce the catalogs

General Translation's libraries keep the same inline authoring: copy stays in [`<T>`](/docs/react/reference/components/t), plural forms go in [`<Plural>`](/docs/react/reference/components/plural), and [`<Num>`](/docs/react/reference/components/num) formats values for each locale. Then General Translation does what Lingui doesn't: it generates the translations. Here's the same inbox with `gt-react`:

```tsx title="Inbox.tsx"
import { T, Plural, Num } from 'gt-react';

export function Inbox({ count }: { count: number }) {
  return (
    <T>
      <section>
        <h1>Inbox</h1>
        <Plural
          n={count}
          singular={<p>You have <Num>{count}</Num> unread message.</p>}
          plural={<p>You have <Num>{count}</Num> unread messages.</p>}
        />
      </section>
    </T>
  );
}
```

[`npx gt translate`](/docs/cli/reference/commands/translate) sends each [`<T>`](/docs/react/reference/components/t) block with its element structure and generates the target catalogs before your build. The `singular` and `plural` source branches supply wording for the forms each target language needs. [`<Plural>`](/docs/react/reference/components/plural) selects the translated branch at runtime. Strings outside JSX go through [`useGT`](/docs/react/reference/hooks/use-gt), the counterpart of Lingui's string macro.

In this example, the inbox heading and message branches travel together into translation. You can also add a [`context` note](/docs/react/reference/components/t#context) to explain product-specific meaning. Reviewers edit the generated text in the [Dashboard Translation Editor](/docs/platform/dashboard/guides/reviewing-translations); the next CLI run reuses unchanged translations and generates new copy, without a separate catalog-compilation command.

Profound's platform and docs ship in 47+ locales with General Translation. (See [production deployments](https://generaltranslation.com/enterprise).)

## Lingui vs. General Translation at a glance

| Feature | Lingui | General Translation |
| --- | --- | --- |
| How you write copy | Inline macros such as `<Trans>` | Inline JSX in [`<T>`](/docs/react/reference/components/t), and strings in [`useGT`](/docs/react/reference/hooks/use-gt) |
| Translates your content | No | Yes, with [`npx gt translate`](/docs/cli/reference/commands/translate) |
| Steps per change | Extract, translate each PO catalog, compile, with a macro transform in your build | [`npx gt translate`](/docs/cli/reference/commands/translate) before your build |
| Catalogs | PO files per locale, compiled to JavaScript modules | Generated per locale, stored in your repository or on General Translation's CDN |
| What the translator sees | The message, plus `context` and `comment` fields | The structure inside marked JSX blocks, context notes, and shared Glossary and Custom Prompts |

Keep Lingui when your translators work in gettext PO catalogs, when its compiled, minimal runtime matters for your bundle, or when your translation process already works. Choose General Translation when you want the same inline authoring without the extract, translate, and compile cycle, and translations generated with the context of your code.

## Moving from Lingui

Move one component or route at a time. Lingui's `<Trans>` maps to [`<T>`](/docs/react/reference/components/t), its `<Plural value={count} one="…" other="…" />` maps to [`<Plural>`](/docs/react/reference/components/plural) with `n={count}`, `singular` and `plural` branches, and [`<Num>`](/docs/react/reference/components/num) for the number. Its string macro maps to [`useGT`](/docs/react/reference/hooks/use-gt). Keep loading Lingui's existing translations for components you have not moved. Once the last component has moved, remove the macro transform and the extract and compile scripts. (See [Migrating i18n libraries](/docs/react/guides/migrating-i18n-libraries).)

## Key takeaways

- Lingui keeps copy inline and compiles a small runtime; translators or a connected service supply each target catalog.
- General Translation's libraries keep the same inline authoring, and General Translation also does the translating, with the context of your code and no catalog cycle.
- Lingui's macros map closely to [`<T>`](/docs/react/reference/components/t), [`<Plural>`](/docs/react/reference/components/plural), and [`useGT`](/docs/react/reference/hooks/use-gt), so you can migrate 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.
- [General Translation vs. i18next: which should you use?](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. react-intl: which should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-react-intl.mdx): 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, and gt-next supports inline translated JSX in Server Components.
- [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.
- [Can I do i18n without translation files?](https://generaltranslation.com/en-US/kb/i18n-without-translation-files.mdx): Yes. With gt-react or gt-next, content stays inline in your components inside a `<T>` component, and translations are generated at build time as output, so there are no keys or per-locale JSON files to write and keep in sync.

## Previous and next questions

- Previous question: [General Translation vs. Intlayer: which should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-intlayer.mdx)
- Next question: [General Translation vs. Locize: which should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-locize.mdx)

## Sitemap

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