i18n-keyless vs Lingui: which to pick in 2026
Lingui is the "modern i18next" — a lightweight, TypeScript-first i18n library with compile-time message extraction and full ICU MessageFormat support. Where i18next grew organically over a decade of plugins, Lingui was designed from scratch with a cleaner API: macros that look like regular function calls, a compiler that extracts messages at build time, and catalogs that stay in sync automatically.
i18n-keyless skips the catalog entirely. There are no message IDs, no extraction step, no .po or .json files to maintain. The source string is the key, translations are AI-generated, and the whole pipeline disappears.
This is an honest comparison. Lingui is a genuinely good library and we'll tell you when it's the better choice.
TL;DR
| i18n-keyless | Lingui | |
|---|---|---|
| Setup time | ~5 minutes | ~30 minutes (plus extraction pipeline) |
| Translation keys | None — source string is the key | Auto-extracted message IDs |
| Locale files | None | .po or .json catalogs, one per locale |
| AI translation | Built in | None — integrate a TMS or MT service |
| Plurals, ordinals, gender | count / ordinal / select, forms written by the model | Hand-authored ICU (plurals, select, nested) |
| Extraction step | None | Required — lingui extract in CI |
| Bundle size | Small runtime | Very small (messages compile away) |
| Best for | MVPs, multi-framework, engineer-driven | Apps needing ICU, compile-time checks, small bundles |
Pick i18n-keyless if you want multilingual in an afternoon and don't need to hand-author the ICU branches yourself. Pick Lingui if you want to hand-author ICU MessageFormat, need compile-time guarantees, and the smallest possible runtime bundle.
The code difference
Lingui setup
npm install @lingui/core @lingui/react @lingui/cli @lingui/macro @lingui/vite-plugin
// lingui.config.ts
export default {
locales: ["en", "fr", "de", "es"],
catalogs: [{ path: "src/locales/{locale}", include: ["src/"] }],
sourceLocale: "en",
};
// In a component
import { Trans, t } from "@lingui/macro";
function Checkout() {
return (
<div>
<h1><Trans>Your cart</Trans></h1>
<button><Trans>Confirm payment</Trans></button>
<input placeholder={t`Search products`} />
</div>
);
}
Then run lingui extract to scan the code and generate catalog files:
npx lingui extract
# Creates src/locales/en.po, src/locales/fr.po, etc.
Each .po file needs translations filled in — by a translator, a TMS, or a machine translation pass. Then compile:
npx lingui compile
# Generates optimized runtime catalogs
i18n-keyless setup
npm install i18n-keyless-react
import { I18nKeylessText, useTranslation } from "i18n-keyless-react";
function Checkout() {
const placeholder = useTranslation("Search products");
return (
<div>
<h1><I18nKeylessText>Your cart</I18nKeylessText></h1>
<button><I18nKeylessText>Confirm payment</I18nKeylessText></button>
<input placeholder={placeholder} />
</div>
);
}
No extraction. No catalogs. No compile step. Translations are AI-generated the first time a string is encountered, cached, and overridable from the dashboard.
Where Lingui genuinely wins
Hand-authored ICU MessageFormat
Lingui handles every ICU construct — plurals with CLDR rules, select, selectordinal, nested arguments — and you write every branch:
<Plural value={count} zero="No items" one="1 item" other="# items" />
<Trans>
{gender, select, male {He} female {She} other {They}} liked your post
</Trans>
Polish (4 plural forms), Arabic (6 plural forms), Russian — Lingui gets them right because you follow the CLDR specification. i18n-keyless covers the same CLDR rules from the model's side: pass count or select and one source form, and the model writes every branch each language needs, validated against Intl.PluralRules before they're saved (see the plurals and genders guide). The difference is authorship: with Lingui you write the branches in catalog files; with i18n-keyless the model writes them and you edit in the dashboard when you disagree.
Compile-time extraction
lingui extract scans your codebase and finds every translatable string automatically. You know at build time:
- Which strings exist.
- Which locales are missing translations.
- Which strings were added or removed since the last extraction.
This is a real safety net. With i18n-keyless, a string exists when it's first rendered — there's no upfront inventory.
Tiny runtime bundle
Lingui compiles message catalogs into optimized JavaScript. The runtime is minimal — messages are resolved from a precompiled lookup, not fetched from a server. For apps where every kilobyte matters (mobile web, poor connections), Lingui's approach produces smaller bundles.
i18n-keyless includes a small runtime SDK and makes an API call to fetch translations (cached locally after the first load). It's not heavy, but it's not zero.
Macro-based DX
Lingui's macros (t, <Trans>, <Plural>) look like regular code. The compiler transforms them at build time, so there's no runtime overhead for the extraction. It's elegant — you write natural-looking JSX and the tooling handles the rest.
Active, growing community
Lingui has a dedicated community, good documentation, and active maintenance. It's increasingly recommended as the "modern alternative to react-intl" — and rightfully so.
Where i18n-keyless wins
No extraction pipeline
Lingui requires an extract → translate → compile pipeline. That's three CLI commands, a CI step, and a process for getting translations into the catalog files. Skip a step and you ship untranslated strings.
i18n-keyless has no pipeline. Write a string, it translates itself.
No catalog files to manage
Lingui keeps .po or .json catalogs in your repo — one per locale. These need to be committed, reviewed, merged, and kept in sync. A new locale means a new file to maintain.
i18n-keyless stores translations in its backend. No files in your repo, no merge conflicts, no "which branch has the latest French translations?" questions.
AI translation is built in
Adding a new language to a Lingui project means: run lingui extract, get empty catalog entries for the new locale, fill them with translations (human or machine), run lingui compile, deploy. Adding a new language to i18n-keyless means: add the language code to the supported array.
Works beyond React
Lingui is primarily a React library (with growing Svelte and Vue support). i18n-keyless has SDKs for React, React Native, Vue, Angular, Svelte, Node.js, Laravel, Rails, Flutter, Go, Python, Swift, and Kotlin — same dashboard, same API key, same translations across your entire stack.
No bundler plugin required
Lingui needs a Vite/webpack/Babel plugin for its macros to work. i18n-keyless is a regular npm package — install it, import it, call init(). No build config to touch.
When to choose Lingui
✅ You want every plural branch in a catalog file you control. ✅ Compile-time extraction and type safety are important to your team. ✅ Bundle size is a critical constraint (mobile web, offline-first). ✅ You want an open-source, self-contained solution with no external API dependency. ✅ You have translators filling catalog files (or a TMS connected to Lingui).
When to choose i18n-keyless
✅ You want multilingual in a day, not after setting up an extraction pipeline. ✅ You don't have (or don't want) translators in the loop. ✅ Your product spans multiple frameworks and languages. ✅ You want to add locales frequently without touching catalogs each time. ✅ Simplicity matters more than compile-time guarantees on message IDs.
FAQ
Does Lingui support AI translation?
Not built in. You can pipe extracted catalogs through a machine translation API (Google Translate, DeepL, or an LLM), but you'd build and maintain that pipeline yourself. Some TMS platforms (Crowdin, Phrase) have Lingui integrations that include MT.
Is i18n-keyless as type-safe as Lingui?
No. Lingui's macros produce typed message descriptors — a missing or mistyped key is a compile error. i18n-keyless uses source strings as keys, so a typo creates a new translation rather than a build failure. The trade-off: less compile-time safety, more code readability.
What about ICU MessageFormat?
i18n-keyless covers all CLDR plural forms: pass count (or select for gender) with one source form, and the model produces every branch each language needs, validated against Intl.PluralRules before they're saved — see the plurals and genders guide. The difference is authorship: with Lingui you write the branches yourself; with i18n-keyless the model writes them and you edit in the dashboard when you disagree.
Can I use both together?
Yes — keep Lingui for existing screens, use i18n-keyless for new features. The libraries don't conflict. Over time, you can replace <Trans> wrappers with <I18nKeylessText> and drop the extraction pipeline.
Next steps
- Compare i18next too: i18n-keyless vs i18next.
- See vs react-intl: i18n-keyless vs react-intl.
- Try keyless: Quick setup guide — 5 minutes.
- Read the philosophy: The complete guide to keyless i18n.