Types
AVAILABLE_LANGS
const: readonly ["ar", "bn", "ca", "zh-Hans", "zh-Hant", "hr", "cs", "da", "nl", "en", "en-GB", "fi", "fr", "fr-CA", "de", "el", "gu", "he", "hi", "hu", "id", "it", "ja", "kn", "ko", "ms", "ml", "mr", "no", "or", "pl", "pt", "pt-BR", "pa", "ro", "ru", "sk", "sl", "es", "es-MX", "sv", "ta", "te", "th", "tr", "uk", "ur", "vi"]
A runtime constant listing every language code i18n-keyless can translate to — 48 of them since v3. Unlike the Lang type (which only exists at compile time), AVAILABLE_LANGS is a real array you can iterate over, spread into your supported config, or use for validation.
It is exported from both SDKs:
import { AVAILABLE_LANGS, type Lang } from 'i18n-keyless-react';
// or
import { AVAILABLE_LANGS, type Lang } from 'i18n-keyless-node';
The Lang type is derived from this constant: type Lang = (typeof AVAILABLE_LANGS)[number].
// Support every language i18n-keyless offers, no hardcoding
I18nKeyless.init({
API_KEY: 'YOUR_API_KEY',
storage: window.localStorage,
languages: {
primary: 'fr',
supported: [...AVAILABLE_LANGS],
},
});
// Type-safe runtime check
const isSupportedLang = (lang: string): lang is Lang =>
(AVAILABLE_LANGS as readonly string[]).includes(lang);
cn is now zh-Hans and cz is now cs. See Upgrading to v3.
Why some languages carry a region and most do not
The list is the 50 App Store localizations collapsed onto bare language codes. A bare designator matches every region of that language, so fr covers fr-FR, fr-CA, fr-BE and fr-CH at once. A region is added only where the translation genuinely differs:
| Code | Why it is separate |
|---|---|
zh-Hans / zh-Hant | A script, not a region. Simplified and Traditional are not mutually readable, so there is no bare zh. |
pt-BR | Brazilian vocabulary differs in ordinary UI words (usuário/utilizador, arquivo/ficheiro, tela/ecrã). |
es-MX | Latin American Spanish (computadora/ordenador, celular/móvil). |
fr-CA | Québec French. |
en-GB | British spelling. |
Everything else stays bare. You are billed per language you opt into, so ["pt", "pt-BR"] is two translations and ["pt"] is one. Reach for a variant only when you want that second, distinct translation.
PrimaryLang
type: Lang
The language you write your application in. Since v3 this is any of the 48 languages — it was limited to "fr" | "en" up to v2.
Lang
type: "ar" | "bn" | "ca" | "zh-Hans" | "zh-Hant" | "hr" | "cs" | "da" | "nl" | "en" | "en-GB" | "fi" | "fr" | "fr-CA" | "de" | "el" | "gu" | "he" | "hi" | "hu" | "id" | "it" | "ja" | "kn" | "ko" | "ms" | "ml" | "mr" | "no" | "or" | "pl" | "pt" | "pt-BR" | "pa" | "ro" | "ru" | "sk" | "sl" | "es" | "es-MX" | "sv" | "ta" | "te" | "th" | "tr" | "uk" | "ur" | "vi"
Every language available for translation.
Derived from AVAILABLE_LANGS — type Lang = (typeof AVAILABLE_LANGS)[number]. If you need the list at runtime (e.g. to populate a <select> or validate input), import AVAILABLE_LANGS instead of writing the array by hand.
resolveLang
function: (tag: string | null | undefined, options?: { supported?: readonly Lang[]; fallback?: Lang }) => Lang | undefined
Resolves any BCP-47 locale tag — navigator.language, Localization.getLocales()[0].languageTag, an Accept-Language entry, an App Store shortcode — onto a supported Lang, most specific match first.
import { resolveLang } from 'i18n-keyless-core';
resolveLang('pt-BR'); // "pt-BR" — exact variant
resolveLang('pt-AO'); // "pt" — no Angolan variant, fall back to the bare language
resolveLang('fr-CH'); // "fr"
resolveLang('zh-TW'); // "zh-Hant"
resolveLang('zh_CN'); // "zh-Hans" — underscores are accepted
resolveLang('es-419'); // "es-MX" — Latin America
resolveLang('xx'); // undefined
Pass supported to only ever get a language you actually ship. The walk continues to the next candidate when a more specific one is not in the list, so a pt-BR device on an app that only ships pt gets pt:
resolveLang('pt-BR', { supported: ['pt', 'en'], fallback: 'en' }); // "pt"
resolveLang('ja', { supported: ['pt', 'en'], fallback: 'en' }); // "en"
toAppStoreLocale and APP_STORE_LOCALES
function: (lang: Lang) => stringconst: Record<Lang, string>
The App Store Connect listing slot for a Lang, to push localized metadata, screenshots or release notes to the right place. Apple qualifies some languages with a region even when there is a single variant (de-DE, nl-NL, ar-SA, fr-FR) and leaves others bare (it, ja, pl); this map absorbs that asymmetry.
import { toAppStoreLocale } from 'i18n-keyless-core';
toAppStoreLocale('fr'); // "fr-FR"
toAppStoreLocale('pt'); // "pt-PT"
Apple's en-AU, en-CA and pt-PT slots have no dedicated Lang: fill them from en and pt, or opt into en-GB / pt-BR for a distinct translation.
resolveLang, toAppStoreLocale and APP_STORE_LOCALES are exported from i18n-keyless-core, which both SDKs depend on. Import them from there:
import { resolveLang } from 'i18n-keyless-core';
Translations
type: Record<string, string>
The translations for a key, represented as a key-value mapping where each key is the original text and each value is its translation. Example: { "un text": "a text" }.
LastRefresh
type: string | null
Timestamp indicating when the translations were last refreshed. Can be null if no refresh has occurred yet.
UniqueId
type: string | null
A unique identifier for tracking purposes. Can be null if no identifier has been assigned.
LanguagesConfig
type: object
Configuration object for language settings with the following properties:
primary: The language you write your app in (PrimaryLang — anyLangsince v3)supported: Array of languages supported for users (Lang[])fallback: Optional fallback language when user's language is not supported (Lang)initWithDefault: Optional language to use when the app is initialized (Lang)
TranslationOptions
type: object
Options for customizing translation behavior with the following properties:
context: Optional context for disambiguation of ambiguous translations (e.g., "8 heures" could mean "8 AM" or "8 hours")debug: Optional boolean for debugging specific translation keysforceTemporary: Optional partial record to override AI translations with custom onesreplace: Optional record for replacing placeholders in text with values (e.g.,{ "{{name}}": "John" })