Browse Source
Ports a part of Unicode's ICU in pure Kotlin and implements Android-style plural string resource support. Fixes JetBrains/compose-multiplatform#425. # Changes - Added `org.jetbrains.compose.resources.intl.{PluralCategory, PluralRule, PluralRuleList}`, which parses and evaluates scripts in Unicode's Locale Data Markup Langauge. - Copied `plurals.xml` from Unicode's [CLDR](https://github.com/unicode-org/cldr/blob/release-44-1/common/supplemental/plurals.xml). - Added `GeneratePluralRuleListsTask`, which parses `plurals.xml` and generates required Kotlin source codes. - Added `PluralStringResource`, `pluralStringResource`, or `getPluralString`, corresponding to `StringResource`, `stringResource`, or `getString`. - Modified `ResourcesSpec.kt` so the generated `Res` class exposes `Res.plurals`. # Potential Further Improvements - [ ] Allow configuring the default language in the `compose.resources {}` block (#4482) to determine the default pluralization rule (or just presume English as default) - [ ] Move the parser logic to the Gradle plugin and generate pluralization rules in `Res` only for languages used in `composeResources` --------- Co-authored-by: Konstantin Tskhovrebov <konstantin.tskhovrebov@jetbrains.com>pull/4543/head
Chanjung Kim
8 months ago
committed by
GitHub
24 changed files with 2827 additions and 18 deletions
@ -0,0 +1,134 @@
|
||||
/* |
||||
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
import groovy.util.Node |
||||
import groovy.xml.XmlParser |
||||
import org.gradle.api.DefaultTask |
||||
import org.gradle.api.file.RegularFileProperty |
||||
import org.gradle.api.tasks.* |
||||
|
||||
/** |
||||
* Reads a pluralization rules XML file from Unicode's CLDR and generates a Kotlin file that holds the XML content as |
||||
* arrays. This Task is required for quantity string resource support. |
||||
*/ |
||||
@CacheableTask |
||||
abstract class GeneratePluralRuleListsTask : DefaultTask() { |
||||
@get:InputFile |
||||
@get:PathSensitive(PathSensitivity.RELATIVE) |
||||
abstract val pluralsFile: RegularFileProperty |
||||
|
||||
@get:OutputFile |
||||
abstract val outputFile: RegularFileProperty |
||||
|
||||
@get:OutputFile |
||||
abstract val samplesOutputFile: RegularFileProperty |
||||
|
||||
@TaskAction |
||||
fun generatePluralRuleLists() { |
||||
val pluralRuleLists = parsePluralRuleLists() |
||||
|
||||
val mainContent = generateMainContent(pluralRuleLists) |
||||
outputFile.get().asFile.writeText(mainContent) |
||||
|
||||
val testContent = generateTestContent(pluralRuleLists) |
||||
samplesOutputFile.get().asFile.writeText(testContent) |
||||
} |
||||
|
||||
private fun parsePluralRuleLists(): List<PluralRuleList> { |
||||
val parser = XmlParser(false, false).apply { |
||||
setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false) |
||||
setFeature("http://apache.org/xml/features/disallow-doctype-decl", false) |
||||
} |
||||
val supplementalData = parser.parse(pluralsFile.get().asFile) |
||||
val pluralRuleLists = supplementalData.children().filterIsInstance<Node>().first { it.name() == "plurals" } |
||||
|
||||
return pluralRuleLists.children().filterIsInstance<Node>().map { pluralRules -> |
||||
val locales = pluralRules.attribute("locales").toString().split(' ') |
||||
PluralRuleList( |
||||
locales, |
||||
pluralRules.children().filterIsInstance<Node>().map { pluralRule -> |
||||
val rule = pluralRule.text().split('@') |
||||
PluralRule( |
||||
pluralRule.attribute("count").toString(), |
||||
// trim samples as not needed |
||||
rule[0].trim(), |
||||
rule.firstOrNull { it.startsWith("integer") }?.substringAfter("integer")?.trim() ?: "", |
||||
rule.firstOrNull { it.startsWith("decimal") }?.substringAfter("decimal")?.trim() ?: "", |
||||
) |
||||
} |
||||
) |
||||
} |
||||
} |
||||
|
||||
private fun generateMainContent(pluralRuleLists: List<PluralRuleList>): String { |
||||
val pluralRuleListIndexByLocale = pluralRuleLists.flatMapIndexed { idx, pluralRuleList -> |
||||
pluralRuleList.locales.map { locale -> |
||||
locale to idx |
||||
} |
||||
} |
||||
|
||||
return """ |
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
/** |
||||
* THIS CODE IS AUTOGENERATED BY './gradlew :resources:library:generatePluralRuleLists' |
||||
* DO NOT EDIT!!! |
||||
*/ |
||||
internal val cldrPluralRuleListIndexByLocale = mapOf( |
||||
${pluralRuleListIndexByLocale.joinToString(separator = ",\n ") { (locale, idx) -> |
||||
"\"$locale\" to $idx" |
||||
}} |
||||
) |
||||
|
||||
internal val cldrPluralRuleLists = arrayOf(${pluralRuleLists.joinToString(",") { pluralRuleList -> |
||||
""" |
||||
arrayOf( |
||||
${pluralRuleList.rules.joinToString(",\n ") { rule -> |
||||
"PluralCategory.${rule.count.uppercase()} to \"${rule.rule}\"" |
||||
}} |
||||
)""" |
||||
}} |
||||
) |
||||
""".trimIndent() |
||||
} |
||||
|
||||
private fun generateTestContent(pluralRuleLists: List<PluralRuleList>): String { |
||||
val pluralRuleIntegerSamplesByLocale = pluralRuleLists.flatMap { pluralRuleList -> |
||||
pluralRuleList.locales.map { locale -> |
||||
locale to pluralRuleList.rules.map { it.count to it.integerSample } |
||||
} |
||||
} |
||||
|
||||
return """ |
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
/** |
||||
* THIS CODE IS AUTOGENERATED BY './gradlew :resources:library:generatePluralRuleLists' |
||||
* DO NOT EDIT!!! |
||||
*/ |
||||
internal val cldrPluralRuleIntegerSamples = arrayOf( |
||||
${pluralRuleIntegerSamplesByLocale.joinToString(",\n ") { (locale, samples) -> |
||||
""""$locale" to arrayOf( |
||||
${samples.joinToString(",\n ") { (count, sample) -> |
||||
"PluralCategory.${count.uppercase()} to \"$sample\"" |
||||
}} |
||||
)""" |
||||
}} |
||||
) |
||||
""".trimIndent() |
||||
} |
||||
} |
||||
|
||||
private data class PluralRuleList( |
||||
val locales: List<String>, |
||||
val rules: List<PluralRule>, |
||||
) |
||||
|
||||
private data class PluralRule( |
||||
val count: String, |
||||
val rule: String, |
||||
val integerSample: String, |
||||
val decimalSample: String, |
||||
) |
@ -0,0 +1,257 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<!DOCTYPE supplementalData SYSTEM "../../common/dtd/ldmlSupplemental.dtd"> |
||||
<!-- copied from https://github.com/unicode-org/cldr/blob/release-44-1/common/supplemental/plurals.xml --> |
||||
<!-- |
||||
Copyright © 1991-2022 Unicode, Inc. |
||||
For terms of use, see http://www.unicode.org/copyright.html |
||||
SPDX-License-Identifier: Unicode-DFS-2016 |
||||
CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/) |
||||
--> |
||||
<supplementalData> |
||||
<version number="$Revision$"/> |
||||
<plurals type="cardinal"> |
||||
<!-- For a canonicalized list, use GeneratedPluralSamples --> |
||||
|
||||
<!-- 1: other --> |
||||
|
||||
<pluralRules locales="bm bo dz hnj id ig ii in ja jbo jv jw kde kea km ko lkt lo ms my nqo osa root sah ses sg su th to tpi vi wo yo yue zh"> |
||||
<pluralRule count="other"> @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 2: one,other --> |
||||
|
||||
<pluralRules locales="am as bn doi fa gu hi kn pcm zu"> |
||||
<pluralRule count="one">i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ff hy kab"> |
||||
<pluralRule count="one">i = 0,1 @integer 0, 1 @decimal 0.0~1.5</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ast de en et fi fy gl ia io ji lij nl sc scn sv sw ur yi"> |
||||
<pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="si"> |
||||
<pluralRule count="one">n = 0,1 or i = 0 and f = 1 @integer 0, 1 @decimal 0.0, 0.1, 1.0, 0.00, 0.01, 1.00, 0.000, 0.001, 1.000, 0.0000, 0.0001, 1.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.2~0.9, 1.1~1.8, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ak bho guw ln mg nso pa ti wa"> |
||||
<pluralRule count="one">n = 0..1 @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="tzm"> |
||||
<pluralRule count="one">n = 0..1 or n = 11..99 @integer 0, 1, 11~24 @decimal 0.0, 1.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0</pluralRule> |
||||
<pluralRule count="other"> @integer 2~10, 100~106, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="af an asa az bal bem bez bg brx ce cgg chr ckb dv ee el eo eu fo fur gsw ha haw hu jgo jmc ka kaj kcg kk kkj kl ks ksb ku ky lb lg mas mgo ml mn mr nah nb nd ne nn nnh no nr ny nyn om or os pap ps rm rof rwk saq sd sdh seh sn so sq ss ssy st syr ta te teo tig tk tn tr ts ug uz ve vo vun wae xh xog"> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="da"> |
||||
<pluralRule count="one">n = 1 or t != 0 and i = 0,1 @integer 1 @decimal 0.1~1.6</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0~3.4, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="is"> |
||||
<pluralRule count="one">t = 0 and i % 10 = 1 and i % 100 != 11 or t % 10 = 1 and t % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.0, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.2~0.9, 1.2~1.8, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="mk"> |
||||
<pluralRule count="one">v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.2~1.0, 1.2~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ceb fil tl"> |
||||
<pluralRule count="one">v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9 @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.3, 0.5, 0.7, 0.8, 1.0~1.3, 1.5, 1.7, 1.8, 2.0, 2.1, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, … @decimal 0.4, 0.6, 0.9, 1.4, 1.6, 1.9, 2.4, 2.6, 10.4, 100.4, 1000.4, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 3: zero,one,other --> |
||||
|
||||
<pluralRules locales="lv prg"> |
||||
<pluralRule count="zero">n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19 @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="one">n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.0, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
<pluralRule count="other"> @integer 2~9, 22~29, 102, 1002, … @decimal 0.2~0.9, 1.2~1.9, 10.2, 100.2, 1000.2, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="lag"> |
||||
<pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule> |
||||
<pluralRule count="one">i = 0,1 and n != 0 @integer 1 @decimal 0.1~1.6</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ksh"> |
||||
<pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="blo"> |
||||
<pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~2.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 3: one,two,other --> |
||||
|
||||
<pluralRules locales="he iw"> |
||||
<pluralRule count="one">i = 1 and v = 0 or i = 0 and v != 0 @integer 1 @decimal 0.0~0.9, 0.00~0.05</pluralRule> |
||||
<pluralRule count="two">i = 2 and v = 0 @integer 2</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.0~2.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="iu naq sat se sma smi smj smn sms"> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 3: one,few,other --> |
||||
|
||||
<pluralRules locales="shi"> |
||||
<pluralRule count="one">i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04</pluralRule> |
||||
<pluralRule count="few">n = 2..10 @integer 2~10 @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00</pluralRule> |
||||
<pluralRule count="other"> @integer 11~26, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~1.9, 2.1~2.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="mo ro"> |
||||
<pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule> |
||||
<pluralRule count="few">v != 0 or n = 0 or n != 1 and n % 100 = 1..19 @integer 0, 2~16, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 20~35, 100, 1000, 10000, 100000, 1000000, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="bs hr sh sr"> |
||||
<pluralRule count="one">v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
<pluralRule count="few">v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 3: one,many,other --> |
||||
|
||||
<pluralRules locales="fr"> |
||||
<pluralRule count="one">i = 0,1 @integer 0, 1 @decimal 0.0~1.5</pluralRule> |
||||
<pluralRule count="many">e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5 @integer 1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, … @decimal 1.0000001c6, 1.1c6, 2.0000001c6, 2.1c6, 3.0000001c6, 3.1c6, …</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0001c3, 1.1c3, 2.0001c3, 2.1c3, 3.0001c3, 3.1c3, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="pt"> |
||||
<pluralRule count="one">i = 0..1 @integer 0, 1 @decimal 0.0~1.5</pluralRule> |
||||
<pluralRule count="many">e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5 @integer 1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, … @decimal 1.0000001c6, 1.1c6, 2.0000001c6, 2.1c6, 3.0000001c6, 3.1c6, …</pluralRule> |
||||
<pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0001c3, 1.1c3, 2.0001c3, 2.1c3, 3.0001c3, 3.1c3, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ca it pt_PT vec"> |
||||
<pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule> |
||||
<pluralRule count="many">e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5 @integer 1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, … @decimal 1.0000001c6, 1.1c6, 2.0000001c6, 2.1c6, 3.0000001c6, 3.1c6, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0001c3, 1.1c3, 2.0001c3, 2.1c3, 3.0001c3, 3.1c3, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="es"> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="many">e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5 @integer 1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, … @decimal 1.0000001c6, 1.1c6, 2.0000001c6, 2.1c6, 3.0000001c6, 3.1c6, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0001c3, 1.1c3, 2.0001c3, 2.1c3, 3.0001c3, 3.1c3, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 4: one,two,few,other --> |
||||
|
||||
<pluralRules locales="gd"> |
||||
<pluralRule count="one">n = 1,11 @integer 1, 11 @decimal 1.0, 11.0, 1.00, 11.00, 1.000, 11.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n = 2,12 @integer 2, 12 @decimal 2.0, 12.0, 2.00, 12.00, 2.000, 12.000, 2.0000</pluralRule> |
||||
<pluralRule count="few">n = 3..10,13..19 @integer 3~10, 13~19 @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 3.00</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 20~34, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="sl"> |
||||
<pluralRule count="one">v = 0 and i % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, …</pluralRule> |
||||
<pluralRule count="two">v = 0 and i % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, …</pluralRule> |
||||
<pluralRule count="few">v = 0 and i % 100 = 3..4 or v != 0 @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="dsb hsb"> |
||||
<pluralRule count="one">v = 0 and i % 100 = 1 or f % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
<pluralRule count="two">v = 0 and i % 100 = 2 or f % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … @decimal 0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 10.2, 100.2, 1000.2, …</pluralRule> |
||||
<pluralRule count="few">v = 0 and i % 100 = 3..4 or f % 100 = 3..4 @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.3, 0.4, 1.3, 1.4, 2.3, 2.4, 3.3, 3.4, 4.3, 4.4, 5.3, 5.4, 6.3, 6.4, 7.3, 7.4, 10.3, 100.3, 1000.3, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 4: one,few,many,other --> |
||||
|
||||
<pluralRules locales="cs sk"> |
||||
<pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule> |
||||
<pluralRule count="few">i = 2..4 and v = 0 @integer 2~4</pluralRule> |
||||
<pluralRule count="many">v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="pl"> |
||||
<pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule> |
||||
<pluralRule count="few">v = 0 and i % 10 = 2..4 and i % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …</pluralRule> |
||||
<pluralRule count="many">v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule> |
||||
<pluralRule count="other"> @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="be"> |
||||
<pluralRule count="one">n % 10 = 1 and n % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, …</pluralRule> |
||||
<pluralRule count="few">n % 10 = 2..4 and n % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 2.0, 3.0, 4.0, 22.0, 23.0, 24.0, 32.0, 33.0, 102.0, 1002.0, …</pluralRule> |
||||
<pluralRule count="many">n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="other"> @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="lt"> |
||||
<pluralRule count="one">n % 10 = 1 and n % 100 != 11..19 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, …</pluralRule> |
||||
<pluralRule count="few">n % 10 = 2..9 and n % 100 != 11..19 @integer 2~9, 22~29, 102, 1002, … @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 22.0, 102.0, 1002.0, …</pluralRule> |
||||
<pluralRule count="many">f != 0 @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ru uk"> |
||||
<pluralRule count="one">v = 0 and i % 10 = 1 and i % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …</pluralRule> |
||||
<pluralRule count="few">v = 0 and i % 10 = 2..4 and i % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …</pluralRule> |
||||
<pluralRule count="many">v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule> |
||||
<pluralRule count="other"> @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 5: one,two,few,many,other --> |
||||
|
||||
<pluralRules locales="br"> |
||||
<pluralRule count="one">n % 10 = 1 and n % 100 != 11,71,91 @integer 1, 21, 31, 41, 51, 61, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 81.0, 101.0, 1001.0, …</pluralRule> |
||||
<pluralRule count="two">n % 10 = 2 and n % 100 != 12,72,92 @integer 2, 22, 32, 42, 52, 62, 82, 102, 1002, … @decimal 2.0, 22.0, 32.0, 42.0, 52.0, 62.0, 82.0, 102.0, 1002.0, …</pluralRule> |
||||
<pluralRule count="few">n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99 @integer 3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003, … @decimal 3.0, 4.0, 9.0, 23.0, 24.0, 29.0, 33.0, 34.0, 103.0, 1003.0, …</pluralRule> |
||||
<pluralRule count="many">n != 0 and n % 1000000 = 0 @integer 1000000, … @decimal 1000000.0, 1000000.00, 1000000.000, 1000000.0000, …</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 5~8, 10~20, 100, 1000, 10000, 100000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="mt"> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule> |
||||
<pluralRule count="few">n = 0 or n % 100 = 3..10 @integer 0, 3~10, 103~109, 1003, … @decimal 0.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, …</pluralRule> |
||||
<pluralRule count="many">n % 100 = 11..19 @integer 11~19, 111~117, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 20~35, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ga"> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule> |
||||
<pluralRule count="few">n = 3..6 @integer 3~6 @decimal 3.0, 4.0, 5.0, 6.0, 3.00, 4.00, 5.00, 6.00, 3.000, 4.000, 5.000, 6.000, 3.0000, 4.0000, 5.0000, 6.0000</pluralRule> |
||||
<pluralRule count="many">n = 7..10 @integer 7~10 @decimal 7.0, 8.0, 9.0, 10.0, 7.00, 8.00, 9.00, 10.00, 7.000, 8.000, 9.000, 10.000, 7.0000, 8.0000, 9.0000, 10.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="gv"> |
||||
<pluralRule count="one">v = 0 and i % 10 = 1 @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, …</pluralRule> |
||||
<pluralRule count="two">v = 0 and i % 10 = 2 @integer 2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, …</pluralRule> |
||||
<pluralRule count="few">v = 0 and i % 100 = 0,20,40,60,80 @integer 0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, …</pluralRule> |
||||
<pluralRule count="many">v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 3~10, 13~19, 23, 103, 1003, …</pluralRule> |
||||
</pluralRules> |
||||
|
||||
<!-- 6: zero,one,two,few,many,other --> |
||||
|
||||
<pluralRules locales="kw"> |
||||
<pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n % 100 = 2,22,42,62,82 or n % 1000 = 0 and n % 100000 = 1000..20000,40000,60000,80000 or n != 0 and n % 1000000 = 100000 @integer 2, 22, 42, 62, 82, 102, 122, 142, 1000, 10000, 100000, … @decimal 2.0, 22.0, 42.0, 62.0, 82.0, 102.0, 122.0, 142.0, 1000.0, 10000.0, 100000.0, …</pluralRule> |
||||
<pluralRule count="few">n % 100 = 3,23,43,63,83 @integer 3, 23, 43, 63, 83, 103, 123, 143, 1003, … @decimal 3.0, 23.0, 43.0, 63.0, 83.0, 103.0, 123.0, 143.0, 1003.0, …</pluralRule> |
||||
<pluralRule count="many">n != 1 and n % 100 = 1,21,41,61,81 @integer 21, 41, 61, 81, 101, 121, 141, 161, 1001, … @decimal 21.0, 41.0, 61.0, 81.0, 101.0, 121.0, 141.0, 161.0, 1001.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 4~19, 100, 1004, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.1, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="ar ars"> |
||||
<pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule> |
||||
<pluralRule count="few">n % 100 = 3..10 @integer 3~10, 103~110, 1003, … @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, …</pluralRule> |
||||
<pluralRule count="many">n % 100 = 11..99 @integer 11~26, 111, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, …</pluralRule> |
||||
<pluralRule count="other"> @integer 100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
<pluralRules locales="cy"> |
||||
<pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule> |
||||
<pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule> |
||||
<pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule> |
||||
<pluralRule count="few">n = 3 @integer 3 @decimal 3.0, 3.00, 3.000, 3.0000</pluralRule> |
||||
<pluralRule count="many">n = 6 @integer 6 @decimal 6.0, 6.00, 6.000, 6.0000</pluralRule> |
||||
<pluralRule count="other"> @integer 4, 5, 7~20, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule> |
||||
</pluralRules> |
||||
</plurals> |
||||
</supplementalData> |
@ -0,0 +1,443 @@
|
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
/** |
||||
* THIS CODE IS AUTOGENERATED BY './gradlew :resources:library:generatePluralRuleLists' |
||||
* DO NOT EDIT!!! |
||||
*/ |
||||
internal val cldrPluralRuleListIndexByLocale = mapOf( |
||||
"bm" to 0, |
||||
"bo" to 0, |
||||
"dz" to 0, |
||||
"hnj" to 0, |
||||
"id" to 0, |
||||
"ig" to 0, |
||||
"ii" to 0, |
||||
"in" to 0, |
||||
"ja" to 0, |
||||
"jbo" to 0, |
||||
"jv" to 0, |
||||
"jw" to 0, |
||||
"kde" to 0, |
||||
"kea" to 0, |
||||
"km" to 0, |
||||
"ko" to 0, |
||||
"lkt" to 0, |
||||
"lo" to 0, |
||||
"ms" to 0, |
||||
"my" to 0, |
||||
"nqo" to 0, |
||||
"osa" to 0, |
||||
"root" to 0, |
||||
"sah" to 0, |
||||
"ses" to 0, |
||||
"sg" to 0, |
||||
"su" to 0, |
||||
"th" to 0, |
||||
"to" to 0, |
||||
"tpi" to 0, |
||||
"vi" to 0, |
||||
"wo" to 0, |
||||
"yo" to 0, |
||||
"yue" to 0, |
||||
"zh" to 0, |
||||
"am" to 1, |
||||
"as" to 1, |
||||
"bn" to 1, |
||||
"doi" to 1, |
||||
"fa" to 1, |
||||
"gu" to 1, |
||||
"hi" to 1, |
||||
"kn" to 1, |
||||
"pcm" to 1, |
||||
"zu" to 1, |
||||
"ff" to 2, |
||||
"hy" to 2, |
||||
"kab" to 2, |
||||
"ast" to 3, |
||||
"de" to 3, |
||||
"en" to 3, |
||||
"et" to 3, |
||||
"fi" to 3, |
||||
"fy" to 3, |
||||
"gl" to 3, |
||||
"ia" to 3, |
||||
"io" to 3, |
||||
"ji" to 3, |
||||
"lij" to 3, |
||||
"nl" to 3, |
||||
"sc" to 3, |
||||
"scn" to 3, |
||||
"sv" to 3, |
||||
"sw" to 3, |
||||
"ur" to 3, |
||||
"yi" to 3, |
||||
"si" to 4, |
||||
"ak" to 5, |
||||
"bho" to 5, |
||||
"guw" to 5, |
||||
"ln" to 5, |
||||
"mg" to 5, |
||||
"nso" to 5, |
||||
"pa" to 5, |
||||
"ti" to 5, |
||||
"wa" to 5, |
||||
"tzm" to 6, |
||||
"af" to 7, |
||||
"an" to 7, |
||||
"asa" to 7, |
||||
"az" to 7, |
||||
"bal" to 7, |
||||
"bem" to 7, |
||||
"bez" to 7, |
||||
"bg" to 7, |
||||
"brx" to 7, |
||||
"ce" to 7, |
||||
"cgg" to 7, |
||||
"chr" to 7, |
||||
"ckb" to 7, |
||||
"dv" to 7, |
||||
"ee" to 7, |
||||
"el" to 7, |
||||
"eo" to 7, |
||||
"eu" to 7, |
||||
"fo" to 7, |
||||
"fur" to 7, |
||||
"gsw" to 7, |
||||
"ha" to 7, |
||||
"haw" to 7, |
||||
"hu" to 7, |
||||
"jgo" to 7, |
||||
"jmc" to 7, |
||||
"ka" to 7, |
||||
"kaj" to 7, |
||||
"kcg" to 7, |
||||
"kk" to 7, |
||||
"kkj" to 7, |
||||
"kl" to 7, |
||||
"ks" to 7, |
||||
"ksb" to 7, |
||||
"ku" to 7, |
||||
"ky" to 7, |
||||
"lb" to 7, |
||||
"lg" to 7, |
||||
"mas" to 7, |
||||
"mgo" to 7, |
||||
"ml" to 7, |
||||
"mn" to 7, |
||||
"mr" to 7, |
||||
"nah" to 7, |
||||
"nb" to 7, |
||||
"nd" to 7, |
||||
"ne" to 7, |
||||
"nn" to 7, |
||||
"nnh" to 7, |
||||
"no" to 7, |
||||
"nr" to 7, |
||||
"ny" to 7, |
||||
"nyn" to 7, |
||||
"om" to 7, |
||||
"or" to 7, |
||||
"os" to 7, |
||||
"pap" to 7, |
||||
"ps" to 7, |
||||
"rm" to 7, |
||||
"rof" to 7, |
||||
"rwk" to 7, |
||||
"saq" to 7, |
||||
"sd" to 7, |
||||
"sdh" to 7, |
||||
"seh" to 7, |
||||
"sn" to 7, |
||||
"so" to 7, |
||||
"sq" to 7, |
||||
"ss" to 7, |
||||
"ssy" to 7, |
||||
"st" to 7, |
||||
"syr" to 7, |
||||
"ta" to 7, |
||||
"te" to 7, |
||||
"teo" to 7, |
||||
"tig" to 7, |
||||
"tk" to 7, |
||||
"tn" to 7, |
||||
"tr" to 7, |
||||
"ts" to 7, |
||||
"ug" to 7, |
||||
"uz" to 7, |
||||
"ve" to 7, |
||||
"vo" to 7, |
||||
"vun" to 7, |
||||
"wae" to 7, |
||||
"xh" to 7, |
||||
"xog" to 7, |
||||
"da" to 8, |
||||
"is" to 9, |
||||
"mk" to 10, |
||||
"ceb" to 11, |
||||
"fil" to 11, |
||||
"tl" to 11, |
||||
"lv" to 12, |
||||
"prg" to 12, |
||||
"lag" to 13, |
||||
"ksh" to 14, |
||||
"blo" to 15, |
||||
"he" to 16, |
||||
"iw" to 16, |
||||
"iu" to 17, |
||||
"naq" to 17, |
||||
"sat" to 17, |
||||
"se" to 17, |
||||
"sma" to 17, |
||||
"smi" to 17, |
||||
"smj" to 17, |
||||
"smn" to 17, |
||||
"sms" to 17, |
||||
"shi" to 18, |
||||
"mo" to 19, |
||||
"ro" to 19, |
||||
"bs" to 20, |
||||
"hr" to 20, |
||||
"sh" to 20, |
||||
"sr" to 20, |
||||
"fr" to 21, |
||||
"pt" to 22, |
||||
"ca" to 23, |
||||
"it" to 23, |
||||
"pt_PT" to 23, |
||||
"vec" to 23, |
||||
"es" to 24, |
||||
"gd" to 25, |
||||
"sl" to 26, |
||||
"dsb" to 27, |
||||
"hsb" to 27, |
||||
"cs" to 28, |
||||
"sk" to 28, |
||||
"pl" to 29, |
||||
"be" to 30, |
||||
"lt" to 31, |
||||
"ru" to 32, |
||||
"uk" to 32, |
||||
"br" to 33, |
||||
"mt" to 34, |
||||
"ga" to 35, |
||||
"gv" to 36, |
||||
"kw" to 37, |
||||
"ar" to 38, |
||||
"ars" to 38, |
||||
"cy" to 39 |
||||
) |
||||
|
||||
internal val cldrPluralRuleLists = arrayOf( |
||||
arrayOf( |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 0 or n = 1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 0,1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 1 and v = 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 0,1 or i = 0 and f = 1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 0..1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 0..1 or n = 11..99", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1 or t != 0 and i = 0,1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "t = 0 and i % 10 = 1 and i % 100 != 11 or t % 10 = 1 and t % 100 != 11", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19", |
||||
PluralCategory.ONE to "n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "i = 0,1 and n != 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 1 and v = 0 or i = 0 and v != 0", |
||||
PluralCategory.TWO to "i = 2 and v = 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n = 2", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 0 or n = 1", |
||||
PluralCategory.FEW to "n = 2..10", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 1 and v = 0", |
||||
PluralCategory.FEW to "v != 0 or n = 0 or n != 1 and n % 100 = 1..19", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11", |
||||
PluralCategory.FEW to "v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 0,1", |
||||
PluralCategory.MANY to "e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 0..1", |
||||
PluralCategory.MANY to "e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 1 and v = 0", |
||||
PluralCategory.MANY to "e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.MANY to "e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1,11", |
||||
PluralCategory.TWO to "n = 2,12", |
||||
PluralCategory.FEW to "n = 3..10,13..19", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i % 100 = 1", |
||||
PluralCategory.TWO to "v = 0 and i % 100 = 2", |
||||
PluralCategory.FEW to "v = 0 and i % 100 = 3..4 or v != 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i % 100 = 1 or f % 100 = 1", |
||||
PluralCategory.TWO to "v = 0 and i % 100 = 2 or f % 100 = 2", |
||||
PluralCategory.FEW to "v = 0 and i % 100 = 3..4 or f % 100 = 3..4", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 1 and v = 0", |
||||
PluralCategory.FEW to "i = 2..4 and v = 0", |
||||
PluralCategory.MANY to "v != 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "i = 1 and v = 0", |
||||
PluralCategory.FEW to "v = 0 and i % 10 = 2..4 and i % 100 != 12..14", |
||||
PluralCategory.MANY to "v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n % 10 = 1 and n % 100 != 11", |
||||
PluralCategory.FEW to "n % 10 = 2..4 and n % 100 != 12..14", |
||||
PluralCategory.MANY to "n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n % 10 = 1 and n % 100 != 11..19", |
||||
PluralCategory.FEW to "n % 10 = 2..9 and n % 100 != 11..19", |
||||
PluralCategory.MANY to "f != 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i % 10 = 1 and i % 100 != 11", |
||||
PluralCategory.FEW to "v = 0 and i % 10 = 2..4 and i % 100 != 12..14", |
||||
PluralCategory.MANY to "v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n % 10 = 1 and n % 100 != 11,71,91", |
||||
PluralCategory.TWO to "n % 10 = 2 and n % 100 != 12,72,92", |
||||
PluralCategory.FEW to "n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99", |
||||
PluralCategory.MANY to "n != 0 and n % 1000000 = 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n = 2", |
||||
PluralCategory.FEW to "n = 0 or n % 100 = 3..10", |
||||
PluralCategory.MANY to "n % 100 = 11..19", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n = 2", |
||||
PluralCategory.FEW to "n = 3..6", |
||||
PluralCategory.MANY to "n = 7..10", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ONE to "v = 0 and i % 10 = 1", |
||||
PluralCategory.TWO to "v = 0 and i % 10 = 2", |
||||
PluralCategory.FEW to "v = 0 and i % 100 = 0,20,40,60,80", |
||||
PluralCategory.MANY to "v != 0", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n % 100 = 2,22,42,62,82 or n % 1000 = 0 and n % 100000 = 1000..20000,40000,60000,80000 or n != 0 and n % 1000000 = 100000", |
||||
PluralCategory.FEW to "n % 100 = 3,23,43,63,83", |
||||
PluralCategory.MANY to "n != 1 and n % 100 = 1,21,41,61,81", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n = 2", |
||||
PluralCategory.FEW to "n % 100 = 3..10", |
||||
PluralCategory.MANY to "n % 100 = 11..99", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
arrayOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n = 2", |
||||
PluralCategory.FEW to "n = 3", |
||||
PluralCategory.MANY to "n = 6", |
||||
PluralCategory.OTHER to "" |
||||
) |
||||
) |
@ -0,0 +1,26 @@
|
||||
/* |
||||
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
/** |
||||
* Plural categories defined in the [CLDR Language Plural Rules](https://cldr.unicode.org/index/cldr-spec/plural-rules). |
||||
*/ |
||||
internal enum class PluralCategory { |
||||
ZERO, |
||||
ONE, |
||||
TWO, |
||||
FEW, |
||||
MANY, |
||||
OTHER; |
||||
|
||||
companion object { |
||||
fun fromString(name: String): PluralCategory? { |
||||
return entries.firstOrNull { |
||||
it.name.equals(name, true) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,406 @@
|
||||
/* |
||||
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
import kotlin.math.absoluteValue |
||||
|
||||
internal class PluralRuleParseException(description: String, position: Int) : |
||||
Exception("Invalid syntax at position $position: $description") |
||||
|
||||
internal class PluralRule private constructor(val category: PluralCategory, private val condition: Condition) { |
||||
|
||||
constructor(category: PluralCategory, condition: String) : this(category, Condition.parse(condition)) |
||||
|
||||
fun appliesTo(n: Int): Boolean { |
||||
return condition.isFulfilled(n) |
||||
} |
||||
|
||||
private sealed class Condition { |
||||
abstract fun isFulfilled(n: Int): Boolean |
||||
|
||||
abstract fun simplifyForInteger(): Condition |
||||
|
||||
abstract fun equivalentForInteger(other: Condition): Boolean |
||||
|
||||
/** |
||||
* Plural operands defined in the [Unicode Locale Data Markup Language](https://unicode.org/reports/tr35/tr35-numbers.html#Plural_Operand_Meanings). |
||||
*/ |
||||
enum class Operand { |
||||
/** |
||||
* The absolute value of the source number. |
||||
*/ |
||||
N, |
||||
|
||||
/** |
||||
* The integer digits of the source number. |
||||
*/ |
||||
I, |
||||
|
||||
/** |
||||
* The number of visible fraction digits in the source number, *with* trailing zeros. |
||||
*/ |
||||
V, |
||||
|
||||
/** |
||||
* The number of visible fraction digits in the source number, *without* trailing zeros. |
||||
*/ |
||||
W, |
||||
|
||||
/** |
||||
* The visible fraction digits in the source number, *with* trailing zeros, expressed as an integer. |
||||
*/ |
||||
F, |
||||
|
||||
/** |
||||
* The visible fraction digits in the source number, *without* trailing zeros, expressed as an integer. |
||||
*/ |
||||
T, |
||||
|
||||
/** |
||||
* Compact decimal exponent value: exponent of the power of 10 used in compact decimal formatting. |
||||
*/ |
||||
C, |
||||
} |
||||
|
||||
class And( |
||||
private val left: Condition, |
||||
private val right: Condition, |
||||
) : Condition() { |
||||
override fun isFulfilled(n: Int): Boolean = left.isFulfilled(n) && right.isFulfilled(n) |
||||
|
||||
override fun simplifyForInteger(): Condition { |
||||
val leftSimplified = left.simplifyForInteger() |
||||
if (leftSimplified == False) return False |
||||
|
||||
val rightSimplified = right.simplifyForInteger() |
||||
when { |
||||
leftSimplified == True -> return rightSimplified |
||||
rightSimplified == False -> return False |
||||
rightSimplified == True -> return leftSimplified |
||||
} |
||||
|
||||
if (leftSimplified.equivalentForInteger(rightSimplified)) return leftSimplified |
||||
return And(leftSimplified, rightSimplified) |
||||
} |
||||
|
||||
override fun equivalentForInteger(other: Condition): Boolean { |
||||
if (this === other) return true |
||||
if (other !is And) return false |
||||
return left.equivalentForInteger(other.left) && right.equivalentForInteger(other.right) |
||||
} |
||||
|
||||
override fun toString(): String = "$left and $right" |
||||
} |
||||
|
||||
class Or( |
||||
private val left: Condition, |
||||
private val right: Condition, |
||||
) : Condition() { |
||||
override fun isFulfilled(n: Int): Boolean = left.isFulfilled(n) || right.isFulfilled(n) |
||||
|
||||
override fun simplifyForInteger(): Condition { |
||||
val leftSimplified = left.simplifyForInteger() |
||||
if (leftSimplified == True) return True |
||||
|
||||
val rightSimplified = right.simplifyForInteger() |
||||
when { |
||||
leftSimplified == False -> return rightSimplified |
||||
rightSimplified == True -> return True |
||||
rightSimplified == False -> return leftSimplified |
||||
} |
||||
|
||||
if (leftSimplified.equivalentForInteger(rightSimplified)) return leftSimplified |
||||
return Or(leftSimplified, rightSimplified) |
||||
} |
||||
|
||||
override fun equivalentForInteger(other: Condition): Boolean { |
||||
if (this === other) return true |
||||
if (other !is Or) return false |
||||
return left.equivalentForInteger(other.left) && right.equivalentForInteger(other.right) |
||||
} |
||||
|
||||
override fun toString(): String = "$left or $right" |
||||
} |
||||
|
||||
class Relation( |
||||
private val operand: Operand, |
||||
private val operandDivisor: Int?, |
||||
private val comparisonIsNegated: Boolean, |
||||
private val ranges: Array<IntRange>, |
||||
) : Condition() { |
||||
override fun isFulfilled(n: Int): Boolean { |
||||
val expressionOperandValue = when (operand) { |
||||
Operand.N, Operand.I -> n.absoluteValue |
||||
else -> 0 |
||||
} |
||||
val moduloAppliedValue = if (operandDivisor != null) { |
||||
expressionOperandValue % operandDivisor |
||||
} else { |
||||
expressionOperandValue |
||||
} |
||||
return ranges.any { moduloAppliedValue in it } != comparisonIsNegated |
||||
} |
||||
|
||||
override fun simplifyForInteger(): Condition { |
||||
return when (operand) { |
||||
Operand.N, Operand.I -> Relation( |
||||
Operand.N, |
||||
operandDivisor, |
||||
comparisonIsNegated, |
||||
ranges, |
||||
) |
||||
|
||||
else -> if (ranges.any { 0 in it } != comparisonIsNegated) True else False |
||||
} |
||||
} |
||||
|
||||
override fun equivalentForInteger(other: Condition): Boolean { |
||||
if (this === other) return true |
||||
if (other !is Relation) return false |
||||
if ((operand == Operand.N || operand == Operand.I) != (other.operand == Operand.N || other.operand == Operand.I)) return false |
||||
if (operandDivisor != other.operandDivisor) return false |
||||
if (comparisonIsNegated != other.comparisonIsNegated) return false |
||||
if (!ranges.contentEquals(other.ranges)) return false |
||||
return true |
||||
} |
||||
|
||||
override fun toString(): String { |
||||
return StringBuilder().run { |
||||
append(operand.name.lowercase()) |
||||
if (operandDivisor != null) { |
||||
append(" % ") |
||||
append(operandDivisor) |
||||
} |
||||
append(' ') |
||||
if (comparisonIsNegated) { |
||||
append('!') |
||||
} |
||||
append("= ") |
||||
var first = true |
||||
for (range in ranges) { |
||||
if (!first) { |
||||
append(',') |
||||
} |
||||
first = false |
||||
append(range.first) |
||||
if (range.first != range.last) { |
||||
append("..") |
||||
append(range.last) |
||||
} |
||||
} |
||||
toString() |
||||
} |
||||
} |
||||
} |
||||
|
||||
private object True : Condition() { |
||||
override fun isFulfilled(n: Int) = true |
||||
override fun simplifyForInteger() = this |
||||
override fun equivalentForInteger(other: Condition) = this == other |
||||
override fun toString(): String = "" |
||||
} |
||||
|
||||
private object False : Condition() { |
||||
override fun isFulfilled(n: Int) = false |
||||
override fun simplifyForInteger() = this |
||||
override fun equivalentForInteger(other: Condition) = this == other |
||||
override fun toString(): String = "(false)" |
||||
} |
||||
|
||||
private class Parser(private val description: String) { |
||||
private var currentIdx = 0 |
||||
|
||||
private fun eof() = currentIdx >= description.length |
||||
|
||||
private fun nextUnchecked() = description[currentIdx] |
||||
|
||||
private fun consumeWhitespaces() { |
||||
while (!eof() && nextUnchecked().isWhitespace()) { |
||||
currentIdx += 1 |
||||
} |
||||
} |
||||
|
||||
private fun raise(): Nothing = throw PluralRuleParseException(description, currentIdx + 1) |
||||
|
||||
private fun assert(condition: Boolean) { |
||||
if (!condition) raise() |
||||
} |
||||
|
||||
private fun peekNextOrNull() = description.getOrNull(currentIdx) |
||||
|
||||
private fun peekNext() = peekNextOrNull() ?: raise() |
||||
|
||||
private fun consumeNext(): Char { |
||||
val next = peekNext() |
||||
currentIdx += 1 |
||||
return next |
||||
} |
||||
|
||||
private fun consumeNextInt(): Int { |
||||
assert(peekNext().isDigit()) |
||||
var integerValue = 0 |
||||
var integerLastIdx = currentIdx |
||||
while (integerLastIdx < description.length && description[integerLastIdx].isDigit()) { |
||||
integerValue *= 10 |
||||
integerValue += description[integerLastIdx] - '0' |
||||
integerLastIdx += 1 |
||||
} |
||||
currentIdx = integerLastIdx |
||||
return integerValue |
||||
} |
||||
|
||||
fun parse(): Condition { |
||||
consumeWhitespaces() |
||||
if (eof()) return True |
||||
val condition = nextCondition() |
||||
consumeWhitespaces() |
||||
assert(eof()) |
||||
return condition |
||||
} |
||||
|
||||
/** |
||||
* Syntax: |
||||
* ``` |
||||
* condition = and_condition ('or' and_condition)* |
||||
* ``` |
||||
*/ |
||||
private fun nextCondition(): Condition { |
||||
var condition: Condition = nextAndCondition() |
||||
while (true) { |
||||
consumeWhitespaces() |
||||
if (peekNextOrNull() != 'o') break |
||||
consumeNext() |
||||
assert(consumeNext() == 'r') |
||||
condition = Or(condition, nextAndCondition()) |
||||
} |
||||
return condition |
||||
} |
||||
|
||||
/** |
||||
* Syntax: |
||||
* ``` |
||||
* and_condition = relation ('and' relation)* |
||||
* ``` |
||||
*/ |
||||
private fun nextAndCondition(): Condition { |
||||
var condition: Condition = nextRelation() |
||||
while (true) { |
||||
consumeWhitespaces() |
||||
if (peekNextOrNull() != 'a') break |
||||
consumeNext() |
||||
assert(consumeNext() == 'n') |
||||
assert(consumeNext() == 'd') |
||||
condition = And(condition, nextRelation()) |
||||
} |
||||
return condition |
||||
} |
||||
|
||||
/** |
||||
* Syntax: |
||||
* ``` |
||||
* relation = operand ('%' value)? ('=' | '!=') range_list |
||||
* ``` |
||||
*/ |
||||
fun nextRelation(): Relation { |
||||
val operand = nextOperand() |
||||
val divisor = nextModulusDivisor() |
||||
val negated = nextComparisonIsNegated() |
||||
val ranges = mutableListOf(nextRange()) |
||||
while (peekNextOrNull() == ',') { |
||||
consumeNext() |
||||
ranges.add(nextRange()) |
||||
} |
||||
// ranges is not empty here |
||||
return Relation(operand, divisor, negated, ranges.toTypedArray()) |
||||
} |
||||
|
||||
/** |
||||
* Syntax: |
||||
* ``` |
||||
* operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w' |
||||
* ``` |
||||
*/ |
||||
fun nextOperand(): Operand { |
||||
consumeWhitespaces() |
||||
return when (consumeNext()) { |
||||
'n' -> Operand.N |
||||
'i' -> Operand.I |
||||
'f' -> Operand.F |
||||
't' -> Operand.T |
||||
'v' -> Operand.V |
||||
'w' -> Operand.W |
||||
'c', 'e' -> Operand.C |
||||
else -> raise() |
||||
} |
||||
} |
||||
|
||||
fun nextModulusDivisor(): Int? { |
||||
consumeWhitespaces() |
||||
if (peekNext() == '%') { |
||||
consumeNext() |
||||
consumeWhitespaces() |
||||
return consumeNextInt() |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* Returns `true` for `!=`, `false` for `=`. |
||||
*/ |
||||
fun nextComparisonIsNegated(): Boolean { |
||||
consumeWhitespaces() |
||||
when (peekNext()) { |
||||
'!' -> { |
||||
consumeNext() |
||||
assert(consumeNext() == '=') |
||||
return true |
||||
} |
||||
|
||||
'=' -> { |
||||
consumeNext() |
||||
return false |
||||
} |
||||
|
||||
else -> raise() |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns `number..number` if the range is actually a value. |
||||
*/ |
||||
fun nextRange(): IntRange { |
||||
consumeWhitespaces() |
||||
val start = consumeNextInt() |
||||
if (peekNextOrNull() != '.') { |
||||
return start..start |
||||
} |
||||
consumeNext() |
||||
assert(consumeNext() == '.') |
||||
val endInclusive = consumeNextInt() |
||||
return start..endInclusive |
||||
} |
||||
} |
||||
|
||||
companion object { |
||||
/** |
||||
* Parses [description] as defined in the [Unicode Plural rules syntax](https://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax). |
||||
* For compact implementation, samples and keywords for backward compatibility are also not handled. You can |
||||
* find such keywords in the [Relations Examples](https://unicode.org/reports/tr35/tr35-numbers.html#Relations_Examples) section. |
||||
* ``` |
||||
* condition = and_condition ('or' and_condition)* |
||||
* and_condition = relation ('and' relation)* |
||||
* relation = operand ('%' value)? ('=' | '!=') range_list |
||||
* operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w' |
||||
* range_list = (range | value) (',' range_list)* |
||||
* range = value'..'value |
||||
* value = digit+ |
||||
* digit = [0-9] |
||||
* ``` |
||||
*/ |
||||
fun parse(description: String): Condition = Parser(description).parse().simplifyForInteger() |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,73 @@
|
||||
/* |
||||
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
import kotlinx.coroutines.CoroutineStart |
||||
import kotlinx.coroutines.Deferred |
||||
import kotlinx.coroutines.async |
||||
import kotlinx.coroutines.coroutineScope |
||||
import kotlinx.coroutines.sync.Mutex |
||||
import kotlinx.coroutines.sync.withLock |
||||
import org.jetbrains.compose.resources.InternalResourceApi |
||||
import org.jetbrains.compose.resources.LanguageQualifier |
||||
import org.jetbrains.compose.resources.RegionQualifier |
||||
|
||||
internal class PluralRuleList(private val rules: Array<PluralRule>) { |
||||
fun getCategory(quantity: Int): PluralCategory { |
||||
return rules.first { rule -> rule.appliesTo(quantity) }.category |
||||
} |
||||
|
||||
companion object { |
||||
private val cacheMutex = Mutex() |
||||
private val cache = Array<Deferred<PluralRuleList>?>(cldrPluralRuleLists.size) { null } |
||||
private val emptyList = PluralRuleList(emptyArray()) |
||||
|
||||
@OptIn(InternalResourceApi::class) |
||||
suspend fun getInstance( |
||||
languageQualifier: LanguageQualifier, |
||||
regionQualifier: RegionQualifier, |
||||
): PluralRuleList { |
||||
val cldrLocaleName = buildCldrLocaleName(languageQualifier, regionQualifier) ?: return emptyList |
||||
return getInstance(cldrLocaleName) |
||||
} |
||||
|
||||
suspend fun getInstance(cldrLocaleName: String): PluralRuleList { |
||||
val listIndex = cldrPluralRuleListIndexByLocale[cldrLocaleName]!! |
||||
return coroutineScope { |
||||
val deferred = cacheMutex.withLock { |
||||
if (cache[listIndex] == null) { |
||||
cache[listIndex] = async(start = CoroutineStart.LAZY) { |
||||
createInstance(listIndex) |
||||
} |
||||
} |
||||
cache[listIndex]!! |
||||
} |
||||
deferred.await() |
||||
} |
||||
} |
||||
|
||||
@OptIn(InternalResourceApi::class) |
||||
private fun buildCldrLocaleName( |
||||
languageQualifier: LanguageQualifier, |
||||
regionQualifier: RegionQualifier, |
||||
): String? { |
||||
val localeWithRegion = languageQualifier.language + "_" + regionQualifier.region |
||||
if (cldrPluralRuleListIndexByLocale.containsKey(localeWithRegion)) { |
||||
return localeWithRegion |
||||
} |
||||
if (cldrPluralRuleListIndexByLocale.containsKey(languageQualifier.language)) { |
||||
return languageQualifier.language |
||||
} |
||||
return null |
||||
} |
||||
|
||||
private fun createInstance(cldrPluralRuleListIndex: Int): PluralRuleList { |
||||
val cldrPluralRuleList = cldrPluralRuleLists[cldrPluralRuleListIndex] |
||||
val pluralRules = cldrPluralRuleList.map { PluralRule(it.first, it.second) } |
||||
return PluralRuleList(pluralRules.toTypedArray()) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,933 @@
|
||||
package org.jetbrains.compose.resources.plural |
||||
|
||||
/** |
||||
* THIS CODE IS AUTOGENERATED BY './gradlew :resources:library:generatePluralRuleLists' |
||||
* DO NOT EDIT!!! |
||||
*/ |
||||
internal val cldrPluralRuleIntegerSamples = arrayOf( |
||||
"bm" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bo" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"dz" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"hnj" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"id" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ig" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ii" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"in" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ja" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"jbo" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"jv" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"jw" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kde" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kea" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"km" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ko" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"lkt" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"lo" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ms" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"my" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nqo" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"osa" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"root" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sah" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ses" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sg" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"su" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"th" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"to" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"tpi" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"vi" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"wo" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"yo" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"yue" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"zh" to arrayOf( |
||||
PluralCategory.OTHER to "0~15, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"am" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"as" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bn" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"doi" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"fa" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"gu" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"hi" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kn" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"pcm" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"zu" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ff" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"hy" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kab" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ast" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"de" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"en" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"et" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"fi" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"fy" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"gl" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ia" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"io" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ji" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"lij" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nl" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sc" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"scn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sv" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sw" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ur" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"yi" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"si" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ak" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bho" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"guw" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ln" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mg" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nso" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"pa" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ti" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"wa" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"tzm" to arrayOf( |
||||
PluralCategory.ONE to "0, 1, 11~24", |
||||
PluralCategory.OTHER to "2~10, 100~106, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"af" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"an" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"asa" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"az" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bal" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bem" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bez" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bg" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"brx" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ce" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"cgg" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"chr" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ckb" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"dv" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ee" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"el" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"eo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"eu" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"fo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"fur" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"gsw" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ha" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"haw" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"hu" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"jgo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"jmc" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ka" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kaj" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kcg" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kk" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kkj" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"kl" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ks" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ksb" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ku" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ky" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"lb" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"lg" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mas" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mgo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ml" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mr" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nah" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nb" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nd" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ne" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nnh" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"no" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nr" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ny" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"nyn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"om" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"or" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"os" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"pap" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ps" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"rm" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"rof" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"rwk" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"saq" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sd" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sdh" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"seh" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"so" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sq" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ss" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ssy" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"st" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"syr" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ta" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"te" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"teo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"tig" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"tk" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"tn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"tr" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ts" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ug" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"uz" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ve" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"vo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"vun" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"wae" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"xh" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"xog" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"da" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"is" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mk" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ceb" to arrayOf( |
||||
PluralCategory.ONE to "0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, …" |
||||
), |
||||
"fil" to arrayOf( |
||||
PluralCategory.ONE to "0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, …" |
||||
), |
||||
"tl" to arrayOf( |
||||
PluralCategory.ONE to "0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, …" |
||||
), |
||||
"lv" to arrayOf( |
||||
PluralCategory.ZERO to "0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.OTHER to "2~9, 22~29, 102, 1002, …" |
||||
), |
||||
"prg" to arrayOf( |
||||
PluralCategory.ZERO to "0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.OTHER to "2~9, 22~29, 102, 1002, …" |
||||
), |
||||
"lag" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ksh" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"blo" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.OTHER to "2~16, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"he" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"iw" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"iu" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"naq" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sat" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"se" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sma" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"smi" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"smj" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"smn" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sms" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.OTHER to "0, 3~17, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"shi" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.FEW to "2~10", |
||||
PluralCategory.OTHER to "11~26, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"mo" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.FEW to "0, 2~16, 101, 1001, …", |
||||
PluralCategory.OTHER to "20~35, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ro" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.FEW to "0, 2~16, 101, 1001, …", |
||||
PluralCategory.OTHER to "20~35, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"bs" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"hr" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sh" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sr" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"fr" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"pt" to arrayOf( |
||||
PluralCategory.ONE to "0, 1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "2~17, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"ca" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"it" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"pt_PT" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"vec" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"es" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.MANY to "1000000, 1c6, 2c6, 3c6, 4c6, 5c6, 6c6, …", |
||||
PluralCategory.OTHER to "0, 2~16, 100, 1000, 10000, 100000, 1c3, 2c3, 3c3, 4c3, 5c3, 6c3, …" |
||||
), |
||||
"gd" to arrayOf( |
||||
PluralCategory.ONE to "1, 11", |
||||
PluralCategory.TWO to "2, 12", |
||||
PluralCategory.FEW to "3~10, 13~19", |
||||
PluralCategory.OTHER to "0, 20~34, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sl" to arrayOf( |
||||
PluralCategory.ONE to "1, 101, 201, 301, 401, 501, 601, 701, 1001, …", |
||||
PluralCategory.TWO to "2, 102, 202, 302, 402, 502, 602, 702, 1002, …", |
||||
PluralCategory.FEW to "3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"dsb" to arrayOf( |
||||
PluralCategory.ONE to "1, 101, 201, 301, 401, 501, 601, 701, 1001, …", |
||||
PluralCategory.TWO to "2, 102, 202, 302, 402, 502, 602, 702, 1002, …", |
||||
PluralCategory.FEW to "3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"hsb" to arrayOf( |
||||
PluralCategory.ONE to "1, 101, 201, 301, 401, 501, 601, 701, 1001, …", |
||||
PluralCategory.TWO to "2, 102, 202, 302, 402, 502, 602, 702, 1002, …", |
||||
PluralCategory.FEW to "3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, …", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"cs" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.FEW to "2~4", |
||||
PluralCategory.MANY to "", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"sk" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.FEW to "2~4", |
||||
PluralCategory.MANY to "", |
||||
PluralCategory.OTHER to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"pl" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.MANY to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
"be" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.MANY to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
"lt" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~9, 22~29, 102, 1002, …", |
||||
PluralCategory.MANY to "", |
||||
PluralCategory.OTHER to "0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ru" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.MANY to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
"uk" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …", |
||||
PluralCategory.FEW to "2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …", |
||||
PluralCategory.MANY to "0, 5~19, 100, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.OTHER to "" |
||||
), |
||||
"br" to arrayOf( |
||||
PluralCategory.ONE to "1, 21, 31, 41, 51, 61, 81, 101, 1001, …", |
||||
PluralCategory.TWO to "2, 22, 32, 42, 52, 62, 82, 102, 1002, …", |
||||
PluralCategory.FEW to "3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003, …", |
||||
PluralCategory.MANY to "1000000, …", |
||||
PluralCategory.OTHER to "0, 5~8, 10~20, 100, 1000, 10000, 100000, …" |
||||
), |
||||
"mt" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.FEW to "0, 3~10, 103~109, 1003, …", |
||||
PluralCategory.MANY to "11~19, 111~117, 1011, …", |
||||
PluralCategory.OTHER to "20~35, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ga" to arrayOf( |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.FEW to "3~6", |
||||
PluralCategory.MANY to "7~10", |
||||
PluralCategory.OTHER to "0, 11~25, 100, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"gv" to arrayOf( |
||||
PluralCategory.ONE to "1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, …", |
||||
PluralCategory.TWO to "2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, …", |
||||
PluralCategory.FEW to "0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, …", |
||||
PluralCategory.MANY to "", |
||||
PluralCategory.OTHER to "3~10, 13~19, 23, 103, 1003, …" |
||||
), |
||||
"kw" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2, 22, 42, 62, 82, 102, 122, 142, 1000, 10000, 100000, …", |
||||
PluralCategory.FEW to "3, 23, 43, 63, 83, 103, 123, 143, 1003, …", |
||||
PluralCategory.MANY to "21, 41, 61, 81, 101, 121, 141, 161, 1001, …", |
||||
PluralCategory.OTHER to "4~19, 100, 1004, 1000000, …" |
||||
), |
||||
"ar" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.FEW to "3~10, 103~110, 1003, …", |
||||
PluralCategory.MANY to "11~26, 111, 1011, …", |
||||
PluralCategory.OTHER to "100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"ars" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.FEW to "3~10, 103~110, 1003, …", |
||||
PluralCategory.MANY to "11~26, 111, 1011, …", |
||||
PluralCategory.OTHER to "100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, …" |
||||
), |
||||
"cy" to arrayOf( |
||||
PluralCategory.ZERO to "0", |
||||
PluralCategory.ONE to "1", |
||||
PluralCategory.TWO to "2", |
||||
PluralCategory.FEW to "3", |
||||
PluralCategory.MANY to "6", |
||||
PluralCategory.OTHER to "4, 5, 7~20, 100, 1000, 10000, 100000, 1000000, …" |
||||
) |
||||
) |
@ -0,0 +1,143 @@
|
||||
/* |
||||
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.resources |
||||
|
||||
import kotlinx.coroutines.test.runTest |
||||
import org.jetbrains.compose.resources.plural.* |
||||
import org.jetbrains.compose.resources.plural.PluralCategory |
||||
import org.jetbrains.compose.resources.plural.PluralRuleList |
||||
import kotlin.test.* |
||||
|
||||
/** |
||||
* Tests Unicode CLDR pluralization rules. |
||||
*/ |
||||
class PluralRulesTest { |
||||
/** |
||||
* Tests the actual language pluralization rules with the integer samples given by Unicode. |
||||
*/ |
||||
@Test |
||||
fun testIntegerSamples() = runTest { |
||||
for ((locale, samplesByCategory) in cldrPluralRuleIntegerSamples) { |
||||
val pluralRuleList = PluralRuleList.getInstance(locale) |
||||
for ((category, samples) in samplesByCategory) { |
||||
for (sample in parsePluralSamples(samples)) { |
||||
assertEquals(category, pluralRuleList.getCategory(sample)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun testOrCondition() { |
||||
val pluralRuleList = pluralRuleListOf( |
||||
PluralCategory.ONE to "n = 15 or n = 24" |
||||
) |
||||
repeat(30) { |
||||
if (it == 15 || it == 24) { |
||||
assertEquals(PluralCategory.ONE, pluralRuleList.getCategory(it)) |
||||
} else { |
||||
assertEquals(PluralCategory.OTHER, pluralRuleList.getCategory(it)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun testAndCondition() { |
||||
val pluralRuleList = pluralRuleListOf( |
||||
PluralCategory.ONE to "n = 15 and n = 24" |
||||
) |
||||
repeat(30) { |
||||
assertEquals(PluralCategory.OTHER, pluralRuleList.getCategory(it)) |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun testModulus() { |
||||
val pluralRuleList = pluralRuleListOf( |
||||
PluralCategory.ONE to "n % 3 = 2" |
||||
) |
||||
repeat(30) { |
||||
if (it % 3 == 2) { |
||||
assertEquals(PluralCategory.ONE, pluralRuleList.getCategory(it)) |
||||
} else { |
||||
assertEquals(PluralCategory.OTHER, pluralRuleList.getCategory(it)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun testRange() { |
||||
val pluralRuleList = pluralRuleListOf( |
||||
PluralCategory.ONE to "n = 2..3,5,10..24" |
||||
) |
||||
repeat(30) { |
||||
if (it in 2..3 || it == 5 || it in 10..24) { |
||||
assertEquals(PluralCategory.ONE, pluralRuleList.getCategory(it)) |
||||
} else { |
||||
assertEquals(PluralCategory.OTHER, pluralRuleList.getCategory(it)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun testMultipleRules() { |
||||
val pluralRuleList = pluralRuleListOf( |
||||
PluralCategory.ZERO to "n = 0", |
||||
PluralCategory.ONE to "n = 1", |
||||
PluralCategory.TWO to "n = 20", |
||||
PluralCategory.FEW to "n = 300", |
||||
PluralCategory.MANY to "n = 400", |
||||
) |
||||
repeat(500) { |
||||
val expected = when (it) { |
||||
0 -> PluralCategory.ZERO |
||||
1 -> PluralCategory.ONE |
||||
20 -> PluralCategory.TWO |
||||
300 -> PluralCategory.FEW |
||||
400 -> PluralCategory.MANY |
||||
else -> PluralCategory.OTHER |
||||
} |
||||
assertEquals(expected, pluralRuleList.getCategory(it)) |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun testOperandValues() { |
||||
pluralRuleListOf( |
||||
PluralCategory.ONE to "n = 1" |
||||
).run { |
||||
assertEquals(PluralCategory.OTHER, getCategory(-3)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(-2)) |
||||
assertEquals(PluralCategory.ONE, getCategory(-1)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(0)) |
||||
assertEquals(PluralCategory.ONE, getCategory(1)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(2)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(3)) |
||||
} |
||||
|
||||
pluralRuleListOf( |
||||
PluralCategory.ONE to "i = 1" |
||||
).run { |
||||
assertEquals(PluralCategory.OTHER, getCategory(-3)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(-2)) |
||||
assertEquals(PluralCategory.ONE, getCategory(-1)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(0)) |
||||
assertEquals(PluralCategory.ONE, getCategory(1)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(2)) |
||||
assertEquals(PluralCategory.OTHER, getCategory(3)) |
||||
} |
||||
|
||||
for (condition in arrayOf("v = 0", "w = 0", "f = 0", "t = 0", "e = 0")) { |
||||
pluralRuleListOf( |
||||
PluralCategory.ONE to condition |
||||
).run { |
||||
for (idx in -100..100) { |
||||
assertEquals(PluralCategory.ONE, getCategory(idx)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,8 +1,42 @@
|
||||
package org.jetbrains.compose.resources |
||||
|
||||
import org.jetbrains.compose.resources.plural.PluralCategory |
||||
import org.jetbrains.compose.resources.plural.PluralRule |
||||
import org.jetbrains.compose.resources.plural.PluralRuleList |
||||
|
||||
@OptIn(InternalResourceApi::class, ExperimentalResourceApi::class) |
||||
internal fun TestStringResource(key: String) = StringResource( |
||||
"STRING:$key", |
||||
key, |
||||
setOf(ResourceItem(emptySet(), "strings.xml")) |
||||
) |
||||
) |
||||
|
||||
@OptIn(InternalResourceApi::class, ExperimentalResourceApi::class) |
||||
internal fun TestPluralStringResource(key: String) = PluralStringResource( |
||||
"PLURALS:$key", |
||||
key, |
||||
setOf(ResourceItem(emptySet(), "strings.xml")) |
||||
) |
||||
|
||||
internal fun parsePluralSamples(samples: String): List<Int> { |
||||
return samples.split(',').flatMap { |
||||
val range = it.trim() |
||||
when { |
||||
range.isEmpty() -> emptyList() |
||||
range in arrayOf("…", "...") -> emptyList() |
||||
// ignore numbers in compact exponent format |
||||
range.contains('c') || range.contains('e') -> emptyList() |
||||
range.contains('~') -> { |
||||
val (start, endInclusive) = range.split('~') |
||||
return@flatMap (start.toInt()..endInclusive.toInt()).toList() |
||||
} |
||||
|
||||
else -> listOf(range.toInt()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
internal fun pluralRuleListOf(vararg rules: Pair<PluralCategory, String>): PluralRuleList { |
||||
val pluralRules = rules.map { PluralRule(it.first, it.second) } + PluralRule(PluralCategory.OTHER, "") |
||||
return PluralRuleList(pluralRules.toTypedArray()) |
||||
} |
@ -0,0 +1,26 @@
|
||||
@file:OptIn(org.jetbrains.compose.resources.InternalResourceApi::class) |
||||
|
||||
package my.lib.res |
||||
|
||||
import kotlin.OptIn |
||||
import org.jetbrains.compose.resources.ExperimentalResourceApi |
||||
import org.jetbrains.compose.resources.PluralStringResource |
||||
|
||||
@ExperimentalResourceApi |
||||
private object Plurals0 { |
||||
public val numberOfSongsAvailable: PluralStringResource by |
||||
lazy { init_numberOfSongsAvailable() } |
||||
} |
||||
|
||||
@ExperimentalResourceApi |
||||
public val Res.plurals.numberOfSongsAvailable: PluralStringResource |
||||
get() = Plurals0.numberOfSongsAvailable |
||||
|
||||
@ExperimentalResourceApi |
||||
private fun init_numberOfSongsAvailable(): PluralStringResource = |
||||
org.jetbrains.compose.resources.PluralStringResource( |
||||
"plurals:numberOfSongsAvailable", "numberOfSongsAvailable", |
||||
setOf( |
||||
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"), |
||||
) |
||||
) |
@ -0,0 +1,26 @@
|
||||
@file:OptIn(org.jetbrains.compose.resources.InternalResourceApi::class) |
||||
|
||||
package app.group.resources_test.generated.resources |
||||
|
||||
import kotlin.OptIn |
||||
import org.jetbrains.compose.resources.ExperimentalResourceApi |
||||
import org.jetbrains.compose.resources.PluralStringResource |
||||
|
||||
@ExperimentalResourceApi |
||||
private object Plurals0 { |
||||
public val numberOfSongsAvailable: PluralStringResource by |
||||
lazy { init_numberOfSongsAvailable() } |
||||
} |
||||
|
||||
@ExperimentalResourceApi |
||||
internal val Res.plurals.numberOfSongsAvailable: PluralStringResource |
||||
get() = Plurals0.numberOfSongsAvailable |
||||
|
||||
@ExperimentalResourceApi |
||||
private fun init_numberOfSongsAvailable(): PluralStringResource = |
||||
org.jetbrains.compose.resources.PluralStringResource( |
||||
"plurals:numberOfSongsAvailable", "numberOfSongsAvailable", |
||||
setOf( |
||||
org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"), |
||||
) |
||||
) |
Loading…
Reference in new issue