or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

font-resources.mdimage-drawable-resources.mdindex.mdplural-string-resources.mdresource-environment.mdstring-array-resources.mdstring-resources.md

plural-string-resources.mddocs/

0

# Plural String Resources

1

2

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.

3

4

## Core Types

5

6

```kotlin { .api }

7

class PluralStringResource(id: String, val key: String, items: Set<ResourceItem>) : Resource(id, items)

8

```

9

10

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

11

12

## Composable Functions

13

14

### Basic Plural String Loading

15

16

```kotlin { .api }

17

@Composable

18

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

19

```

20

21

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.

22

23

**Parameters:**

24

- `resource` - The plural string resource

25

- `quantity` - The quantity that determines which plural form to use

26

27

**Usage:**

28

```kotlin

29

@Composable

30

fun ItemCounter(itemCount: Int) {

31

val text = pluralStringResource(Res.plurals.items_count, itemCount)

32

Text(text = text)

33

}

34

35

@Composable

36

fun MessageIndicator(messageCount: Int) {

37

val status = pluralStringResource(

38

resource = Res.plurals.message_status,

39

quantity = messageCount

40

)

41

Text(text = status)

42

}

43

```

44

45

### Formatted Plural String Loading

46

47

```kotlin { .api }

48

@Composable

49

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

50

```

51

52

Loads a formatted pluralized string resource with variable arguments. The selected plural form can contain format placeholders that are replaced with the provided arguments.

53

54

**Parameters:**

55

- `resource` - The plural string resource with format placeholders

56

- `quantity` - The quantity for plural form selection

57

- `formatArgs` - Variable arguments to substitute into the string

58

59

**Usage:**

60

```kotlin

61

@Composable

62

fun FileOperationStatus(fileCount: Int, operation: String) {

63

val status = pluralStringResource(

64

resource = Res.plurals.file_operation_message,

65

quantity = fileCount,

66

formatArgs = arrayOf(fileCount, operation)

67

)

68

Text(text = status)

69

}

70

```

71

72

**Plural Resource Example:**

73

```xml

74

<plurals name="file_operation_message">

75

<item quantity="one">%2$s %1$d file</item>

76

<item quantity="other">%2$s %1$d files</item>

77

</plurals>

78

```

79

80

## Suspend Functions

81

82

### Basic Non-Composable Loading

83

84

```kotlin { .api }

85

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

86

```

87

88

Loads a pluralized string resource outside of a Composable context using the system's resource environment.

89

90

**Usage:**

91

```kotlin

92

suspend fun createNotificationText(unreadCount: Int): String {

93

return getPluralString(Res.plurals.unread_notifications, unreadCount)

94

}

95

96

class NotificationManager {

97

suspend fun updateBadge(count: Int) {

98

val badgeText = getPluralString(Res.plurals.badge_count, count)

99

updateSystemBadge(badgeText)

100

}

101

}

102

```

103

104

### Formatted Non-Composable Loading

105

106

```kotlin { .api }

107

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

108

```

109

110

Loads a formatted pluralized string resource outside of a Composable context.

111

112

**Usage:**

113

```kotlin

114

suspend fun generateSummaryText(downloadCount: Int, totalSize: String): String {

115

return getPluralString(

116

resource = Res.plurals.download_summary,

117

quantity = downloadCount,

118

formatArgs = arrayOf(downloadCount, totalSize)

119

)

120

}

121

```

122

123

### Environment-Specific Loading

124

125

```kotlin { .api }

126

suspend fun getPluralString(

127

environment: ResourceEnvironment,

128

resource: PluralStringResource,

129

quantity: Int

130

): String

131

132

suspend fun getPluralString(

133

environment: ResourceEnvironment,

134

resource: PluralStringResource,

135

quantity: Int,

136

vararg formatArgs: Any

137

): String

138

```

139

140

Loads pluralized string resources using a specific resource environment. Useful for testing different locales or generating content for specific language contexts.

141

142

**Usage:**

143

```kotlin

144

suspend fun getLocalizedPluralString(

145

locale: Locale,

146

itemCount: Int

147

): String {

148

val environment = ResourceEnvironment(

149

LanguageQualifier(locale.language),

150

RegionQualifier(locale.country),

151

ThemeQualifier.LIGHT,

152

DensityQualifier.MDPI

153

)

154

155

return getPluralString(

156

environment = environment,

157

resource = Res.plurals.item_count,

158

quantity = itemCount,

159

formatArgs = arrayOf(itemCount)

160

)

161

}

162

```

163

164

## CLDR Plural Categories

165

166

The library supports all CLDR plural categories:

167

168

```kotlin { .api }

169

enum class PluralCategory {

170

ZERO, // Exact zero (Arabic, Latvian)

171

ONE, // Singular form (most languages)

172

TWO, // Dual form (Arabic, Welsh)

173

FEW, // Small numbers (Polish, Russian 2-4)

174

MANY, // Large numbers (Polish, Russian 5+)

175

OTHER // Default/fallback (always required)

176

}

177

```

178

179

### Language-Specific Plural Rules

180

181

**English:**

182

- `ONE`: 1

183

- `OTHER`: 0, 2, 3, 4, ... (everything else)

184

185

**Russian:**

186

- `ONE`: 1, 21, 31, 41, ... (ends with 1, not 11)

187

- `FEW`: 2-4, 22-24, 32-34, ... (ends with 2-4, not 12-14)

188

- `MANY`: 0, 5-20, 25-30, ... (everything else)

189

190

**Arabic:**

191

- `ZERO`: 0

192

- `ONE`: 1

193

- `TWO`: 2

194

- `FEW`: 3-10

195

- `MANY`: 11-99

196

- `OTHER`: 100, 200, ... (hundreds)

197

198

## Plural Resource Definition

199

200

### XML Resource Format

201

202

```xml

203

<plurals name="notification_count">

204

<item quantity="zero">No notifications</item>

205

<item quantity="one">1 notification</item>

206

<item quantity="other">%d notifications</item>

207

</plurals>

208

209

<plurals name="download_time">

210

<item quantity="one">%d minute remaining</item>

211

<item quantity="other">%d minutes remaining</item>

212

</plurals>

213

214

<plurals name="complex_example">

215

<item quantity="zero">No items selected</item>

216

<item quantity="one">One item selected</item>

217

<item quantity="two">Both items selected</item>

218

<item quantity="few">A few items selected (%d)</item>

219

<item quantity="many">Many items selected (%d)</item>

220

<item quantity="other">%d items selected</item>

221

</plurals>

222

```

223

224

### Localized Plural Resources

225

226

```

227

res/

228

├── values/plurals.xml # Default (English)

229

├── values-ru/plurals.xml # Russian (complex rules)

230

├── values-ar/plurals.xml # Arabic (6 categories)

231

├── values-zh/plurals.xml # Chinese (simple rules)

232

└── values-pl/plurals.xml # Polish (complex rules)

233

```

234

235

## Plural Rule Management

236

237

```kotlin { .api }

238

class PluralRuleList(private val rules: Array<PluralRule>) {

239

fun getCategory(quantity: Int): PluralCategory

240

241

companion object {

242

suspend fun getInstance(

243

languageQualifier: LanguageQualifier,

244

regionQualifier: RegionQualifier

245

): PluralRuleList

246

247

suspend fun getInstance(cldrLocaleName: String): PluralRuleList

248

}

249

}

250

```

251

252

The library includes built-in CLDR plural rules for all supported locales. Rules are loaded automatically based on the current resource environment.

253

254

## Error Handling

255

256

**Common Exceptions:**

257

- `IllegalArgumentException` - Resource ID not found or no matching plural category

258

- `MissingResourceException` - Plural resource file cannot be read

259

260

**Fallback Behavior:**

261

1. If the exact plural category is not found, falls back to `OTHER`

262

2. If `OTHER` is not defined, throws an exception

263

3. Always define `OTHER` as the fallback category

264

265

**Example Error Handling:**

266

```kotlin

267

@Composable

268

fun SafePluralText(count: Int) {

269

val text = try {

270

pluralStringResource(Res.plurals.item_count, count)

271

} catch (e: IllegalArgumentException) {

272

// Fallback to simple formatting

273

if (count == 1) "1 item" else "$count items"

274

}

275

276

Text(text = text)

277

}

278

```

279

280

## Best Practices

281

282

1. **Always provide the OTHER category**:

283

```xml

284

<plurals name="example">

285

<item quantity="one">1 item</item>

286

<item quantity="other">%d items</item> <!-- Required -->

287

</plurals>

288

```

289

290

2. **Test with multiple locales**:

291

```kotlin

292

// Test plural rules for different languages

293

val testCounts = listOf(0, 1, 2, 3, 4, 5, 11, 21, 101)

294

testCounts.forEach { count ->

295

val text = pluralStringResource(Res.plurals.test_resource, count)

296

println("$count: $text")

297

}

298

```

299

300

3. **Use meaningful resource names**:

301

```kotlin

302

Res.plurals.unread_messages_count // Good

303

Res.plurals.plural1 // Bad

304

```

305

306

4. **Include quantity in formatted strings**:

307

```xml

308

<plurals name="download_progress">

309

<item quantity="one">%d file downloaded</item>

310

<item quantity="other">%d files downloaded</item>

311

</plurals>

312

```

313

314

5. **Handle zero appropriately**:

315

```xml

316

<plurals name="search_results">

317

<item quantity="zero">No results found</item>

318

<item quantity="one">1 result found</item>

319

<item quantity="other">%d results found</item>

320

</plurals>

321

```

322

323

6. **Consider context for better UX**:

324

```xml

325

<!-- Instead of just numbers, provide meaningful context -->

326

<plurals name="friend_activity">

327

<item quantity="zero">No friends are online</item>

328

<item quantity="one">1 friend is online</item>

329

<item quantity="other">%d friends are online</item>

330

</plurals>

331

```

332

333

## Advanced Usage

334

335

### Dynamic Plural Selection

336

337

```kotlin

338

@Composable

339

fun DynamicPluralExample(items: List<Item>) {

340

val selectedCount = items.count { it.isSelected }

341

val totalCount = items.size

342

343

val statusText = pluralStringResource(

344

resource = Res.plurals.selection_status,

345

quantity = selectedCount,

346

formatArgs = arrayOf(selectedCount, totalCount)

347

)

348

349

Text(text = statusText)

350

}

351

```

352

353

### Nested Plural Logic

354

355

```kotlin

356

@Composable

357

fun ComplexPluralExample(users: List<User>, posts: List<Post>) {

358

val userText = pluralStringResource(Res.plurals.user_count, users.size)

359

val postText = pluralStringResource(Res.plurals.post_count, posts.size)

360

361

Text(text = "$userText created $postText")

362

// Examples: "1 user created 5 posts", "3 users created 1 post"

363

}

364

```