Show HN: Localize React apps without rewriting code
by maxpr | 2025-06-03 17:27:32+00:00
Hi HN! We've just released an open-source React bundler plugin that makes apps multilingual—at build time, without modifying the code.

React app localization typically requires implementing i18n frameworks, extracting text to JSON files, and wrapping components in translation tags - essentially rewriting your entire codebase before you can even start translating.

Our React bundler plugin eliminates this friction entirely. You add it to an existing React app, specify which languages you want, and it automatically makes your app multilingual without touching a single line of your component code.

Here's a video showing how it works: https://www.youtube.com/watch?v=sSo2ERxAvB4. The docs are at https://lingo.dev/en/compiler and, sample apps at https://github.com/lingodotdev/lingo.dev/tree/main/demo.

Last year, a dev from our Twitter community told us: "I don't want to wrap every React component with `<T>` tags or extract strings to JSON. Can I just wrap the entire React app and make it multilingual?"

Our first reaction was "That's not how i18n works in React." But a couple hours later, we found ourselves deep in a technical rabbit hole, wondering what if that actually was possible?

That question led us to build the "localization compiler" - a middleware for React that plugs into the codebase, processes the Abstract Syntax Tree of the React code, deterministically locates translatable elements, feeds every context boundary into LLMs, and bakes the translations back into the build, making UI multilingual in seconds.

Everything happens locally during build time, keeping the React project as the source of truth. No code modifications, no extraction, and no maintenance of separate translation files are needed, however, overrides are possible via data-lingo-* attributes.

Building this was trickier than we expected. Beyond traversing React/JS abstract syntax trees, we had to solve some challenging problems. We wanted to find a way to deterministically group elements that should be translated together, so, for example, a phrase wrapped in the `<a>` link tag wouldn't get mistranslated because it was processed in isolation. We also wanted to detect inline function calls and handle them gracefully during compile-time code generation.

For example, this entire text block that our localization compiler identifies as a single translation unit, preserving the HTML structure and context for the LLM.

``` function WelcomeMessage() { return ( <div> Welcome to <i>our platform</i>! <a href="/start">Get started</a> today. </div> ); } ```

The biggest challenge was making our compiler compatible with Hot Module Replacement. This allows developers to code in English while instantly seeing the UI in Spanish or Japanese, which is invaluable for catching layout issues caused by text expansion or contraction in different languages that take more/less space on the screen.

For performance, we implemented aggressive caching that stores AST analysis results between runs and only reprocesses components that have changed. Incremental builds stay fast even on large codebases, since at any point in time as a dev, you update only a limited number of components, and we heavily parallelized LLM calls.

This approach was technically possible before LLMs, but practically useless, since for precise translations you'd still need human translators familiar with the product domain. However, now, with context-aware models, we can generate decent translations automatically.

We're excited about finally making it production ready and sharing this with the HN community.

Run `npm i lingo.dev` , check out the docs at lingo.dev/compiler, try breaking it and let us know what you think about this approach to React i18n!