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

i18next loads translation files, picks the message for the user's language, resolves plural forms, interpolates values, and formats numbers and dates with `Intl`. It's been on npm since 2012, and with `react-i18next` and `next-i18next` it's a common choice for React and Next.js apps. What i18next doesn't do is translate: every message in every language comes from you, your translators, or a service such as Locize, which [i18next's creators run](https://www.i18next.com/). General Translation's libraries do the same rendering job, and General Translation also generates the translations from the copy in your components.

## What i18next does well

- **Adoption.** It's one of the most widely used JavaScript i18n frameworks.
- **Breadth.** [Bindings cover React, Vue, Angular, Svelte, and more](https://www.i18next.com/overview/supported-frameworks), and plugins load files over HTTP, detect the user's language, and switch messages to ICU MessageFormat with `i18next-icu`.
- **Complete plural and context support.** Keys carry [CLDR plural suffixes](https://www.i18next.com/translation-function/plurals) such as `_one`, `_few`, and `_many`, resolved with `Intl.PluralRules`, and context variants such as `friend_male`.
- **Tooling.** The official [`i18next-cli`](https://github.com/i18next/i18next-cli) extracts keys, generates TypeScript types, and writes each locale's plural keys, and its `status` command exits with an error when a locale has untranslated keys, so CI can catch gaps.
- **Server Components.** [`next-i18next` 16](https://github.com/i18next/next-i18next) adds a server-side translation function for the Next.js App Router.
- **No required service.** Catalogs are plain JSON you own, and i18next works with any translation service or none.

## What i18next leaves to you

Here's a small inbox with react-i18next. Each string gets a key, and each plural form gets its own key:

```json title="locales/en/translation.json"
{
  "inbox": {
    "title": "Inbox",
    "unread_one": "You have {{count}} unread message.",
    "unread_other": "You have {{count}} unread messages."
  }
}
```

```tsx title="Inbox.tsx"
import { useTranslation } from 'react-i18next';

export function Inbox({ count }: { count: number }) {
  const { t } = useTranslation();
  return (
    <section>
      <h1>{t('inbox.title')}</h1>
      <p>{t('inbox.unread', { count })}</p>
    </section>
  );
}
```

Every other language needs the same message keys, with the plural forms that language uses: Polish needs `unread_one`, `unread_few`, `unread_many`, and `unread_other`. If a Polish file has only the English-shaped `_one` and `_other` forms and your [fallback language](https://www.i18next.com/principles/fallback) is English, counts such as 2 and 5 fall back to English:

```text title="Output"
pl, count 1:  Masz 1 nieprzeczytaną wiadomość.
pl, count 2:  You have 2 unread messages.
pl, count 5:  You have 5 unread messages.
pl, count 22: You have 22 unread messages.
```

Running `i18next-cli status` in CI catches the missing forms. Translation services can generate the catalog contents; your application still refers to keys such as `inbox.unread`, and the extraction and translation workflow keeps those catalogs current.

## General Translation keeps copy inline and generates translations

General Translation's libraries do the same job as i18next. They pick each locale's messages, apply its plural rules, interpolate variables, and format numbers, currencies, and dates with [`<Num>`](/docs/react/reference/components/num), [`<Currency>`](/docs/react/reference/components/currency), and [`<DateTime>`](/docs/react/reference/components/datetime), and teams that prefer keys can keep dictionaries with [`useTranslations`](/docs/react/reference/hooks/use-translations). Then General Translation does what i18next 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, to the General Translation API before your build and writes a translation for every target locale. The generic `singular` and `plural` source branches supply the wording for the forms each target language needs. [`<Plural>`](/docs/react/reference/components/plural) then selects a translated branch using that locale's rules. A value wrapped in [`<Var>`](/docs/react/reference/components/var) is never sent to the API.

When you edit a sentence inside [`<T>`](/docs/react/reference/components/t), the next translation run updates it for each language and reuses translations for unchanged content. Reviewers work in the [Dashboard Translation Editor](/docs/platform/dashboard/guides/reviewing-translations), so editing translations does not require changing components.

The JavaScript libraries are MIT-licensed and work without an account when you supply translations. An app configured to load all translations from its bundle makes no runtime calls to General Translation. No other i18n library sits underneath `gt-react` or `gt-next`.

Cursor ships 14+ locales across web and docs with General Translation. (See [production deployments](https://generaltranslation.com/enterprise).)

## i18next vs. General Translation at a glance

| Feature | i18next | General Translation |
| --- | --- | --- |
| How you write copy | Keys in JSON files per language and namespace | JSX inside [`<T>`](/docs/react/reference/components/t), strings through [`useGT`](/docs/react/reference/hooks/use-gt), or keyed dictionaries |
| Translates your content | No | Yes, with [`npx gt translate`](/docs/cli/reference/commands/translate) |
| Where translations come from | You, translators, or a service such as Locize | Generated with context from your code, or written by your team |
| Plural forms | A key per CLDR form, written for each language | [`<Plural>`](/docs/react/reference/components/plural) branches, translated with the rest of the block |
| Translation context | Source messages and context supplied by your translation workflow | The structure inside marked JSX blocks, context notes, and shared Glossary and Custom Prompts |
| Frameworks | React, Next.js, and bindings for Vue, Angular, Svelte, and more | React, Next.js, Vue, Node.js, and [additional SDKs](/docs/overview/get-started) |
| Account needed | No | Not for the libraries; translation runs through a General Translation project |

Keep i18next when your catalogs and translation process already work, when you build on a framework General Translation's libraries don't support, or when you want keys that stay stable as copy changes. Use General Translation when you want copy inline in your components, translations generated with the context of your code, and every language current with each build.

## Keep i18next and let General Translation translate it

You don't have to switch libraries. The `gt` CLI detects `i18next` in your `package.json` and preserves its interpolation syntax. Here is a configuration for translating the inbox catalog above into German:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["de"],
  "files": {
    "json": {
      "include": ["locales/[locale]/translation.json"]
    }
  }
}
```

English and German use the same `_one` and `_other` plural-key structure. This configuration generates `locales/de/translation.json` from `locales/en/translation.json`. Add per-key context, such as where a string appears, with [keyed metadata](/docs/cli/reference/keyed-metadata). Run [`npx gt upload`](/docs/cli/reference/commands/upload) to import your sources and existing translations before running [`npx gt translate`](/docs/cli/reference/commands/translate) for new copy.

To move to [`<T>`](/docs/react/reference/components/t) instead, follow [Migrating i18n libraries](/docs/react/guides/migrating-i18n-libraries). It covers replacing key lookups with inline copy, keeping your dictionaries with [`useTranslations`](/docs/react/reference/hooks/use-translations), and running both libraries while you move one route at a time. (See [General Translation vs. i18next, react-intl, and next-intl](/kb/general-translation-vs-i18n-libraries) for how i18next compares with the rest.)

## How do I handle Polish and other plural-heavy languages in i18next?

Each language needs a key for every CLDR plural form it uses, such as `_one`, `_few`, `_many`, and `_other` for Polish. Run `i18next-cli status` in CI to catch missing forms. With General Translation's inline authoring, write the `singular` and `plural` branches shown above, and the translation service generates the target forms. [`<Plural>`](/docs/react/reference/components/plural) selects the right one at runtime.

## Key takeaways

- i18next renders keyed catalogs and handles plural selection; people or a connected service produce the translations.
- General Translation's libraries render translations the same way, and General Translation also does the translating, from copy written inline in [`<T>`](/docs/react/reference/components/t).
- You can keep i18next and let the `gt` CLI translate its JSON files, or migrate to [`<T>`](/docs/react/reference/components/t) one route 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. 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. 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): Don't hard-code plural logic with checks like n === 1. A small helper is enough for English-only apps, but multilingual apps need locale-aware plural rules, which an i18n component such as `<Plural>` from gt-react or gt-next handles for every language.

## Previous and next questions

- Previous question: [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)
- Next question: [General Translation vs. Intlayer: which should you use?](https://generaltranslation.com/en-US/kb/general-translation-vs-intlayer.mdx)

## Sitemap

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