Skip to main content

i18n-keyless vs i18next: which to pick in 2026

· 9 min read
Founder of i18n-keyless

i18next is the de-facto standard for JavaScript i18n. It has been around since 2011, ships in tens of thousands of production apps, and has plugins for every framework you can name. So why would anyone build something different?

The short answer: i18next was designed for a workflow that most modern teams no longer have — translators receiving JSON files, glossaries, TMS pipelines, key management as a discipline. If your "localization team" is one engineer adding French because a customer just signed, the overhead doesn't pay off.

This is an honest comparison. We use i18n-keyless ourselves and we'll happily tell you when i18next is the better fit.

TL;DR​

i18n-keylessi18next
Setup time~5 minutes~1–2 days for a real config
Translation keysNone — source string is the keyRequired — you name every key
JSON locale filesNone — translations live in our backendYou maintain one per locale
AI translationBuilt inDIY via plugins or external service
Plurals, ordinals, gendercount / ordinal / select, forms written by the modelHand-authored ICU MessageFormat
Ecosystem / pluginsSmall (focused SDKs)Huge
Best forMVPs, indie SaaS, engineer-driven product copyMature apps, TMS workflows, content-heavy sites

Pick i18n-keyless if you want to ship multilingual today and you don't have a localization team. Pick i18next if you have an established TMS workflow, want to hand-author the ICU branches yourself, or your content team owns the locale files.

The fundamental difference: keys vs no keys​

Every i18next codebase has this pattern somewhere:

// 1. Define the key in en.json
{ "checkout": { "confirm": { "cta": "Confirm payment" } } }

// 2. Define the same key in fr.json
{ "checkout": { "confirm": { "cta": "Confirmer le paiement" } } }

// 3. Reference it in the component
import { useTranslation } from "react-i18next";
const { t } = useTranslation();
<button>{t("checkout.confirm.cta")}</button>

i18n-keyless skips the first two steps:

import { I18nKeylessText } from "i18n-keyless-react";
<button><I18nKeylessText>Confirm payment</I18nKeylessText></button>

That's it. The source string is the key. Translations are managed in our backend, generated automatically by AI on first encounter, cached forever, and overridable from the dashboard when you need nuance.

If you've never thought about the cost of key management, here's what it actually adds up to:

  • Naming the key — every string needs a unique, hierarchical name. Teams disagree on conventions. Refactors break references.
  • Keeping locale files in sync — delete a key in en.json, forget to delete in fr.json, ship a stale string. Add a key in one locale, forget the others, ship a [hero.title] placeholder.
  • Code review overhead — reviewers can't tell what t("checkout.confirm.cta") says without opening the locale file.
  • Onboarding cost — every new engineer learns "where do I add this string?" instead of just writing it.

Across a year, on a team of 5, this is hundreds of hours.

Setup comparison​

i18next setup (typical React app)​

npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend
// i18n.js
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import HttpBackend from "i18next-http-backend";

i18n
.use(HttpBackend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: "en",
debug: false,
interpolation: { escapeValue: false },
backend: { loadPath: "/locales/{{lng}}/{{ns}}.json" },
ns: ["common", "checkout", "marketing"],
defaultNS: "common",
});

Then create public/locales/en/common.json, public/locales/fr/common.json, etc. Repeat per namespace, per locale. Wire up your bundler to serve them. Pick a key naming convention. Document it. Add a contributing guide.

i18n-keyless setup​

npm install i18n-keyless-react
import * as I18nKeyless from "i18n-keyless-react";

I18nKeyless.init({
API_KEY: "YOUR_API_KEY",
storage: window.localStorage,
languages: { primary: "en", supported: ["en", "fr", "de", "es"] },
});

That's the entire setup. Start writing <I18nKeylessText> in your JSX. See the quick-setup guide for the full walkthrough.

Where i18next genuinely wins​

We're not going to pretend i18next has no advantages. It absolutely does:

Pluralization​

i18next handles pluralization with per-key suffixes:

t("itemCount", { count: 0 });   // "No items"
t("itemCount", { count: 1 }); // "1 item"
t("itemCount", { count: 12 }); // "12 items"

With CLDR plural rules per locale (Polish has 4 plural forms, Arabic has 6). i18n-keyless covers the same CLDR rules: pass count and one source form ({count} items), and the model produces every CLDR plural branch for every language, validated against Intl.PluralRules before they're saved (see the plurals and genders guide). The difference is who writes the branches — with i18next, you do; with i18n-keyless, the model does and you can still edit any branch by hand from the dashboard. Zero-specific display text ("Your cart is empty" instead of "0 items") is a conditional in the component — it's display logic, not a plural rule.

Massive ecosystem​

i18next has plugins for: every framework (Vue, Svelte, Angular, Next.js, Nuxt), every backend (HTTP, filesystem, MongoDB), every TMS (Lokalise, Crowdin, Phrase, Locize). If your stack is unusual, there's probably an i18next plugin for it.

Battle-tested at scale​

Notion, Decathlon, KLM, and many others run i18next in production. The library has handled every edge case you'll ever hit.

Static analysis​

Tools like i18next-parser extract keys from your code, detect missing translations at build time, and integrate with TMS tools. Keyless removes the bug class but also removes the static-analysis surface.

Where i18n-keyless wins​

Time-to-multilingual​

Realistically, going from zero to "my app speaks 4 languages" with i18next + a translation pass is a 1–3 week project. With i18n-keyless it's a 1-day project — install, wrap strings, ship.

Code readability​

You read the source strings directly in the JSX. Nothing to context-switch to. New engineers are productive on day one without learning your key naming convention.

Zero key-management bugs​

There are no keys, so there are no missing keys, no stale keys, no typo'd keys, and no namespacing arguments at standup.

Free locales by default​

When you add a new locale (say, Italian), every existing string is auto-translated in the background. With i18next, adding a locale is a translation project — every key in every namespace needs a value.

One source of truth​

Translations live in our backend. No JSON files in your repo. No "which branch has the right copy?" merge conflicts. Manual overrides are versioned in the dashboard.

When to choose i18next​

✅ You have a localization team using a TMS (Lokalise, Crowdin, Phrase). ✅ You want every plural branch in a JSON file you control. ✅ Your app already uses i18next and the migration cost outweighs the benefit. ✅ You're targeting 30+ locales with strict glossary consistency. ✅ Translation files must live in your repo for compliance/audit reasons.

When to choose i18n-keyless​

✅ You're an early-stage product, indie SaaS, or MVP. ✅ Engineers write the source copy directly in the JSX. ✅ You want to add languages frequently without project planning each time. ✅ You don't have (or don't want) a translator in the loop for every string. ✅ Your team is small and translation is infrastructure, not a workflow.

A real cost example​

Consider a 500-string app launching English + French + German + Spanish.

With i18next:

  • 500 keys × 3 target locales = 1,500 translations to commission and review.
  • At 30 seconds per string for a translator (optimistic), that's ~12 hours of human translation.
  • Plus engineer time: 4–8 hours of setup, key naming, and locale file wiring.
  • Plus ongoing maintenance: every new string needs to be translated 3 times.

With i18n-keyless:

  • 500 strings × 3 target locales auto-translated in minutes.
  • Engineer time: ~30 minutes setup + wrapping strings.
  • Ongoing: new strings translate themselves; you review only the ones that matter.

This is why for early-stage teams, i18n-keyless dominates on time-to-ship.

Migration​

If you're already on i18next and considering the switch, there's a clean dual-run migration path: keep i18next handling existing keys, use i18n-keyless for new strings, then sweep through and replace t() calls with <I18nKeylessText> over a sprint or two.

We have a step-by-step guide: Migrate from i18next to i18n-keyless.

FAQ​

Can I use i18next and i18n-keyless together?​

Yes — many teams dual-run during migration. Keyless handles new strings, i18next continues serving existing keys. There's no conflict between them.

Does i18n-keyless support React Server Components?​

Yes — use the Node.js SDK with awaitForTranslationOrFallbackToOriginal for server-side rendering paths.

What about pluralization?​

i18n-keyless writes the CLDR forms for you: pass count and one source form, and the model generates the branches each language needs (French 2, Russian 4, Arabic 6), validated against Intl.PluralRules. You still write ICU by hand with i18next; the trade-off is who writes the branches, not whether plurals are correct.

Is i18next going away?​

Not at all — i18next will continue to be the right tool for many teams (especially those with TMS workflows). Different products solve different shapes of problem.

How much does i18n-keyless cost?​

Free tier covers most early-stage usage. Paid plans scale with translation volume. See the homepage for current pricing.

Next steps​