Skip to content

Instantly share code, notes, and snippets.

@ArthurKun21
Created January 19, 2026 13:32
Show Gist options
  • Select an option

  • Save ArthurKun21/51f29b58f8aaeef67f27165fcf12e075 to your computer and use it in GitHub Desktop.

Select an option

Save ArthurKun21/51f29b58f8aaeef67f27165fcf12e075 to your computer and use it in GitHub Desktop.
Compose Component Resources String helper to make it easier to reuse the string resource for both composable and non-composable environments
import androidx.compose.runtime.Composable
import org.jetbrains.compose.resources.PluralStringResource
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.getPluralString
import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.pluralStringResource
import org.jetbrains.compose.resources.stringResource
/**
* A sealed interface that abstracts compose component string resources, allowing them to be passed
* as data and resolved later in either a [Composable] or a non-composable context.
*
* This utility provides a unified way to handle different types of resource resolutions,
* such as standard strings with arguments or pluralized forms, while maintaining
* compatibility with Compose Multiplatform resource loading.
*
* Use the [plus] operator to combine multiple ComposeString instances:
* ```
* val combined = ComposeString.Strings(Res.string.hello) + ComposeString.Strings(Res.string.world)
* ```
*/
sealed interface ComposeString {
/**
* Resolves the localized string in a non-composable context.
*
* This is a suspending function as it may perform asynchronous resource loading.
*
* @return The resolved localized string.
*/
suspend fun asString(): String
/**
* Resolves the localized string within a Compose [Composable] context.
*
* This function utilizes the current composition's resources to return the formatted
* string, automatically reacting to configuration changes (like language or orientation).
*
* @return The resolved and formatted localized [String].
*/
@Composable
fun asStringComposable(): String
/**
* Combines this ComposeString with another ComposeString.
*
* @param other The ComposeString to append to this one.
* @return A new Combined ComposeString that represents both strings concatenated.
*/
operator fun plus(other: ComposeString): ComposeString = when {
this is Combined && other is Combined -> Combined(this.parts + other.parts)
this is Combined -> Combined(this.parts + other)
other is Combined -> Combined(listOf(this) + other.parts)
else -> Combined(listOf(this, other))
}
/**
* Represents a plain text string that does not require localization or resource lookup.
*
* @property text The raw string value to be displayed.
*/
data class Text(val text: String) : ComposeString {
override suspend fun asString(): String = text
@Composable
override fun asStringComposable(): String = text
}
/**
* Represents a standard string resource with optional formatting arguments.
*
* @property res The [StringResource] to be resolved.
* @property args A list of arguments used for string formatting.
*/
data class Strings(
val res: StringResource,
val args: List<Any> = emptyList(),
) : ComposeString {
// Helper constructor for varargs
constructor(res: StringResource, vararg args: Any) : this(res, args.toList())
override suspend fun asString(): String {
return getString(res, *args.toTypedArray())
}
@Composable
override fun asStringComposable(): String {
return stringResource(res, *args.toTypedArray())
}
}
/**
* Represents a pluralized string resource.
*
* @property res The plural string resource to be used.
* @property quantity The quantity to use for selecting the appropriate plural form.
* @property args Optional formatting arguments to be applied to the string.
*/
data class Plurals(
val res: PluralStringResource,
val quantity: Int,
val args: List<Any> = emptyList(),
) : ComposeString {
// Helper constructor for varargs
constructor(res: PluralStringResource, quantity: Int, vararg args: Any) : this(res, quantity, args.toList())
override suspend fun asString(): String {
return getPluralString(res, quantity, *args.toTypedArray())
}
@Composable
override fun asStringComposable(): String {
return pluralStringResource(res, quantity, *args.toTypedArray())
}
}
/**
* Represents a combination of multiple ComposeString instances.
*
* This implementation is automatically created when using the [plus] operator
* to combine different ComposeString types. It concatenates all parts in order
* when resolved.
*
* @property parts The list of ComposeString instances to combine.
*/
data class Combined(
val parts: List<ComposeString>,
) : ComposeString {
override suspend fun asString(): String {
return buildString {
parts.forEach { append(it.asString()) }
}
}
@Composable
override fun asStringComposable(): String {
return buildString {
parts.forEach { append(it.asStringComposable()) }
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment