diff --git a/docs/en-US/cli/reference/commands/meta.json b/docs/en-US/cli/reference/commands/meta.json index b2b260cad..b01e433aa 100644 --- a/docs/en-US/cli/reference/commands/meta.json +++ b/docs/en-US/cli/reference/commands/meta.json @@ -3,6 +3,7 @@ "description": "Browse CLI Commands pages.", "pages": [ "./init", + "./migrate", "./setup", "./configure", "./auth", diff --git a/docs/en-US/cli/reference/commands/migrate.mdx b/docs/en-US/cli/reference/commands/migrate.mdx new file mode 100644 index 000000000..677c05c1e --- /dev/null +++ b/docs/en-US/cli/reference/commands/migrate.mdx @@ -0,0 +1,81 @@ +--- + +title: gt migrate +description: Convert an existing internationalized Next.js app to gt-next in one command. API reference for the gt migrate command. + +--- + +Converts an existing internationalized Next.js App Router project to [`gt-next`](/docs/react/overview) in one command. It reads your current i18n setup, sets up gt-next, and rewrites your code and message catalogs. Your existing translations are preserved. + +`--from` is required. The supported values today are `next-intl`, `react-intl`, and `react-i18next`. For a new project with no existing i18n library, use [`gt init`](/docs/cli/reference/commands/init) instead. + +*Note: `migrate` requires a clean git working tree. Commit or stash your changes first, so every edit the command makes is easy to review and revert. Pass `--allow-dirty` to skip this check.* + +```bash +npx gt migrate --from next-intl +``` + +## How it works [#how-it-works] + +1. **Surveys the project.** Confirms the library you passed to `--from` is installed, then reads your locales and default locale, where your message catalogs live, and your package manager. Library detection is advisory here: `--from` decides what is migrated, and a mismatch is reported as a warning. +2. **Sets up gt-next.** Creates or updates `gt.config.json`, wires up dictionary loading, adds the provider, wraps your Next.js config in `withGTConfig`, adds middleware when the project needs it, and installs `gt-next`. The `withGTConfig` options carry `cacheUrl: null` until a General Translation project is configured, so a dictionary-only project does not warn about a missing Project ID on every build. +3. **Migrates the code and catalogs.** Rewrites call sites and components, converts message catalogs (including ICU plural and context forms), and removes the old library where it is safe to do so. + +Every edit is buffered until the last pass finishes, so a run that stops partway leaves the project untouched. + +### Requirements + +- **App Router.** A project with no `app/` or `src/app/` directory is refused with nothing changed. Pages Router and `next-i18next` setups are not supported. +- **A server provider boundary, for `react-intl` and `react-i18next`.** These need `[locale]` as the root layout segment, a Server Component in that chain rendering ``, and Next.js 15.5 or later. Without all three the run stops before writing anything and prints the manual steps, because gt-next's server `GTProvider` has nowhere correct to mount. +- **Next.js 15.5 or later to keep static rendering.** `next-intl` projects still migrate on older Next.js, but the locale then resolves per request and the report leaves a TODO instead of restoring static rendering. +- **`gt-next` 11.1.0 or later for webpack builds.** On an older `gt-next`, build with `next build --turbopack` or upgrade. + +## Flags [#flags] + +| Parameter | Description | Type | Optional | Default | +| --- | --- | --- | --- | --- | +| `--from ` | Library to migrate from: `next-intl`, `react-intl`, or `react-i18next`. | `string` | No | None | +| `--src ` | Glob patterns for the source files to migrate. | `string[]` | Yes | `src`, `app`, `pages`, `components`, and `i18n` globs, plus the directories your i18n config files sit in | +| `-c, --config ` | Path to the config file. | `string` | Yes | `gt.config.json` | +| `--dry-run` | Print the migration report without writing files. | `boolean` | Yes | `false` | +| `--allow-dirty` | Skip the clean-git-tree safety check. | `boolean` | Yes | `false` | +| `-y, --yes` | Skip the confirmation prompt. | `boolean` | Yes | `false` | + +## Example [#example] + +```bash +# Migrate a next-intl project to gt-next +npx gt migrate --from next-intl + +# Preview the changes without writing anything +npx gt migrate --from next-intl --dry-run + +# Migrate from react-i18next +npx gt migrate --from react-i18next +``` + +## What to expect [#what-to-expect] + +- **Report:** the command writes `gt-migrate-report.md` to your project root. It lists everything that changed, every file it skipped and why, and the TODOs that need a human decision. +- **Partial migrations:** migrations can be partial by design. Anything the tool cannot convert safely is skipped, and the old library stays wired up for those files, so your app keeps working. A run that finishes exits `0` even when it held files back. +- **Hard stops:** a wiring the command cannot produce correctly stops the run before anything is written, and it exits `1`. That covers a missing server provider boundary, a Next.js config it cannot wrap in `withGTConfig`, catalogs it cannot find, and a routing config whose locales share nothing usable with your catalogs. +- **Confirmation:** the command prompts before rewriting files in place. Pass `-y` in CI; with no terminal to answer the prompt, it exits without writing. +- **Formatting:** it runs your project's formatter over the files it rewrote. A file is left unformatted when reformatting would change its rendered JSX, and the report names it. +- **Lockfile:** installing `gt-next` rewrites your lockfile. Run your lockfile install once (`npm ci`) before committing: npm can write a lockfile it then rejects, and a second `npm install` resyncs it. +- **On-demand engine:** the migration engine ships as a separate package, `@generaltranslation/migrate`, so the `gt` CLI stays small. The first `gt migrate` run downloads it automatically. This is a one-time step and needs network access. In an offline or restricted environment, add `@generaltranslation/migrate` as a devDependency with your package manager and run the command again. + +## Manual follow-ups [#manual-follow-ups] + +Some patterns need a human, and the report flags each one so you can finish it by hand: + +- Test wiring: setup files, render helpers, and module mocks that reference the old library. They keep intercepting code that now calls gt-next, so those suites fail until you migrate them. The report lists each file with the evidence that flagged it. +- Rich-text render-prop translations, such as next-intl's `t.rich`. +- Dynamic translation keys or namespaces that the tool cannot resolve at build time. +- Custom wrapper hooks around the old library. For `react-i18next` this includes the App Router wrapper pattern, where components import from a local `i18n/client` or `i18n/server` module; the server side is skipped with a `getTranslations` recipe. + +## After the migration [#after] + +1. Review `gt-migrate-report.md` and resolve any TODOs it lists. +2. Migrate the test wiring it lists, then run those suites. +3. Run your build, then your app, to confirm the migrated pages render in the right locale. +4. Translate new strings with [`gt translate`](/docs/cli/reference/commands/translate). The run records the migrated catalog as the `dictionary` key in `gt.config.json`, so no flag is needed unless your config already named a dictionary. See [Generating translations](/docs/cli/guides/generating-translations) for the full workflow.