Skip to content

Conversation

@leo-benz
Copy link

@leo-benz leo-benz commented Dec 7, 2025

Summary

This PR adds comprehensive Jetpack Compose support to the Crowdin Android SDK, enabling real-time translation updates in Compose-based applications through a Kotlin compiler plugin.

Key Features

1. Kotlin Compiler Plugin (crowdin-compiler-plugin/)

  • Transparently intercepts stringResource() calls at compile-time
  • Redirects them to crowdinString() for real-time updates
  • Uses K2-compatible IR transformation APIs
  • Includes comprehensive test framework with test generation

2. Gradle Plugin (crowdin-gradle-plugin/)

  • Seamlessly integrates the compiler plugin into Android builds
  • Must be applied before the Compose plugin to ensure correct transformation order
  • Zero configuration required for basic usage

3. Compose Runtime Integration (crowdin/src/main/java/com/crowdin/platform/compose/)

  • ComposeStringRepository: Thread-safe state management for Compose strings
  • crowdinString(): Composable functions with automatic recomposition on translation updates
  • Full WebSocket integration for real-time preview
  • Lifecycle-aware watcher registration/deregistration using DisposableEffect

4. Enhanced WebSocket Support

  • Extended EchoWebSocketListener to support Compose watchers
  • Real-time synchronization between Crowdin platform and app UI
  • Automatic subscription/unsubscription based on composition lifecycle

5. Build Configuration Improvements

  • Centralized version management in gradle.properties
  • Shared publishing configuration (gradle/publishing.gradle.kts) for consistent POM metadata
  • Maven Central ready: Complete POM metadata with sources JARs for all modules
  • Fixed deprecation warnings: Updated buildConfig configuration
  • No code duplication: Single source of truth for versions and metadata

Documentation

  • Added comprehensive documentation in website/docs/advanced-features/jetpack-compose.mdx
  • Code samples for configuration and usage
  • Updated sidebar navigation

Breaking Changes

None - this is a purely additive feature that's opt-in via configuration.

Usage Guide

Option 1: With Compiler Plugin (Recommended)

The compiler plugin automatically transforms all stringResource() calls to support real-time updates. No code changes required!

  1. Apply the Gradle plugin:
plugins {
    id("com.crowdin.platform.gradle")  // Must be before Compose plugin
    id("org.jetbrains.kotlin.plugin.compose")
}
  1. Enable in Crowdin config:
Crowdin.init(
    context,
    CrowdinConfig.Builder()
        .withRealTimeComposeEnabled(true)
        .build()
)
  1. Use existing Compose code - it just works:
@Composable
fun MyScreen() {
    // stringResource() is automatically transformed to crowdinString()
    val text = stringResource(R.string.welcome)
    Text(text = text)
}

Option 2: Without Compiler Plugin

If you prefer not to use the compiler plugin, you can manually use crowdinString():

@Composable
fun MyScreen() {
    val text = crowdinString(R.string.welcome)
    Text(text = text)
}

🤖 Generated with Claude Code


Note

Introduces a K2 compiler plugin and Gradle plugin to auto-transform stringResource() to crowdinString(), plus SDK-side Compose runtime/state + WebSocket integration, centralized build/publishing config, and documentation.

  • Compose Real-time Support (SDK):
    • Add com.crowdin.platform.compose runtime: ComposeStringRepository and crowdinString() composables with stateful updates and lifecycle-aware watchers.
    • Extend Crowdin, CrowdinConfig, and FeatureFlags to enable/guard real-time Compose (API 24+), expose repository, and trigger updates on config/data changes.
    • Integrate WebSocket: enhance EchoWebSocketListener and RealTimeUpdateManager to subscribe/update Compose watchers.
  • Kotlin Compiler Plugin (crowdin-compiler-plugin/):
    • K2 IR transformer replaces androidx.compose.ui.res.stringResource() calls with com.crowdin.platform.compose.crowdinString().
    • Command-line processor/registrar with enabled option; tests and generators included.
  • Gradle Plugin (crowdin-gradle-plugin/):
    • Wires compiler plugin into builds; enforces being applied before Compose; per-variant enablement via crowdin extension.
  • Build/Publishing:
    • Centralize versions/metadata (gradle.properties, libs.versions.toml).
    • Shared POM config (gradle/publishing.gradle.kts) and sources JARs; include new modules in settings.gradle.
    • Add Compose deps/build features in crowdin/ and update example app config.
  • Docs:
    • New Jetpack Compose guide with config/usage; sidebar updated.

Written by Cursor Bugbot for commit ff67778. This will update automatically on new commits. Configure here.

Copilot AI review requested due to automatic review settings December 7, 2025 21:09
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces comprehensive Jetpack Compose support to the Crowdin Android SDK, enabling real-time translation updates in Compose applications through a sophisticated compiler plugin architecture and runtime integration system.

Key Changes

  • New compiler plugin module (crowdin-compiler-plugin) that transparently transforms stringResource() calls to crowdinString() at compile-time using K2-compatible IR transformation
  • New Gradle plugin module (crowdin-gradle-plugin) that integrates the compiler plugin into Android builds with variant-based control
  • Compose runtime integration with thread-safe state management, WebSocket support for real-time updates, and lifecycle-aware watcher registration

Reviewed changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
website/sidebars.ts Added Jetpack Compose documentation to sidebar navigation
website/docs/advanced-features/jetpack-compose.mdx Comprehensive documentation for Compose integration with usage examples
website/docs/advanced-features/real-time-preview.mdx Added cross-reference to Compose documentation
website/docs/code-samples/jetpack-compose/config.kt Configuration example for enabling Compose support
website/docs/code-samples/jetpack-compose/usage.kt Usage example for manual Compose integration
settings.gradle Added new compiler and Gradle plugin modules to build
gradle/publishing.gradle.kts Shared publishing configuration for consistent Maven Central metadata
gradle/libs.versions.toml New version catalog with centralized dependency versions
gradle.properties Centralized version management and publishing metadata
example/build.gradle Enabled Compose support in example app
crowdin/build.gradle Added Compose dependencies and enabled Compose build features
crowdin/src/main/java/com/crowdin/platform/Crowdin.kt Added Compose repository initialization and integration hooks
crowdin/src/main/java/com/crowdin/platform/CrowdinConfig.kt Added configuration flag for Compose support
crowdin/src/main/java/com/crowdin/platform/compose/CrowdinCompose.kt Composable functions for real-time string retrieval
crowdin/src/main/java/com/crowdin/platform/compose/ComposeStringRepository.kt Thread-safe state management for Compose strings with WebSocket integration
crowdin/src/main/java/com/crowdin/platform/realtimeupdate/EchoWebSocketListener.kt Extended WebSocket listener to support Compose watchers
crowdin/src/main/java/com/crowdin/platform/realtimeupdate/RealTimeUpdateManager.kt Integrated Compose repository into real-time update system
crowdin/src/main/java/com/crowdin/platform/data/model/TextMetaData.kt Added resourceId field for Compose integration
crowdin/src/main/java/com/crowdin/platform/util/FeatureFlags.kt Added Compose feature flag
crowdin/src/test/java/com/crowdin/platform/compose/ComposeStringRepositoryTest.kt Basic unit tests for Compose repository
crowdin/src/test/java/com/crowdin/platform/RealTimeUpdateManagerTest.kt Updated tests to include Compose repository parameter
crowdin/src/test/java/com/crowdin/platform/EchoWebSocketListenerTest.kt Updated tests to include Compose repository parameter
crowdin/src/test/java/com/crowdin/platform/FeatureFlagTest.kt Added test for Compose feature flag
crowdin/src/test/java/com/crowdin/platform/CrowdinConfigTest.kt Added test for Compose configuration
crowdin-gradle-plugin/build.gradle.kts Build configuration for Gradle plugin with Maven publishing
crowdin-gradle-plugin/src/main/kotlin/com/crowdin/platform/gradle/CrowdinGradlePlugin.kt Gradle plugin that applies compiler plugin with variant-based enabling
crowdin-gradle-plugin/src/test/kotlin/com/crowdin/platform/gradle/CrowdinExtensionTest.kt Tests for Gradle plugin extension
crowdin-compiler-plugin/build.gradle.kts Build configuration for compiler plugin with test framework
crowdin-compiler-plugin/src/main/kotlin/com/crowdin/platform/compiler/CrowdinComponentRegistrar.kt Compiler plugin entry point and extension registration
crowdin-compiler-plugin/src/main/kotlin/com/crowdin/platform/compiler/CrowdinCommandLineProcessor.kt Command-line processor for compiler plugin options
crowdin-compiler-plugin/src/main/kotlin/com/crowdin/platform/compiler/CrowdinIrGenerationExtension.kt IR generation extension with plugin ordering enforcement
crowdin-compiler-plugin/src/main/kotlin/com/crowdin/platform/compiler/CrowdinStringResourceTransformer.kt IR transformer that intercepts and transforms stringResource calls
crowdin-compiler-plugin/testData/box/stringResourceTransform.kt Compiler plugin test for transformation verification
crowdin-compiler-plugin/test-fixtures/* Test infrastructure for compiler plugin testing
crowdin-compiler-plugin/resources/META-INF/services/* Service loader files for compiler plugin discovery

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@leo-benz leo-benz force-pushed the feature/compose-support branch from b7c33cd to 50c7142 Compare December 7, 2025 21:24
@andrii-bodnar
Copy link
Member

@leo-benz thanks a lot for such a great contribution! 🚀

Requesting a review from @MykhailoNester. In the meantime, could you please take a look at the AI comments? If something looks irrelevant, just resolve it.

@leo-benz leo-benz force-pushed the feature/compose-support branch from ff7b804 to 1cb42d6 Compare December 13, 2025 14:33
@leo-benz leo-benz force-pushed the feature/compose-support branch from 1cb42d6 to ff67778 Compare December 13, 2025 14:47
@leo-benz
Copy link
Author

@andrii-bodnar First time for me working with a GitHub repo with such extensive AI checks, overall a nice workflow and good comments 👍🏻 I have addressed and resolved all the relevant ones.

@RequiresApi(Build.VERSION_CODES.N)
@Composable
fun crowdinString(
resourceId: Int,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor API suggestion: Consider matching the original stringResource() signature more closely:
@StringRes id: Int

// Original code
Text(stringResource(id = R.string.welcome))

// After find/replace "stringResource" → "crowdinString"  
Text(crowdinString(id = R.string.welcome)) 

return
}

if (eventData.pluralForm == null || eventData.pluralForm == PLURAL_NONE) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @leo-benz ! 👋
Nice work on this! The Compose integration looks solid and the compiler plugin approach is clean.

Quick question - I noticed the WebSocket handler for Compose only handles non-plural strings EchoWebSocketListener.kt:349-354, while TextViews handle both the else block at line 224 handles plurals. Is plural support for Compose something planned for a follow-up, or should we document this limitation?
Otherwise looks good to merge! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants