Skip to main content

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);
Two codes changed in v3

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:

CodeWhy it is separate
zh-Hans / zh-HantA script, not a region. Simplified and Traditional are not mutually readable, so there is no bare zh.
pt-BRBrazilian vocabulary differs in ordinary UI words (usuário/utilizador, arquivo/ficheiro, tela/ecrã).
es-MXLatin American Spanish (computadora/ordenador, celular/móvil).
fr-CAQuébec French.
en-GBBritish 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_LANGStype 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) => string const: 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.

note

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 — any Lang since 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 keys
  • forceTemporary: Optional partial record to override AI translations with custom ones
  • replace: Optional record for replacing placeholders in text with values (e.g., { "{{name}}": "John" })