If you've ever set up i18n in a React or Next.js app the traditional way, you know the pain:
- Create a
/localesfolder with a JSON file for every language - Wrap every string with
t('some.key') - Configure your framework's i18n routing
- Maintain translations as your UI evolves
- Repeat for every new language
What if you could skip all of that?
@universal-i18n/react lets you add internationalization to your entire React app in literally two steps — with no translation files, no t() wrappers, and no build-time configuration.
What is @universal-i18n/react?
It's a tiny (<10KB, zero dependencies) npm package that automatically translates your entire React app at runtime using AI-powered translation (via the Lingo.dev API). It works by:
-
Observing the DOM with a
MutationObserverto catch all text — even dynamically loaded content - Batching translation requests for efficiency
-
Caching results in
localStorageso subsequent visits are instant - Keeping your API key secure on the server (in Next.js) via a built-in proxy route
Quick Setup (Next.js App Router)
Step 1 — Get your API key
Sign up at lingo.dev and grab your API key. Add it to .env.local:
LINGODOTDEV_API_KEY="your_api_key_here"
Step 2 — Create the API proxy route
Create app/api/universal-i18n/route.ts:
import { createTranslationRoute } from '@universal-i18n/react/server';
// One line. Your API key never reaches the browser.
export const POST = createTranslationRoute();
Step 3 — Wrap your layout
Create a client wrapper component:
// components/I18nWrapper.tsx
"use client";
import { AutoTranslateProvider } from '@universal-i18n/react';
export function I18nWrapper({ children }) {
return (
<AutoTranslateProvider sourceLocale="en" availableLocales="all">
{children}
</AutoTranslateProvider>
);
}
Then use it in your root layout:
// app/layout.tsx
import { I18nWrapper } from '@/components/I18nWrapper';
export default function RootLayout({ children }) {
return (
<I18Wrapper>
{children}
</I18Wrapper>
);
}
That's it. A floating 🌐 button appears in the corner of your app. Click it, pick a language, and your entire app switches — instantly.
Works with Vite and CRA Too
For non-Next.js apps, you can pass your API key directly to the provider. Note that this exposes the key to the browser — for production, it's recommended to build a small backend proxy and pass its URL to the apiRoute prop instead.
import { AutoTranslateProvider } from "@universal-i18n/react";
function App() {
return (
<AutoTranslateProvider
apiKey={import.meta.env.VITE_LINGO_API_KEY}
sourceLocale="en"
availableLocales="all"
>
<Navbar />
<MainContent />
</AutoTranslateProvider>
);
}
Build Your Own Language Switcher
Don't want the floating globe button? Use the useAutoTranslate hook to build your own UI:
import { useAutoTranslate } from '@universal-i18n/react';
export function LanguagePicker() {
const { locale, setLocale, availableLocales } = useAutoTranslate();
return (
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
{availableLocales.map((lang) => (
{lang.toUpperCase()}
))}
);
}
What Makes This Different from react-i18next or next-intl?
| Feature | Traditional i18n | universal-i18n |
|---|---|---|
| Translation files | ✅ Required (per language) | ❌ Not needed |
t() wrappers |
✅ Every string | ❌ Never |
| Setup time | Hours to days | ~2 minutes |
| Dynamic content | Manual handling | Auto (MutationObserver) |
| New languages | Re-translate everything | Just add the locale |
| Bundle size | Varies (often large) | <10KB |
The tradeoff is that translation happens at runtime via an external API rather than at build time, so there's a small latency on first load per locale (then cached). For most use cases, this is a worthwhile tradeoff to eliminate the maintenance burden.
Supported Languages
ALL_LOCALES includes 100+ languages out of the box, including:
🇺🇸 English · 🇪🇸 Spanish · 🇫🇷 French · 🇩🇪 German · 🇮🇳 Hindi · 🇯🇵 Japanese · 🇨🇳 Chinese · 🇧🇷 Portuguese · 🇷🇺 Russian · 🇰🇷 Korean · 🇸🇦 Arabic · 🇮🇹 Italian · 🇧🇩 Bengali · 🇹🇭 Thai · 🇻🇳 Vietnamese ... and 80+ more.
Security Note
In Next.js, createTranslationRoute() acts as a server-side proxy. The browser only calls your own /api/universal-i18n endpoint — your Lingo.dev API key is never exposed to the client. For other frameworks, you'll want to implement a similar proxy on your own backend.
Install It Now
npm install @universal-i18n/react
Final Thoughts
@universal-i18n/react is a genuinely clever approach to a genuinely tedious problem. If you've got an existing React app and want to reach a global audience without a major refactor, this is the fastest path to get there.
Give it a star on GitHub if you find it useful, and let the author know what you think!
Youtube Demo Video Link:
Built by Rohit Rawat · MIT License


Top comments (0)