Migrating from Intlayer to source-strings calls
Intlayer is ideal for applications that manage translations via typed content dictionaries or translation management systems. ai-i18n-tools targets a different workflow: code that uses source-string calls such as t('English source'). The string inside t() is written in sourceLocale, which can be any language. English in these examples is only a sample. By keeping that source string directly in the code, this approach simplifies maintenance and reduces complexity. When this model fits your needs, migrate-intlayer imports your existing dictionaries and automatically rewrites compatible call sites. It leaves remaining sites unchanged and generates a report with specific replacement instructions, allowing you to complete the migration in stages or drop the report into a AI coding agent to complete the migration for you.
Already using i18next JSON translation files? You do not need this migration command; use the JSON pipeline instead.
Translate in place, or migrate off?
This page moves your app off Intlayer onto ai-i18n-tools' source-string t() calls, such as t('English source'). The string is written in sourceLocale, which can be any language. If you want to keep Intlayer at runtime and only fill the missing translations, use translate-intlayer instead — it translates the *.content.ts leaves in place.
What migrate-intlayer does
- Parses
*.content.tsdefault exports (key+content+t({ locale: '…' })leaves). - Seeds
ui.stringsJsonand per-locale files underui.flatOutputDirfrom the source-locale text and any translations already in the dictionary. Imported rows have nomodelsfield (they were not machine-translated by this run). - Rewrites safe call sites:
binding.path.to.leaf.value→t('English source')binding.path.value.replace('{token}', expr)→t('English {{token}}', { token: expr })
- Leaves everything else (dynamic keys, JSX spreads, chained
.replace().replace(), destructuring) untouched. The report lists each of those sites with the exact expression, a concretet()or JSX replacement, and theimport { t } from '…';line to add. - Dry run by default. Pass
--writeto apply catalog seeding and safe rewrites. The report is always written. It also lists dictionary files and leftoveruseIntlayer/IntlayerProviderusage to delete after the manual rewrites, catalog keys that still needextractthentranslate-ui, and a runtime bootstrap to paste over the app's i18n module.
Migrate your project
Install
ai-i18n-tools(see Installation). If your project has noai-i18n-tools.config.jsonyet, scaffold one:bashai-i18n-tools init -P geminiEdit
sourceLocaleandtargetLocalesto match the locales already in your Intlayer dictionaries, and setui.sourceRoots,ui.stringsJson,ui.flatOutputDirto point at your app's source and desired catalog paths — same keystranslate-uiuses, see UI strings — Step 1: Initialise.Dry run first:
ai-i18n-tools migrate-intlayer(no--write). Readmigrate-intlayer-report.mdto see what it finds and which call sites need manual review before any file changes.ai-i18n-tools migrate-intlayer --writeto seedui.stringsJson/ui.flatOutputDirand rewrite the safe call sites.Give the regenerated report
migrate-intlayer-report.mdto an AI coding agent (recommended), or work through it yourself by following the steps:- The report ends with a Step-by-step TODO: finish each manual-review site with the concrete
t('…')/JSX shown there, add theimport { t } from '…';line, then delete the leftover*.content.tsfiles anduseIntlayer/IntlayerProviderusage the report lists. - Paste the report's runtime bootstrap over your app's i18n module. In the locale control, call
loadLocale(next)and theni18n.changeLanguage(next)—loadLocaleonly registers the flat bundle and does not switch the active language. - Run
ai-i18n-tools extractthenai-i18n-tools translate-ui(orsync) for any source strings the report marks as new.extractalso writesui-languages.json, which the bootstrap imports, so run it before starting the app even when no new string was added. Do not hand-editstrings.json, the flat locale files, orui-languages.json— those commands own them. - Once the report's cleanup list is complete and the app runs on ai-i18n-tools, remove the
intlayer/react-intlayerdependencies and the dictionary files.
- The report ends with a Step-by-step TODO: finish each manual-review site with the concrete
Run the example
The steps above apply to any Intlayer project. The intlayer-migration example walks through them on a small Vite + React app with basic (auto-rewritable) and complex (manual-review) cases, so you can see the report and the runtime bootstrap before trying it on your own code. intlayer-pristine/ is never modified; src/ is the working copy.
npx degit wsj-br/ai-i18n-tools/examples/intlayer-migration intlayer-migration
cd intlayer-migration
pnpm install
pnpm reset
pnpm migrate:dry
pnpm migrate:writeHand migrate-intlayer-report.md to an AI coding agent (or edit the flagged files yourself). The report includes the runtime module to paste over src/i18n.ts. In the locale control, call loadLocale(next) and then i18n.changeLanguage(next). loadLocale only registers the flat bundle.
pnpm i18n:sync
pnpm devpnpm i18n:sync runs extract first, which writes ui-languages.json. The bootstrap imports that file, so start the app only after extract. Do not edit strings.json, the flat locale files, or ui-languages.json by hand.
pnpm reset copies intlayer-pristine/ back over src/ and clears generated catalogs so you can start over.
Full walkthrough: examples/intlayer-migration/README.md.
Command
ai-i18n-tools migrate-intlayer [paths...] [--write] [--report <path>] [--content-glob <glob>] [--t-import <specifier>]Requires ui.stringsJson and ui.flatOutputDir in config (same as translate-ui). Does not call an LLM.
| Option | Meaning |
|---|---|
[paths...] | Files/dirs/globs to scan (default: ui.sourceRoots) |
--write | Seed the catalog and rewrite safe call sites (default: dry run) |
--report <path> | Report path (default: migrate-intlayer-report.md) |
--content-glob <glob> | Dictionary filename glob (default: **/*.content.ts) |
--t-import <specifier> | Import specifier for generated t() (default: relative ./i18n if src/i18n.ts exists, otherwise i18next) |
After --write, finish the manual-review sites from the report, delete the unused *.content.ts files and IntlayerProvider wrapper it lists, paste in the runtime bootstrap, and call i18n.changeLanguage from the locale control. Run extract then translate-ui (or sync) for source strings the report marks as new. extract also writes ui-languages.json, which the bootstrap imports. Do not edit strings.json, the flat locale files, or ui-languages.json by hand.
See also: CLI — UI strings, Wire i18next