# i18n-keyless > Ultimate DX for i18n. A keyless internationalization SaaS: write strings in your source language, get AI-powered translations at runtime — no JSON files, no translation keys, no manual upkeep. i18n-keyless lets you ship multi-language apps without managing translation keys or files. You write text in your primary language (French or English), wrap it in a component or call, and the SDK fetches AI-generated translations on the fly, caches them locally, and lets you override them from a dashboard or directly in code. Official SDKs: React, React Native (`i18n-keyless-react`), and Node.js (`i18n-keyless-node`). This file is a single-page Markdown summary of the documentation, intended to be pasted into an LLM context window so the assistant has full coverage of the API surface and conventions. ## Core concepts - **Keyless**: the source string itself is the translation key — no IDs to manage. - **Primary language**: `fr` or `en` only. This is the language you write your code in. - **Supported target languages**: `fr`, `en`, `nl`, `it`, `de`, `es`, `pl`, `pt`, `ro`, `hu`, `sv`, `tr`, `ja`, `cn`, `cz`, `ru`, `ko`, `ar`. Also exported as the runtime const `AVAILABLE_LANGS` from `i18n-keyless-react` and `i18n-keyless-node` (see Type reference below). - **Storage** (React / React Native only): required, used to cache translations locally. Must implement `getItem`, `setItem`, `removeItem` (sync or async). - **AI translations**: on cache miss, the server generates a translation with Mistral, stores it server-side and pushes it to the client cache. - **Overrides**: edit a translation in the dashboard at https://i18n-keyless.com/dashboard, or use `forceTemporary` from code. - **API key**: get one at https://i18n-keyless.com/#get-api-key. ## Installation ### React (web) ```bash npm install i18n-keyless-react ``` Initialize once in `main.tsx` / `index.tsx` before rendering the app: ```ts import * as I18nKeyless from "i18n-keyless-react"; I18nKeyless.init({ API_KEY: "YOUR_API_KEY", storage: window.localStorage, // or any get/set/del-compatible adapter languages: { primary: "fr", // "fr" | "en" supported: ["en", "fr"], fallback: "en", // optional initWithDefault: "fr", // optional }, }); ``` For IndexedDB, wrap `idb-keyval` in a `{ getItem, setItem, removeItem }` adapter. ### React Native ```bash npx expo install i18n-keyless-react react-native-mmkv npx expo prebuild ``` ```ts import * as I18nKeyless from "i18n-keyless-react"; import { MMKV } from "react-native-mmkv"; I18nKeyless.init({ API_KEY: "YOUR_API_KEY", storage: new MMKV(), languages: { primary: "fr", supported: ["en", "fr"] }, }); ``` `AsyncStorage` (`@react-native-async-storage/async-storage`) is also supported. ### Node.js ```bash npm install i18n-keyless-node ``` ```ts import * as I18nKeyless from "i18n-keyless-node"; I18nKeyless.init({ API_KEY: "YOUR_API_KEY", languages: { primary: "fr", supported: ["en", "fr"] }, }); ``` No storage parameter on Node. ## React / React Native API (`i18n-keyless-react`) ### `I18nKeylessText` — translation component Use it inline to wrap any text. The text content is also the translation key. ```tsx import { I18nKeylessText } from "i18n-keyless-react";

Bonjour le monde

``` Props: - `children: ReactNode` — the source text. - `context?: string` — disambiguation hint (e.g. `"This is a back button"`). - `replace?: Record` — placeholder substitution (e.g. `{ "{name}": user.name }`). - `forceTemporary?: Record` — override per language, e.g. `{ en: "Back" }`. - `debug?: boolean` — log internals for this call. ### `getTranslation(text, options?)` — string-returning hook Use when you need a translated string in a prop (placeholder, `aria-label`, tab label, etc.) instead of as JSX. ```tsx import { getTranslation } from "i18n-keyless-react"; ``` Same options as `I18nKeylessText`. Returns `string`. Must be called inside a React component (it's a hook). ### `useCurrentLanguage()` — current language hook Returns `Lang | null` (null until set). ```ts const current = useCurrentLanguage(); // "fr" | "en" | ... | null ``` ### `setCurrentLanguage(lang)` — switch language ```ts import { setCurrentLanguage } from "i18n-keyless-react"; setCurrentLanguage("es"); ``` Triggers re-render of all consumers. Can be called from anywhere (not a hook). ### `getSupportedLanguages()` — configured languages Returns the `Lang[]` you passed to `init`. Useful for building a language selector. ### `useI18nKeyless(selector)` — Zustand store accessor Low-level access to the store. Common selectors: ```ts const primary = useI18nKeyless((s) => s.config.languages.primary); const supported = useI18nKeyless((s) => s.config.languages.supported); const lastRefresh = useI18nKeyless((s) => s.lastRefresh); // for forcing re-renders ``` ## Node.js API (`i18n-keyless-node`) ### `awaitForTranslation(text, language, options?)` Returns a `Promise`. **Must be awaited** — calling without `await` will trigger 429 rate limit errors. ```ts import { awaitForTranslation, type Lang } from "i18n-keyless-node"; const title = await awaitForTranslation("Viens voir l'application", user.lang as Lang); const body = await awaitForTranslation( "Bonjour {name} !", user.lang as Lang, { replace: { "{name}": user.name }, context: "push notification" } ); ``` Options: - `context?: string` - `replace?: Record` - `forceTemporary?: string` — note: a single string here, not a record (target language is already known). - `debug?: boolean` ### `getSupportedLanguages()` Same as in the React SDK. ## Common patterns ### Disambiguate ambiguous words ```tsx Retour Proche ``` ### Replace dynamic values Any pattern can be a placeholder: `{name}`, `{{name}}`, `[name]`, `%name%`, ``, plain `name`, `{user_name}`, etc. ```tsx Hello {name} ! ``` ### Force a translation from code When the AI gets it wrong and you can't (or won't) fix it from the dashboard: ```tsx Retour ``` ### Build a language selector ```tsx import { useCurrentLanguage, setCurrentLanguage, useI18nKeyless } from "i18n-keyless-react"; const current = useCurrentLanguage(); const primary = useI18nKeyless((s) => s.config.languages.primary); ``` ### Translate Markdown `i18n-keyless` only translates strings, so use Markdown for inline styling. With `react-markdown`, force re-render with `lastRefresh`: ```tsx import { useI18nKeyless, getTranslation } from "i18n-keyless-react"; import ReactMarkdown from "react-markdown"; const lastRefresh = useI18nKeyless((s) => s.lastRefresh); {getTranslation(children)} ``` ### Wrap in a `MyText` component Recommended in React Native (for fonts/styles) and useful in React too. Forward `context`, `replace`, `forceTemporary`, `debug` through an `i18nProps` prop, and add a `skipTranslation` escape hatch for already-translated content. ### Debug a single call ```tsx Hello world getTranslation("Hello world", { debug: true }); await awaitForTranslation("Hello world", "fr", { debug: true }); ``` ## Type reference ```ts // Importable runtime const — exported from i18n-keyless-react and i18n-keyless-node // (re-exported from i18n-keyless-core). Use it to support every available language // without hardcoding the list, or to build language selectors / validation. const AVAILABLE_LANGS = [ "fr", "en", "nl", "it", "de", "es", "pl", "pt", "ro", "hu", "sv", "tr", "ja", "cn", "cz", "ru", "ko", "ar", ] as const; type Lang = (typeof AVAILABLE_LANGS)[number]; // "fr" | "en" | "nl" | "it" | "de" | "es" | "pl" | "pt" | "ro" // | "hu" | "sv" | "tr" | "ja" | "cn" | "cz" | "ru" | "ko" | "ar" type PrimaryLang = "fr" | "en"; type LanguagesConfig = { primary: PrimaryLang; supported: Lang[]; fallback?: Lang; initWithDefault?: Lang; }; type TranslationOptions = { context?: string; debug?: boolean; forceTemporary?: Partial>; // Node: string replace?: Record; }; ``` ### Using `AVAILABLE_LANGS` ```ts import { AVAILABLE_LANGS } from "i18n-keyless-react"; // or "i18n-keyless-node" // Support every available language without hardcoding the list I18nKeyless.init({ API_KEY: "YOUR_API_KEY", storage: window.localStorage, languages: { primary: "fr", supported: [...AVAILABLE_LANGS], }, }); // Validate a user-provided language code at runtime const isLang = (l: string): l is Lang => (AVAILABLE_LANGS as readonly string[]).includes(l); ``` ## Gotchas - `awaitForTranslation` **must** be awaited. Fire-and-forget calls will hit rate limits. - `init` must run before any translation call; in React, do it in your entry file before rendering. - Storage adapter methods can be sync or async, but must all be present (`getItem`, `setItem`, `removeItem`). - The `primary` language can only be `fr` or `en`. Source strings must be written in that language. - Translations are cached on-device — if you change a translation in the dashboard, cached clients pick it up via the next refresh, not instantly. - For `react-markdown` (and similar memoized renderers), pass `key={lastRefresh}` so the tree re-renders when translations refresh. ## Resources - Website: https://i18n-keyless.com - Docs: https://i18n-keyless.com/docs/quick-setup - Dashboard: https://i18n-keyless.com/dashboard - Get an API key: https://i18n-keyless.com/#get-api-key - GitHub: https://github.com/arnaudambro/i18n-keyless