# General Translation Knowledge Base: Can I do i18n without translation files?
URL: https://generaltranslation.com/en-US/kb/i18n-without-translation-files.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Yes. General Translation's gt-react and gt-next libraries do React and Next.js i18n with no translation keys and no JSON file per language to maintain. Copy stays inline in JSX inside the `<T>` component, and the gt translate command generates each language's translations in your build, with context from your code. Locadex can keep them current through pull requests.
Category: Internationalization
Last updated: 2026-10-21
Authors: Jackie Chen, Ernest McCarter
Published: 2026-05-07

Yes. General Translation's open-source `gt-react` and `gt-next` libraries let you internationalize (i18n) a React or Next.js app without translation keys and without writing a JSON file for each language. You write copy inline in your JSX inside the [`<T>`](/docs/react/reference/components/t) component, and [`npx gt translate`](/docs/cli/reference/commands/translate) generates the translations for every language when you build.

Key-based libraries such as i18next, react-intl, and next-intl look up each string by key in a message file per language, so every new string needs a key in every file. A key added to `en.json` but missed in `ja.json` leaves one line of your Japanese checkout page untranslated.

Translation files still exist with General Translation, but as build output. The CLI writes one generated file per language and can publish the translations to General Translation's CDN. No one edits those files by hand or copies keys between them.

## Video

The video is narrated in English, with English captions.

[Can I do i18n without translation files?](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-i18n-without-translation-files.mp4) (46 sec)

General Translation lets you stop writing translation files with `gt-react` or `gt-next`. Run `npx gt init`, write the English inside a `<T>` component, then add `npx gt translate` to your build script so every build writes the translations.

## Can I translate React components inline instead of using a key file?

Yes. With General Translation, each sentence stays in the component inside [`<T>`](/docs/react/reference/components/t), and the CLI translates the whole block. A checkout summary with react-i18next reads every string by key from a JSON file:

```json title="locales/en/checkout.json"
{
  "summary": {
    "title": "Order summary",
    "item_count_one": "You have {{count}} item in your cart.",
    "item_count_other": "You have {{count}} items in your cart.",
    "tax_notice": "Tax is calculated at checkout."
  }
}
```

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

export function CheckoutSummary({ itemCount }: { itemCount: number }) {
  const { t } = useTranslation('checkout');
  return (
    <section>
      <h2>{t('summary.title')}</h2>
      <p>{t('summary.item_count', { count: itemCount })}</p>
      <small>{t('summary.tax_notice')}</small>
    </section>
  );
}
```

The same component with `gt-next` keeps the English in the JSX. Other React frameworks import from their own package, such as `gt-react`.

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

export function CheckoutSummary({ itemCount }: { itemCount: number }) {
  return (
    <T>
      <section>
        <h2>Order summary</h2>
        <Plural
          n={itemCount}
          one={<p>You have <Num>{itemCount}</Num> item in your cart.</p>}
          other={<p>You have <Num>{itemCount}</Num> items in your cart.</p>}
        />
        <small>Tax is calculated at checkout.</small>
      </section>
    </T>
  );
}
```

The `gt-next` version has no `checkout.json`, no keys to name, and no `ja.json` to update. [`npx gt translate`](/docs/cli/reference/commands/translate) sends each [`<T>`](/docs/react/reference/components/t) block, with its element structure as context, to the General Translation API and writes a translation for every language in `gt.config.json`. [`<Plural>`](/docs/react/reference/components/plural) picks the plural form each language needs (Japanese uses one form, Arabic six), and [`<Num>`](/docs/react/reference/components/num) formats the count for the reader's locale.

## Which i18n libraries let you write text directly in JSX without key files?

General Translation's `gt-react` and `gt-next` let you write translatable text directly in JSX with no key files, and General Translation generates the translations. Lingui and next-intl's experimental extraction also accept inline messages, but they extract them into catalogs that your team, translators, or a service still has to translate.

| Library | Where you write copy | Where translations come from | What your team maintains |
| --- | --- | --- | --- |
| i18next (`react-i18next`) | Keys in a JSON file per language | Your team, translators, or a service | A key for every string, in every language's file |
| next-intl | Keys in a JSON catalog per language; [inline messages with `useExtracted`](https://next-intl.dev/docs/usage/extraction) are experimental | Your team, translators, or a service | Every catalog, kept current as the copy changes |
| [Lingui](https://lingui.dev/introduction) | Inline `<Trans>` macros with generated message IDs, extracted to PO catalogs | Your team, translators, or a service | Extracting, translating, and compiling catalogs |
| General Translation (`gt-react`, `gt-next`) | Inline JSX inside [`<T>`](/docs/react/reference/components/t), strings through [`useGT`](/docs/react/reference/hooks/use-gt), or optional keyed dictionaries | Generated by [`npx gt translate`](/docs/cli/reference/commands/translate) in each build, with context from your code | Wrapping copy in [`<T>`](/docs/react/reference/components/t) and one build step |

Use i18next or next-intl when translators or a translation management system already work from catalog files, or when the copy rarely changes. Use Lingui or next-intl extraction when you want inline source and plan to send catalogs out for translation. Use General Translation when you want copy inline and every language generated with each build. Teams that prefer stable keys can keep them with General Translation's [dictionary mode](/docs/react/guides/translating-with-dictionaries).

## What are the pros and cons of key-based i18n and inline translation?

Inline translation keeps each sentence in the React component that renders it, so components and pull requests stay readable and there are no keys to name, sync, or clean up. The cost is that source copy lives in code, so copy edits go through developers. Key-based i18n keeps copy in catalogs apart from the code, which lets writers and translators work without touching components but adds a key and an entry in every language's file for each string. General Translation supports both: inline copy with [`<T>`](/docs/react/reference/components/t), or keys with dictionary mode.

| Task | Translation keys (i18next, next-intl) | Inline copy (General Translation) |
| --- | --- | --- |
| Reading a component or a pull request | You see `t('summary.tax_notice')` and open the JSON file to find the sentence | You see the sentence in the JSX |
| Adding a string | Name a key, add it to the source file, then get it into every language's file | Write it inside [`<T>`](/docs/react/reference/components/t); the next [`gt translate`](/docs/cli/reference/commands/translate) run translates it |
| Changing source copy | Other languages keep the old translation until someone updates them | The next run translates the changed entry again |
| Deleting a component | Its keys stay in every file until someone or a script removes them | The next run stops collecting its content |
| Adding a language | Create a file with every key and translate it | Add the locale code to `locales` in `gt.config.json` and run [`gt translate`](/docs/cli/reference/commands/translate) |
| Stable IDs | Every string has one | Optional, with [`$id`](/docs/react/reference/components/t#id) on [`<T>`](/docs/react/reference/components/t) or dictionary mode |
| Who edits source copy | Writers can edit a catalog without touching code | Copy changes are code changes |

Keys fit better when writers edit source copy without touching code, or when components should hold no sentences in any one language. In that case, keep your keys: General Translation's [dictionary mode](/docs/react/guides/translating-with-dictionaries) reads a keyed dictionary and still generates the translations.

## How do I add multi-language support to a Next.js App Router app without translation keys?

Use General Translation's `gt-next` library and the `gt` CLI in four steps, which the [Next.js App Router quickstart](/docs/react/nextjs-quickstart) also covers by hand:

1. Run [`npx gt@latest init`](/docs/cli/reference/commands/init). The setup wizard detects the App Router, can install `gt-next`, add `withGTConfig` to `next.config.ts` and [`GTProvider`](/docs/react/reference/components/gt-provider) to `app/layout.tsx`, and writes your languages to `gt.config.json`. It can also write a development key to `.env.local`, so `next dev` translates new copy on demand. Review the changes it makes.
2. Wrap copy in [`<T>`](/docs/react/reference/components/t) and add a [`<LocaleSelector>`](/docs/react/reference/components/locale-selector) dropdown for switching languages. [`<T>`](/docs/react/reference/components/t) works in Server Components and Client Components.
3. Put [`npx gt translate`](/docs/cli/reference/commands/translate) before `next build` in your build script.
4. Set `GT_PROJECT_ID` and `GT_API_KEY` in your hosting provider. The build's key needs **Files > Write** and **Translation queue** enabled.

```tsx title="app/page.tsx"
import { T, LocaleSelector } from 'gt-next';

export default function Home() {
  return (
    <main>
      <LocaleSelector />
      <T>
        <h1>Find your next project</h1>
        <p>Explore projects from teams around the world.</p>
      </T>
    </main>
  );
}
```

```json title="package.json"
{
  "scripts": {
    "build": "npx gt translate && next build"
  }
}
```

Each production build then writes translations for every language in `gt.config.json`. For a longer walkthrough with Server and Client Components, see [How do I add i18n to a Next.js App Router app?](/kb/add-i18n-to-nextjs). To hand the setup to a coding agent, see [the coding-agent workflow](/kb/ai-agent-i18n-setup).

## How do I stop translation JSON files from going out of sync with my source code?

Generate them from the source code in every build instead of editing them. With key files, an app with 400 strings in 12 target languages has 4,800 entries that someone keeps in step with the code. With General Translation, [`npx gt translate`](/docs/cli/reference/commands/translate) runs before the build, collects every [`<T>`](/docs/react/reference/components/t) block and [`useGT`](/docs/react/reference/hooks/use-gt) string, translates what is new or changed into each language in `gt.config.json`, and writes one JSON file per language to the `files.gt.output` path:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "fr", "ja"],
  "files": {
    "gt": {
      "output": "public/_gt/[locale].json"
    }
  }
}
```

```txt title=".gitignore"
public/_gt/
```

Because General Translation regenerates those files from the code each build compiles, they match that code. The Next.js quickstart adds the output directory to `.gitignore`, since the files are generated. General Translation's [incremental workflow](/docs/cli/guides/generating-translations#retranslate) translates only changed source and reuses matching translations from earlier versions. [Branch tracking](/docs/cli/guides/branching) (`--enable-branching`, on a Starter or Enterprise plan) keeps a feature branch's translations separate from production until it merges.

For teams that want translation changes committed to the repository, [Locadex automations](/docs/platform/locadex/guides/configuring-automations) translate new or updated source content, and add or remove locale files when your language list changes, through pull requests. Each automation runs on one of three triggers: a pull request changes, a commit is pushed, or someone starts it manually. See [How do I keep translations up to date on every deploy?](/kb/translations-in-ci) for CI setups.

## Can General Translation add i18n to a React app automatically?

Yes. General Translation automates both steps of React i18n: wrapping copy for translation and generating the translations.

- **At build time:** the General Translation compiler, `@generaltranslation/compiler`, wraps translatable JSX text in [`<T>`](/docs/react/reference/components/t) when you set `enableAutoJsxInjection` under `files.gt.parsingFlags` in `gt.config.json`. [Automatic JSX injection](/docs/cli/guides/using-auto-jsx) works in React single-page apps, server-rendered React apps, and Next.js webpack builds. For Next.js, use webpack for this compiler workflow; with Turbopack, mark content with [`<T>`](/docs/react/reference/components/t) directly or use Locadex to add the wrappers.
- **Through pull requests:** Locadex, General Translation's AI agent, runs a **Generate code** automation that wraps your source in [`<T>`](/docs/react/reference/components/t) and string calls such as [`useGT`](/docs/react/reference/hooks/use-gt), then opens a pull request for you to review or auto-merge.
- **For the translations:** [`npx gt translate`](/docs/cli/reference/commands/translate) in your build, or a Locadex **Generate translations and push** automation, translates new and changed content into every configured language.

## How does gt-next compare with next-intl?

next-intl renders messages from a JSON catalog per language that your team or a service writes. gt-next, General Translation's Next.js library, keeps copy inline in [`<T>`](/docs/react/reference/components/t) and generates every translation with [`gt translate`](/docs/cli/reference/commands/translate). Both support the App Router and Server Components, and both are MIT-licensed.

You don't have to switch libraries to use General Translation. The `gt` CLI detects next-intl, react-i18next, and next-i18next from `package.json` and [translates their JSON files](/docs/cli/guides/generating-translations) while preserving each library's message syntax, so your components and routing stay the same. To move to inline copy later, the [migration guide](/docs/react/guides/migrating-i18n-libraries) covers replacing keys with [`<T>`](/docs/react/reference/components/t), keeping dictionaries with [`useTranslations`](/docs/react/reference/hooks/use-translations), and running both libraries while you migrate one route at a time. For a side-by-side comparison, see [next-intl vs gt-next](/kb/next-intl-vs-gt-next).

## How do reviewers correct translations without editing translation files?

Reviewers use General Translation's [Dashboard Translation Editor](/docs/platform/dashboard/guides/reviewing-translations). They compare locales side by side and edit generated translations without opening locale files or starting a new translation job. If your team edits downloaded files instead, [`npx gt save-local`](/docs/cli/reference/commands/save-local) uploads those edits to the platform, or pass `--save-local` to [`gt translate`](/docs/cli/reference/commands/translate) to sync them in each run.

Translation context is set in the code and in the Dashboard. The [`context` prop](/docs/react/reference/components/t#context) on [`<T>`](/docs/react/reference/components/t) resolves ambiguous words: "Save" in a document editor becomes *speichern* in German, while saving money becomes *sparen*. [Glossary terms and Custom Prompts](/docs/platform/dashboard/guides/defining-context-for-translations) in a Context Group apply the same terminology and tone across your app, docs, and other projects.

## Where do generated translations live, and do I need an account?

Generated translations live in one of two places:

- **Bundled with your app:** a [local loader](/docs/react/guides/storing-translations) imports the generated files, so the production app reads its own translations and makes no runtime requests to General Translation. New translations ship with the next build.
- **On General Translation's CDN:** with [CDN delivery](/docs/react/guides/configuring#delivery), published edits reach the deployed app without a rebuild, subject to its version and cache settings.

`gt-react` and `gt-next` are [MIT-licensed](https://github.com/generaltranslation/gt) and work without a General Translation account when you supply the translations. [`npx gt generate`](/docs/cli/reference/commands/generate) writes a template file per locale for you to translate by hand. Generating translations with [`gt translate`](/docs/cli/reference/commands/translate) uses General Translation's hosted service; see [General Translation's pricing](https://generaltranslation.com/pricing).

## Key takeaways

- You can do i18n without translation files: General Translation's `gt-react` and `gt-next` keep copy inline in [`<T>`](/docs/react/reference/components/t) with no translation keys, and [`npx gt translate`](/docs/cli/reference/commands/translate) generates a file per language in each build.
- The generated files are build output. No one edits them or copies keys between them, so they stay in sync with the code.
- General Translation's compiler can wrap JSX in [`<T>`](/docs/react/reference/components/t) at build time, and Locadex can wrap code and translate it through pull requests.
- If you already use next-intl or react-i18next, the `gt` CLI translates your existing JSON catalogs, and dictionary mode keeps keys if you want them.

## Related questions

- [How do I add i18n to a Next.js App Router app?](https://generaltranslation.com/en-US/kb/add-i18n-to-nextjs.mdx): Start with gt init to configure General Translation in a supported App Router project, then mark source content, generate translations, and verify language switching. gt-next keeps copy in JSX with translation context; the CLI, Dashboard editor, and Locadex handle generation, review, and ongoing updates. This guide also shows the explicit local-file setup.
- [How do I internationalize an app with Cursor or Claude Code?](https://generaltranslation.com/en-US/kb/ai-agent-i18n-setup.mdx): Start with General Translation's Setup for Agents prompt in Cursor or Claude Code, choose a feature and target languages, and have the agent implement and verify the result. Browser sign-in, machine-readable docs, and MCP tools connect setup to translation and review. Use Locadex to automate continuing localization through pull requests.
- [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.
- [How do I keep translations up to date on every deploy?](https://generaltranslation.com/en-US/kb/translations-in-ci.mdx): Run translation as a pipeline step before each production build, so new copy ships translated with the deploy that adds it. General Translation's gt CLI does this with npx gt translate, using a project API key and project ID stored as CI secrets.

## Previous and next questions

- Previous question: [What is the best localization software for developers?](https://generaltranslation.com/en-US/kb/best-localization-software.mdx)
- Next question: [Crowdin alternatives: General Translation vs. Crowdin](https://generaltranslation.com/en-US/kb/general-translation-vs-crowdin.mdx)

## Sitemap

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