Resource management library for Compose Multiplatform applications providing type-safe access to images, strings, fonts, and drawable assets across all platforms.
—
Plural string resources handle quantity-based pluralization following CLDR (Common Locale Data Repository) plural rules. This enables proper localization for languages with complex pluralization rules, ensuring grammatically correct text across all supported locales.
class PluralStringResource(id: String, val key: String, items: Set<ResourceItem>) : Resource(id, items)A plural string resource represents a text entry with multiple plural forms based on quantity. Each resource contains variants for different plural categories (zero, one, two, few, many, other).
@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int): StringLoads a pluralized string resource based on the provided quantity. The function automatically selects the appropriate plural form according to CLDR rules for the current locale.
Parameters:
resource - The plural string resourcequantity - The quantity that determines which plural form to useUsage:
@Composable
fun ItemCounter(itemCount: Int) {
val text = pluralStringResource(Res.plurals.items_count, itemCount)
Text(text = text)
}
@Composable
fun MessageIndicator(messageCount: Int) {
val status = pluralStringResource(
resource = Res.plurals.message_status,
quantity = messageCount
)
Text(text = status)
}@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): StringLoads a formatted pluralized string resource with variable arguments. The selected plural form can contain format placeholders that are replaced with the provided arguments.
Parameters:
resource - The plural string resource with format placeholdersquantity - The quantity for plural form selectionformatArgs - Variable arguments to substitute into the stringUsage:
@Composable
fun FileOperationStatus(fileCount: Int, operation: String) {
val status = pluralStringResource(
resource = Res.plurals.file_operation_message,
quantity = fileCount,
formatArgs = arrayOf(fileCount, operation)
)
Text(text = status)
}Plural Resource Example:
<plurals name="file_operation_message">
<item quantity="one">%2$s %1$d file</item>
<item quantity="other">%2$s %1$d files</item>
</plurals>suspend fun getPluralString(resource: PluralStringResource, quantity: Int): StringLoads a pluralized string resource outside of a Composable context using the system's resource environment.
Usage:
suspend fun createNotificationText(unreadCount: Int): String {
return getPluralString(Res.plurals.unread_notifications, unreadCount)
}
class NotificationManager {
suspend fun updateBadge(count: Int) {
val badgeText = getPluralString(Res.plurals.badge_count, count)
updateSystemBadge(badgeText)
}
}suspend fun getPluralString(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): StringLoads a formatted pluralized string resource outside of a Composable context.
Usage:
suspend fun generateSummaryText(downloadCount: Int, totalSize: String): String {
return getPluralString(
resource = Res.plurals.download_summary,
quantity = downloadCount,
formatArgs = arrayOf(downloadCount, totalSize)
)
}suspend fun getPluralString(
environment: ResourceEnvironment,
resource: PluralStringResource,
quantity: Int
): String
suspend fun getPluralString(
environment: ResourceEnvironment,
resource: PluralStringResource,
quantity: Int,
vararg formatArgs: Any
): StringLoads pluralized string resources using a specific resource environment. Useful for testing different locales or generating content for specific language contexts.
Usage:
suspend fun getLocalizedPluralString(
locale: Locale,
itemCount: Int
): String {
val environment = ResourceEnvironment(
LanguageQualifier(locale.language),
RegionQualifier(locale.country),
ThemeQualifier.LIGHT,
DensityQualifier.MDPI
)
return getPluralString(
environment = environment,
resource = Res.plurals.item_count,
quantity = itemCount,
formatArgs = arrayOf(itemCount)
)
}The library supports all CLDR plural categories:
enum class PluralCategory {
ZERO, // Exact zero (Arabic, Latvian)
ONE, // Singular form (most languages)
TWO, // Dual form (Arabic, Welsh)
FEW, // Small numbers (Polish, Russian 2-4)
MANY, // Large numbers (Polish, Russian 5+)
OTHER // Default/fallback (always required)
}English:
ONE: 1OTHER: 0, 2, 3, 4, ... (everything else)Russian:
ONE: 1, 21, 31, 41, ... (ends with 1, not 11)FEW: 2-4, 22-24, 32-34, ... (ends with 2-4, not 12-14)MANY: 0, 5-20, 25-30, ... (everything else)Arabic:
ZERO: 0ONE: 1TWO: 2FEW: 3-10MANY: 11-99OTHER: 100, 200, ... (hundreds)<plurals name="notification_count">
<item quantity="zero">No notifications</item>
<item quantity="one">1 notification</item>
<item quantity="other">%d notifications</item>
</plurals>
<plurals name="download_time">
<item quantity="one">%d minute remaining</item>
<item quantity="other">%d minutes remaining</item>
</plurals>
<plurals name="complex_example">
<item quantity="zero">No items selected</item>
<item quantity="one">One item selected</item>
<item quantity="two">Both items selected</item>
<item quantity="few">A few items selected (%d)</item>
<item quantity="many">Many items selected (%d)</item>
<item quantity="other">%d items selected</item>
</plurals>res/
├── values/plurals.xml # Default (English)
├── values-ru/plurals.xml # Russian (complex rules)
├── values-ar/plurals.xml # Arabic (6 categories)
├── values-zh/plurals.xml # Chinese (simple rules)
└── values-pl/plurals.xml # Polish (complex rules)class PluralRuleList(private val rules: Array<PluralRule>) {
fun getCategory(quantity: Int): PluralCategory
companion object {
suspend fun getInstance(
languageQualifier: LanguageQualifier,
regionQualifier: RegionQualifier
): PluralRuleList
suspend fun getInstance(cldrLocaleName: String): PluralRuleList
}
}The library includes built-in CLDR plural rules for all supported locales. Rules are loaded automatically based on the current resource environment.
Common Exceptions:
IllegalArgumentException - Resource ID not found or no matching plural categoryMissingResourceException - Plural resource file cannot be readFallback Behavior:
OTHEROTHER is not defined, throws an exceptionOTHER as the fallback categoryExample Error Handling:
@Composable
fun SafePluralText(count: Int) {
val text = try {
pluralStringResource(Res.plurals.item_count, count)
} catch (e: IllegalArgumentException) {
// Fallback to simple formatting
if (count == 1) "1 item" else "$count items"
}
Text(text = text)
}Always provide the OTHER category:
<plurals name="example">
<item quantity="one">1 item</item>
<item quantity="other">%d items</item> <!-- Required -->
</plurals>Test with multiple locales:
// Test plural rules for different languages
val testCounts = listOf(0, 1, 2, 3, 4, 5, 11, 21, 101)
testCounts.forEach { count ->
val text = pluralStringResource(Res.plurals.test_resource, count)
println("$count: $text")
}Use meaningful resource names:
Res.plurals.unread_messages_count // Good
Res.plurals.plural1 // BadInclude quantity in formatted strings:
<plurals name="download_progress">
<item quantity="one">%d file downloaded</item>
<item quantity="other">%d files downloaded</item>
</plurals>Handle zero appropriately:
<plurals name="search_results">
<item quantity="zero">No results found</item>
<item quantity="one">1 result found</item>
<item quantity="other">%d results found</item>
</plurals>Consider context for better UX:
<!-- Instead of just numbers, provide meaningful context -->
<plurals name="friend_activity">
<item quantity="zero">No friends are online</item>
<item quantity="one">1 friend is online</item>
<item quantity="other">%d friends are online</item>
</plurals>@Composable
fun DynamicPluralExample(items: List<Item>) {
val selectedCount = items.count { it.isSelected }
val totalCount = items.size
val statusText = pluralStringResource(
resource = Res.plurals.selection_status,
quantity = selectedCount,
formatArgs = arrayOf(selectedCount, totalCount)
)
Text(text = statusText)
}@Composable
fun ComplexPluralExample(users: List<User>, posts: List<Post>) {
val userText = pluralStringResource(Res.plurals.user_count, users.size)
val postText = pluralStringResource(Res.plurals.post_count, posts.size)
Text(text = "$userText created $postText")
// Examples: "1 user created 5 posts", "3 users created 1 post"
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-compose-components--components-resources