CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-compose-components--components-resources

Resource management library for Compose Multiplatform applications providing type-safe access to images, strings, fonts, and drawable assets across all platforms.

Pending
Overview
Eval results
Files

plural-string-resources.mddocs/

Plural String Resources

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.

Core Types

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 Functions

Basic Plural String Loading

@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int): String

Loads 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 resource
  • quantity - The quantity that determines which plural form to use

Usage:

@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)
}

Formatted Plural String Loading

@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): String

Loads 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 placeholders
  • quantity - The quantity for plural form selection
  • formatArgs - Variable arguments to substitute into the string

Usage:

@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 Functions

Basic Non-Composable Loading

suspend fun getPluralString(resource: PluralStringResource, quantity: Int): String

Loads 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)
    }
}

Formatted Non-Composable Loading

suspend fun getPluralString(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): String

Loads 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)
    )
}

Environment-Specific Loading

suspend fun getPluralString(
    environment: ResourceEnvironment,
    resource: PluralStringResource,
    quantity: Int
): String

suspend fun getPluralString(
    environment: ResourceEnvironment,
    resource: PluralStringResource,
    quantity: Int,
    vararg formatArgs: Any
): String

Loads 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)
    )
}

CLDR Plural Categories

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)
}

Language-Specific Plural Rules

English:

  • ONE: 1
  • OTHER: 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: 0
  • ONE: 1
  • TWO: 2
  • FEW: 3-10
  • MANY: 11-99
  • OTHER: 100, 200, ... (hundreds)

Plural Resource Definition

XML Resource Format

<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>

Localized Plural Resources

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)

Plural Rule Management

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.

Error Handling

Common Exceptions:

  • IllegalArgumentException - Resource ID not found or no matching plural category
  • MissingResourceException - Plural resource file cannot be read

Fallback Behavior:

  1. If the exact plural category is not found, falls back to OTHER
  2. If OTHER is not defined, throws an exception
  3. Always define OTHER as the fallback category

Example 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)
}

Best Practices

  1. Always provide the OTHER category:

    <plurals name="example">
        <item quantity="one">1 item</item>
        <item quantity="other">%d items</item> <!-- Required -->
    </plurals>
  2. 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")
    }
  3. Use meaningful resource names:

    Res.plurals.unread_messages_count  // Good
    Res.plurals.plural1               // Bad
  4. Include quantity in formatted strings:

    <plurals name="download_progress">
        <item quantity="one">%d file downloaded</item>
        <item quantity="other">%d files downloaded</item>
    </plurals>
  5. 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>
  6. 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>

Advanced Usage

Dynamic Plural Selection

@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)
}

Nested Plural Logic

@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

docs

font-resources.md

image-drawable-resources.md

index.md

plural-string-resources.md

resource-environment.md

string-array-resources.md

string-resources.md

tile.json