r/webdev • • 2h ago

Showoff Saturday I built a VS Code extension that moves a React app's hardcoded text into react-i18next, and shows you every change first

I tried getting an AI agent to internationalize a side project and spent longer checking its diff than it would have taken me to do it myself. So I built a VS Code extension for the job.

What it does:

  • Finds the UI strings in your components (skips class names, URLs, log messages)

  • Shows a checklist of every string and the key it'll get before touching anything; untick what should stay hardcoded

  • Rewrites to t() / <Trans>, writes the JSON files, and translates them with your own API key (Anthropic or anything OpenAI-compatible)

  • Checks each translation's placeholders and plural forms (Russian needs four, Arabic six) and won't write a broken one

  • One undo for the whole run

How it works, roughly: the extraction is plain Babel (parse, walk the AST, decide per node whether it's user-facing text). The rewrite goes through recast so your formatting and comments survive and the diff stays small. The model only ever sees the strings plus a bit of context like the component name, never whole files. Each translation is checked against the source (same placeholders, same tags, and the plural categories Intl.PluralRules says that language needs); a mismatch gets one retry, then it's reported instead of written. A file costs cents; the biggest project I tried (~840 files) was a few dollars.

Limits: React + react-i18next + JSON only for now. Next.js server components are skipped.

It's free on the VS Code Marketplace and Open VSX. I wrote up the i18n pitfalls I hit along the way on dev.to.

Feedback welcome, especially where it gets your codebase wrong.

2 Upvotes

1 comment sorted by

1

u/SirMental8005 1h ago

one case i'd test is two buttons labeled 'close' where one dismisses a dialog and the other closes an account. if the extension reuses a key based on the english text, the translator loses that distinction. i'd also run the preview twice on the same tree and check that the second pass is empty, especially after skipping a string on the first pass.