Skip to main content

Jetpack Compose Realtime Preview

The Crowdin Android SDK provides seamless integration with Jetpack Compose, enabling real-time updates for your application's UI strings without the need to restart the activity or the application.

Configuration

To enable Jetpack Compose support, you need to configure the CrowdinConfig in your Application class.

import com.crowdin.platform.Crowdin
import com.crowdin.platform.CrowdinConfig

Crowdin.init(
application,
CrowdinConfig.Builder()
.withDistributionHash("your_distribution_hash")
.withRealTimeUpdates()
.withRealTimeComposeEnabled(true) // Enable Real-time Compose support
.build()
)
info

The withRealTimeComposeEnabled(true) flag is required to activate the Compose-specific repositories and watchers.

Required Dependencies

Both withRealTimeUpdates() and withRealTimeComposeEnabled(true) are required for real-time Compose support to work properly:

  • withRealTimeUpdates() - Establishes the WebSocket connection for receiving translation updates from Crowdin
  • withRealTimeComposeEnabled(true) - Enables the Compose-specific integration layer to propagate updates to your UI

If you enable withRealTimeComposeEnabled(true) without withRealTimeUpdates(), the SDK will throw a configuration error at initialization, as the Compose support needs the WebSocket connection to function.

Android API Level Requirements

Real-time Compose support requires Android API level 24 (Android 7.0) or higher. This is because the implementation uses ConcurrentHashMap.computeIfAbsent() and Map.putIfAbsent() methods which are only available from API 24+.

On devices running API 21-23:

  • The SDK will automatically detect the incompatible API level
  • Real-time Compose updates will be gracefully disabled
  • A warning will be logged to help with debugging
  • Your Compose UI will continue to work normally with static translations
  • All other SDK features remain fully functional

Recommendation: If you need to support API 21-23 devices, consider implementing a runtime check to conditionally enable real-time Compose support:

val enableRealtimeCompose = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N

CrowdinConfig.Builder()
.withDistributionHash("your_hash")
.withRealTimeUpdates()
.withRealTimeComposeEnabled(enableRealtimeCompose)
.build()

Usage

There are two ways to use Crowdin with Jetpack Compose: manually using the crowdinString / crowdinPluralString composables or automatically using the Crowdin Gradle plugin.

Manual Usage

You can use the crowdinString and crowdinPluralString composables to retrieve localized strings that automatically update when translations change.

import com.crowdin.platform.compose.crowdinString
import com.crowdin.platform.compose.crowdinPluralString

@Composable
fun WelcomeScreen() {
// Basic usage
Text(text = crowdinString(R.string.welcome_message))

// Usage with arguments
Text(text = crowdinString(R.string.welcome_user, "User"))

// Plural usage
Text(text = crowdinPluralString(R.plurals.task_count, 3, 3))
}

Automatic Usage (Gradle Plugin)

For a more seamless experience, you can use the Crowdin Gradle plugin. This plugin automatically transforms your stringResource calls into crowdinString calls and your pluralStringResource calls into crowdinPluralString calls at compile time, allowing you to use the standard Compose API while getting the benefits of Crowdin's real-time updates.

Setup

Add the Crowdin Gradle plugin to your module-level build.gradle.kts file.

Critical Plugin Ordering

It is mandatory to apply the com.crowdin.platform.gradle plugin before the Compose (org.jetbrains.kotlin.plugin.compose) plugin. This ordering is required because the Crowdin plugin needs to transform the intermediate representation (IR) of your Compose code before the Compose compiler processes it. If the Crowdin plugin is applied after Compose, it will not be able to intercept and modify the IR, and real-time string updates will not work as intended.

build.gradle.kts
plugins {
// 1. Crowdin plugin MUST be applied first
id("com.crowdin.platform.gradle")

// 2. Android and other plugins follow
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
}

The plugin handles the rest automatically. You can continue writing standard Compose code:

@Composable
fun Greeting() {
// This will be automatically transformed to use Crowdin's real-time updates
Text(text = stringResource(R.string.hello_world))

// Plural resources are transformed as well
Text(text = pluralStringResource(R.plurals.task_count, 3, 3))
}

See also