Skip to documentation
DocumentationSDKs and frameworks

Kotlin Multiplatform

Set up the ReRune Kotlin Multiplatform SDK in shared Compose Multiplatform UI on Android, iOS and desktop, with the standard generated resources.

Documented SDK 1.0.0

Requirements: Kotlin 2.1.21+, Compose Multiplatform 1.8.2+, Android API 23+, iosArm64 and iosSimulatorArm64, desktop JVM

Package referenceExplore Kotlin Multiplatform localization
On this page

Add the dependency

Gradle Kotlin DSL · shared UI module

commonMain.dependencies {
  implementation("io.rerune:rerune-kmp-compose:1.0.0")
}

Add the dependency to the commonMain source set of the module that holds your shared Compose UI, and enable Maven Central. Keep your composeResources files and the generated Res accessors.

It needs Kotlin 2.1.21 or newer, Compose Multiplatform 1.8.2 or newer and Android API 23 or newer. iOS builds use the iosArm64 and iosSimulatorArm64 targets; desktop runs on the JVM.

Connect the shared UI

  1. Call ReRune.setup once at startup with the project's read-only OTA Publish ID.
  2. Replace stringResource, pluralStringResource, getString and getPluralString with reRuneStringResource, reRunePluralStringResource, reRuneGetString and reRuneGetPluralString. Each takes the same arguments.
  3. On Android, ReRune captures the application context automatically. If your app removes ReRune's provider from its manifest, call applicationContext.reRuneBind() before setup.

Kotlin · once at startup

ReRune.setup(otaPublishId = "<READ_ONLY_OTA_PUBLISH_ID>")

Kotlin · inside a composable

Text(reRuneStringResource(Res.string.greeting))
Text(reRuneStringResource(Res.string.welcome_user, userName))
Text(reRunePluralStringResource(Res.plurals.item_count, count, count))

val text = reRuneGetString(Res.string.greeting) // suspend, outside composition

A screen that still calls plain stringResource(...) compiles and shows bundled text only. Bundled resources also show before setup and whenever ReRune has no usable value.

Why the ReRune functions are needed: Compose Multiplatform offers no public way for a library to change the text that stringResource(...), pluralStringResource(...), getString(...) and getPluralString(...) return, so those calls always return the bundled text. The only alternatives rely on Compose internals or a Kotlin compiler plugin, which can break with a Compose or Kotlin update, and ReRune deliberately avoids them so such an update can't break your app or its text. Instead, ReRune ships counterparts that take the same arguments and the same generated Res values, and fall back to the bundled text whenever ReRune has no value. We have asked JetBrains for a public hook in CMP-11130, where you can vote for it. If one is added, a later SDK version can make plain calls work on the Compose versions that have it.

Updates, variants and staging

Composable call sites update on their own when new content arrives, with no wrapper needed. Outside composition, observe ReRune.revisionFlow.

Kotlin · runtime API

ReRune.checkForUpdates()
ReRune.setVariant(ReRuneVariant.fromSlug("vip"), persist = true)
ReRune.resetVariant()
ReRune.setStaging(true)
ReRune.availableLocalesFlow // dashboard languages for a picker
ReRune.revisionFlow // increments when text may change

ReRune.setup also accepts updatePolicy, cacheStore, requestTimeout, logLevel, variant and staging, with the same meaning as in the Android SDK.

With checkOnStart on, which is the default, ReRune checks for new text when the app starts and every time it returns to the foreground.

Every published language is downloaded and cached, so a language switch also works offline. Cached texts are kept out of device backups. A failure inside ReRune never reaches the app: lookups show the bundled text.

Which language a text comes from

Lookups use the locale Compose resources use (Locale.current). For each key, ReRune tries in this order:

  1. Dashboard text in the phone's language, closest region first: a de-AT phone uses de-AT, then de, then de-DE. Another script never counts, so zh-TW never shows Simplified Chinese.
  2. The app's own text, when the app declares the phone's language.
  3. Dashboard text in the project's main language.
  4. The app's own text.

Declare the languages your app ships: on Android 13 and later with an android:localeConfig resource, on iOS with CFBundleLocalizations in Info.plist. Without a declaration, ReRune assumes the app ships the phone's language and skips the main-language step.

ReRune.availableLocalesFlow lists the dashboard's languages with their names. Apply a choice with the platform's per-app language API, such as AppCompatDelegate.setApplicationLocales on Android, so Locale.current and ReRune follow it.

Verify delivery on each target

  1. Start with bundled resources and confirm the app renders without a network connection.
  2. Publish a changed value for an existing key and use the correct project OTA Publish ID.
  3. Bring the app back to the foreground or call ReRune.checkForUpdates(), and confirm visible screens show the new text.
  4. Restart offline after a successful update to check that cached texts load. Repeat on Android, iOS and desktop if you ship all three.