Self-hosted

Painless i18n, expanded to your own horizons without spending thousands of dollars.

Free to install. One project free, forever. No licence key needed.
A €30 lifetime licence unlocks unlimited projects. No subscription, no usage cap, no expiry.

Free
€0forever

One project. No licence key. No expiry.

  • All 48 languages, unlimited translations
  • The dashboard, the MCP server, every SDK
  • Nothing to buy, nothing to enter but your AI key
Install it free
Lifetime licence
30once, for life

Unlimited projects. Needed from the second one.

  • Everything in Free, for as many projects as you like
  • No subscription, no usage cap, no expiry
  • Paste the key on the same Settings screen, whenever you need it

Secure payment by Stripe. The licence key lands in your inbox and on the next page.

What you get

  • Free without the licence: one project, all 48 languages, no expiry
  • With the licence: unlimited projects, unlimited translations
  • The dashboard, the MCP server for your agents, every SDK
  • One container, one SQLite file to back up
  • A licence checked offline: your server never calls home
  • Every update, for life: docker compose pull

What you bring

  • A machine with Docker: a €4 VPS is plenty
  • An AI API key (Mistral, OpenAI, Anthropic, Google or any OpenAI-compatible provider). Translations run on your own account, for a few cents per app
  • Five minutes

Support is by email, best effort. Need someone on call? The hosted plans are for you.

How it runs

No licence key to get started: install, create the admin, paste your AI key. Your first project runs free for as long as you like.

With ONCE — a fresh server, a domain, five minutes

curl -fsSL https://get.once.com | sh
once   # add an app: ghcr.io/ambroselli-io/i18n-keyless:latest, pick a host name
# then open it: create the admin, paste your AI key on Settings — no licence needed
# add the licence on the same screen when you need a second project
# ONCE does the domain, the TLS, the updates and the backups

With docker compose — any machine that runs Docker

mkdir i18n-keyless && cd i18n-keyless
curl -fsSL https://i18n-keyless.com/self-hosted/docker-compose.yml -o docker-compose.yml
docker compose up -d
# → http://localhost:1800: create the admin, paste your AI key on Settings
# add the licence on the same screen when you need a second project

Then point your SDK at your server:

I18nKeyless.init({
  API_KEY: "your-project-key",
  API_URL: "https://i18n.example.com",
  // …
});

The full guide: https://docs.i18n-keyless.com/docs/guides/self-hosting

Why a lifetime licence?

Because you pay for the software once, and you handle the VPS and the AI API key yourself. There is no reason I would charge you for a subscription. Also : I hate subscriptions myself.

And because you should try it before you pay: the image installs free and runs one project forever, with every language and no expiry. Buy the licence the day you need a second one.

Questions before you buy? Write to us

Setup i18n, keep your codebase clean and ship fast

Multiple PITA exist with the current i18n solutions. Pains are so big that you delay i18n as much as possible.

It consumes time you should spend on the beach

Setup the keys' system: at least 1 hour of senior dev time

Back and forth for each new key: 1 minute per key, x500 keys, x2 languages = 17 hours

With i18n-keyless, you don't care about the i18n system at all. You can go on the beach and order a mojito.

Today most of the systems use keys to translate the text

This is painful to generate. This is painful to maintain.

When you see a text in the app, and you want to update it, you need to find the corresponding key.

With i18n-keyless, you don't care about the i18n system at all. Use your brain for something more interesting.

Leave translations to AI

With the key system, you need to manage the translations in the app.

Otherwise your users will see someheader.welcome.title in their app.

With i18n-keyless, you don't care about the i18n system at all. Just write good headlines, focus on marketing, get sales.

Codebases are beautiful... until i18n keys' infection

With the key system, when you read the code and the content, you have to read keys, not natural language.

Sometimes you should make a fix because a sentence is not grammatically correct. But you don't know that because you read keys.

With i18n-keyless, you don't care about the i18n system at all. Codebase stays beautiful.

Add i18n from day one without any impact on your development pace
Built for coding agents

MCP server to cover all your i18n needs

Plus six other reasons why the system is so optimized for agentic coding.

No name to invent

A key is a naming decision with no right answer. Two agents write login.submit and auth.button.send for the same button. Without keys there is no decision to make.

One file to edit, not twenty

A keyed change touches the component plus every locale JSON, and agents forget files. Here a copy change is a single-file edit.

Zero merge conflicts in agent fleets

Five agents on five branches all edit en.json: a guaranteed conflict. There is no shared file, so worktrees and background agents never collide.

Cheap in tokens

To reuse a key, an agent must load the locale files into context on every edit. Keyless loads nothing: the text is right there in the component.

Readable diffs

The pull request shows real sentences. A human or a review agent can judge the copy without digging for what a key stands for.

One rule in your CLAUDE.md

Every i18n rule you write is a rule the agent can break. This one needs a single line — and the fallback is the real text, so a miss cannot show a.b.c on screen.

The only i18n rule your agent needs

# CLAUDE.md
Write the UI copy in English and wrap it in <T>…</T> from i18n-keyless-react.
That is the whole i18n setup.

Your agent can operate it, not only write it

Through the MCP server, the agent lists missing translations, reads one, overrides a bad one, or imports the copy you already have — with its own OAuth login, no key to paste.

Read the MCP guide
Perfect for MVPs

Launch globally from day one

Stop delaying i18n because of complexity. Implement in 5 minutes, not days. Maintain your development velocity as if i18n wasn't implemented.

  • 5-minute implementation. Not kidding.

    One simple config object and you're done.

  • Maintain development velocity

    Code as if i18n wasn't implemented at all.

  • Ship to global markets

    No refactoring needed as you scale to new languages.

  • SSR & SEO ready

    Works with Next.js, Remix, TanStack Start and Astro. Server-render any language for search engines — same 5-minute setup.

Traditional i18n

Setup keys system (1 hour)
Create translation files (2 hours)
Refactor components (4 hours)
Test all languages (2 hours)
Fix layout issues (3 hours)
12+ hours of work

i18n-keyless

Add package (1 min)
Configure with API key (2 min)
Wrap text components (2 min)
5 minutes of work
How It Works

It's no brainer to setup

Just the simplest config object and you're ready to go global.
And even more, your agent will set it up for you.

1. Basic Setup

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

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

2. Component Usage (React here; the same in Vue, Angular, Flutter, Swift and Kotlin)

import { I18nKeylessText } from "i18n-keyless-react";
// import { T } from "i18n-keyless-react"; // also works

// Just write in your primary language
<I18nKeylessText>
  Welcome to our website
</I18nKeylessText>

3. Server-side Usage (Node.js here; the same call in Laravel, Rails, Python and Go)

import { awaitForTranslationOrFallbackToOriginal, type Lang } from 'i18n-keyless-node';

const title = await awaitForTranslationOrFallbackToOriginal('Come see my app!', user.lang as Lang);
const body = await awaitForTranslationOrFallbackToOriginal('So many new stuff!', user.lang as Lang);

await sendExpoPushNotification({ user, title, body });

4. For text outside components

import { getTranslation } from "i18n-keyless-react";

export default function Navigation() {
  return (
    <HomeTabs.Navigator>
      <HomeTabs.Screen
        options={{ tabBarLabel: getTranslation("Welcome") }}
        name="WELCOME"
      />
    </HomeTabs.Navigator>
  );
}

5. Pick your SDK: one install line, the same API everywhere

  • React, React Native, Expo, Next.js, Remix, TanStack Start, Astronpm install i18n-keyless-react
  • Vue, Nuxtnpm install i18n-keyless-vue
  • Angularnpm install i18n-keyless-angular
  • Plain HTML, Svelte, Alpine, htmx, one script tagnpm install i18n-keyless-browser
  • Node.jsnpm install i18n-keyless-node
  • Laravel, PHPcomposer require i18n-keyless/laravel
  • Rails, Rubybundle add i18n-keyless-rails
  • Flutter, Dartflutter pub add i18n_keyless
  • Swift, iOS, macOS, VaporSwiftPM: arnaudambro/i18n-keyless-swift
  • Kotlin, Android, Ktorio.github.arnaudambro:i18n-keyless-kotlin
  • Python, Django, Flask, FastAPIpip install i18n-keyless
  • Gogo get github.com/arnaudambro/i18n-keyless/ports/go/v3

Quick setup for each of the twelve SDKs

How translations work

i18n-keyless is a library, combined with an API service, that allows you to translate your text without the need to use keys.

If the translation is not found, there will be an asynchronous fetch to I18nKeyless' API to get the translation by an AI API call.

This operation is made usually in dev mode, while you're coding. If you missed one, in production only the first user missing the translation will see a glitch, then it'll be available instantly to users all over the globe.

App Store & Google Play

Your store listing in every language, on every release

Every update means new release notes, a description and keywords — for each language, on both stores. That is what stops you from adding languages. Not the app.

  • Release notes for every language, in one call

    Write the update once. awaitForTranslation returns it in each language you sell in, and your store config feeds it to EAS or fastlane.

  • 48 languages, mapped to the App Store slots

    pt-BR and pt-PT are two listings; en-GB, en-AU and en-CA are three. toAppStoreLocale puts each translation in the right one.

  • Fix a bad translation without a release

    In the app, one override in the dashboard is live at once — no hotfix build, no store review. In the listing, re-run the push.

  • Not priced per word

    A translator charges about €0.10 a word. 2,000 strings times 10 languages is a budget a solo developer does not have. Here words are not counted.

The whole recipe for an Expo app

// store.config.js — EAS Metadata awaits an async config
const { init, awaitForTranslation, toAppStoreLocale } = require("i18n-keyless-node");

const LANGS = ["en", "fr", "de", "ja", "pt-BR"];
const DESCRIPTION = "Bibi translates your app while you sleep…";

module.exports = async () => {
  init({ API_KEY: process.env.I18N_KEYLESS_KEY, languages: { primary: "en", supported: LANGS } });
  const info = {};
  for (const lang of LANGS) {
    info[toAppStoreLocale(lang)] = {
      title: await awaitForTranslation("Bibi", lang, { context: "App Store app name, 30 characters max" }),
      subtitle: await awaitForTranslation("Keyless i18n", lang, { context: "App Store subtitle, 30 characters max" }),
      description: await awaitForTranslation(DESCRIPTION, lang, { context: "App Store description" }),
    };
  }
  return { configVersion: 0, apple: { info } };
};

The same call writes fastlane metadata files for Google Play. Caps are advisory: put the limit in the context and check the length before you push.

Try It Yourself

Interactive Sandbox

See how i18n-keyless works in real-time

Open a live, editable StackBlitz project to see translations resolve as you type.

Why I built this

"I always postponed i18n until my client wanted it so much that I had no choice. I hate reading the code with i18n keys inside, and I hate maintaining JSON files as much as seeing how expensive are i18n translations providers. So I had to build mine, and I FREAKING LOVE IT. All my apps are i18n by default now."

AA

Arnaud Ambroselli

Founder of i18n-keyless

Want to add yours?

A testimony against a free subscription. Request yours!

Send my testimony
Before you ask

Frequently asked questions

Do I need to manage translation files?

No. There are no JSON files, no key extraction step, and no build-time plugin. You write your sentences in your source language, the SDK sends them to the API on the first request, the API translates them with AI, and every subsequent request is served from the cache. Your code is the single source of truth.

What happens when I change the source text?

The source text is the key. Change it and you get a new key with a fresh AI translation. The old key simply stops being requested, and the dashboard cleans it up after 30 days without use. A typo fix is the same: fix it in the code, deploy, and the new text is translated on the first request.

How much does it cost?

Hosted: one flat price per project per month, by monthly active users — €4 up to 1,000, €9 up to 5,000, €29 up to 50,000, €99 up to 500,000 — billed monthly, cancel any time. Self-hosted: free to install, one project free forever, €30 once for unlimited projects, no subscription and no usage cap. There is no per-seat, per-word, or per-string pricing on either.

Can I export my translations?

Yes. The dashboard has an "Export JSON" button that downloads every translation in your project as a single JSON file. The export includes all rows, not just the ones used in the last 30 days, so it is a full backup. There is no lock-in: your data is always one click away.

Try It Yourself

Watch the Demo

Watch this short video to see i18n-keyless in action