001/* 002 * Copyright 2017-2022 Product Mog LLC, 2022-2026 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.lokalized; 018 019import com.lokalized.Maps.MapEntry; 020import org.jspecify.annotations.NonNull; 021import org.jspecify.annotations.Nullable; 022 023import java.math.BigDecimal; 024import java.math.BigInteger; 025import java.math.RoundingMode; 026import java.text.Collator; 027import java.util.Arrays; 028import java.util.Collections; 029import java.util.HashMap; 030import java.util.Locale; 031import java.util.Map; 032import java.util.Optional; 033import java.util.SortedMap; 034import java.util.SortedSet; 035import java.util.TreeSet; 036import java.util.function.Function; 037import java.util.stream.Collectors; 038 039import static com.lokalized.NumberUtils.equal; 040import static com.lokalized.NumberUtils.inRange; 041import static com.lokalized.NumberUtils.inSet; 042import static com.lokalized.NumberUtils.notEqual; 043import static com.lokalized.NumberUtils.notInRange; 044import static com.lokalized.NumberUtils.notInSet; 045import static java.lang.String.format; 046import static java.util.Objects.requireNonNull; 047 048/** 049 * Language plural cardinality forms. 050 * <p> 051 * For example, English has two: {@code 1 dog, 2 dogs}, while Welsh has many: {@code 0 cŵn, 1 ci, 2 gi, 3 chi, 4 ci}. 052 * <p> 053 * See the <a href="http://cldr.unicode.org/index/cldr-spec/plural-rules">Unicode Common Locale Data Repository</a> 054 * and its <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">Language Plural Rules</a> for details. 055 * <p> 056 * Per the CLDR: 057 * <blockquote> 058 * These categories are only mnemonics -- the names don't necessarily imply the exact contents of the category. 059 * For example, for both English and French the number 1 has the category one (singular). 060 * <p> 061 * In English, every other number has a plural form, and is given the category other. 062 * French is similar, except that the number 0 also has the category one and not other or zero, because the form of 063 * units qualified by 0 is also singular. 064 * <p> 065 * This is worth emphasizing: A common mistake is to think that "one" is only for only the number 1. 066 * Instead, "one" is a category for any number that behaves like 1. So in some languages, for example, 067 * one → numbers that end in "1" (like 1, 21, 151) but that don't end in 11 (like "11, 111, 10311). 068 * </blockquote> 069 * 070 * @author <a href="https://revetkn.com">Mark Allen</a> 071 */ 072public enum Cardinality implements LanguageForm { 073 /** 074 * Normally the form used with 0, if it is limited to numbers whose integer values end with 0. 075 * <p> 076 * For example: the Welsh {@code 0 cŵn, 0 cathod} means {@code 0 dogs, 0 cats} in English. 077 */ 078 ZERO, 079 /** 080 * The form used with 1. 081 * <p> 082 * For example: the Welsh {@code 1 ci, 1 gath} means {@code 1 dog, 1 cat} in English. 083 */ 084 ONE, 085 /** 086 * Normally the form used with 2, if it is limited to numbers whose integer values end with 2. 087 * <p> 088 * For example: the Welsh {@code 2 gi, 2 gath} means {@code 2 dogs, 2 cats} in English. 089 */ 090 TWO, 091 /** 092 * The form that falls between {@code TWO} and {@code MANY}. 093 * <p> 094 * For example: the Welsh {@code 3 chi, 3 cath} means {@code 3 dogs, 3 cats} in English. 095 */ 096 FEW, 097 /** 098 * The form that falls between {@code FEW} and {@code OTHER}. 099 * <p> 100 * For example: the Welsh {@code 6 chi, 6 chath} means {@code 6 dogs, 6 cats} in English. 101 */ 102 MANY, 103 /** 104 * General "catchall" form which comprises any cases not handled by the other forms. 105 * <p> 106 * For example: the Welsh {@code 4 ci, 4 cath} means {@code 4 dogs, 4 cats} in English. 107 */ 108 OTHER; 109 110 @NonNull 111 private static final BigInteger BIG_INTEGER_0; 112 @NonNull 113 private static final BigInteger BIG_INTEGER_1; 114 @NonNull 115 private static final BigInteger BIG_INTEGER_2; 116 @NonNull 117 private static final BigInteger BIG_INTEGER_3; 118 @NonNull 119 private static final BigInteger BIG_INTEGER_4; 120 @NonNull 121 private static final BigInteger BIG_INTEGER_5; 122 @NonNull 123 private static final BigInteger BIG_INTEGER_6; 124 @NonNull 125 private static final BigInteger BIG_INTEGER_9; 126 @NonNull 127 private static final BigInteger BIG_INTEGER_10; 128 @NonNull 129 private static final BigInteger BIG_INTEGER_11; 130 @NonNull 131 private static final BigInteger BIG_INTEGER_12; 132 @NonNull 133 private static final BigInteger BIG_INTEGER_14; 134 @NonNull 135 private static final BigInteger BIG_INTEGER_19; 136 @NonNull 137 private static final BigInteger BIG_INTEGER_20; 138 @NonNull 139 private static final BigInteger BIG_INTEGER_40; 140 @NonNull 141 private static final BigInteger BIG_INTEGER_60; 142 @NonNull 143 private static final BigInteger BIG_INTEGER_80; 144 @NonNull 145 private static final BigInteger BIG_INTEGER_100; 146 147 @NonNull 148 private static final BigDecimal BIG_DECIMAL_0; 149 @NonNull 150 private static final BigDecimal BIG_DECIMAL_1; 151 @NonNull 152 private static final BigDecimal BIG_DECIMAL_2; 153 @NonNull 154 private static final BigDecimal BIG_DECIMAL_3; 155 @NonNull 156 private static final BigDecimal BIG_DECIMAL_4; 157 @NonNull 158 private static final BigDecimal BIG_DECIMAL_5; 159 @NonNull 160 private static final BigDecimal BIG_DECIMAL_6; 161 @NonNull 162 private static final BigDecimal BIG_DECIMAL_7; 163 @NonNull 164 private static final BigDecimal BIG_DECIMAL_9; 165 @NonNull 166 private static final BigDecimal BIG_DECIMAL_10; 167 @NonNull 168 private static final BigDecimal BIG_DECIMAL_11; 169 @NonNull 170 private static final BigDecimal BIG_DECIMAL_12; 171 @NonNull 172 private static final BigDecimal BIG_DECIMAL_13; 173 @NonNull 174 private static final BigDecimal BIG_DECIMAL_14; 175 @NonNull 176 private static final BigDecimal BIG_DECIMAL_19; 177 @NonNull 178 private static final BigDecimal BIG_DECIMAL_70; 179 @NonNull 180 private static final BigDecimal BIG_DECIMAL_71; 181 @NonNull 182 private static final BigDecimal BIG_DECIMAL_72; 183 @NonNull 184 private static final BigDecimal BIG_DECIMAL_79; 185 @NonNull 186 private static final BigDecimal BIG_DECIMAL_90; 187 @NonNull 188 private static final BigDecimal BIG_DECIMAL_91; 189 @NonNull 190 private static final BigDecimal BIG_DECIMAL_92; 191 @NonNull 192 private static final BigDecimal BIG_DECIMAL_99; 193 @NonNull 194 private static final BigDecimal BIG_DECIMAL_100; 195 @NonNull 196 private static final BigDecimal BIG_DECIMAL_1_000_000; 197 198 @NonNull 199 static final Map<@NonNull String, @NonNull Cardinality> CARDINALITIES_BY_NAME; 200 201 static { 202 BIG_INTEGER_0 = BigInteger.ZERO; 203 BIG_INTEGER_1 = BigInteger.ONE; 204 BIG_INTEGER_2 = BigInteger.valueOf(2); 205 BIG_INTEGER_3 = BigInteger.valueOf(3); 206 BIG_INTEGER_4 = BigInteger.valueOf(4); 207 BIG_INTEGER_5 = BigInteger.valueOf(5); 208 BIG_INTEGER_6 = BigInteger.valueOf(6); 209 BIG_INTEGER_9 = BigInteger.valueOf(9); 210 BIG_INTEGER_10 = BigInteger.TEN; 211 BIG_INTEGER_11 = BigInteger.valueOf(11); 212 BIG_INTEGER_12 = BigInteger.valueOf(12); 213 BIG_INTEGER_14 = BigInteger.valueOf(14); 214 BIG_INTEGER_19 = BigInteger.valueOf(19); 215 BIG_INTEGER_20 = BigInteger.valueOf(20); 216 BIG_INTEGER_40 = BigInteger.valueOf(40); 217 BIG_INTEGER_60 = BigInteger.valueOf(60); 218 BIG_INTEGER_80 = BigInteger.valueOf(80); 219 BIG_INTEGER_100 = BigInteger.valueOf(100); 220 221 BIG_DECIMAL_0 = BigDecimal.ZERO; 222 BIG_DECIMAL_1 = BigDecimal.ONE; 223 BIG_DECIMAL_2 = BigDecimal.valueOf(2); 224 BIG_DECIMAL_3 = BigDecimal.valueOf(3); 225 BIG_DECIMAL_4 = BigDecimal.valueOf(4); 226 BIG_DECIMAL_5 = BigDecimal.valueOf(5); 227 BIG_DECIMAL_6 = BigDecimal.valueOf(6); 228 BIG_DECIMAL_7 = BigDecimal.valueOf(7); 229 BIG_DECIMAL_9 = BigDecimal.valueOf(9); 230 BIG_DECIMAL_10 = BigDecimal.TEN; 231 BIG_DECIMAL_11 = BigDecimal.valueOf(11); 232 BIG_DECIMAL_12 = BigDecimal.valueOf(12); 233 BIG_DECIMAL_13 = BigDecimal.valueOf(13); 234 BIG_DECIMAL_14 = BigDecimal.valueOf(14); 235 BIG_DECIMAL_19 = BigDecimal.valueOf(19); 236 BIG_DECIMAL_70 = BigDecimal.valueOf(70); 237 BIG_DECIMAL_71 = BigDecimal.valueOf(71); 238 BIG_DECIMAL_72 = BigDecimal.valueOf(72); 239 BIG_DECIMAL_79 = BigDecimal.valueOf(79); 240 BIG_DECIMAL_90 = BigDecimal.valueOf(90); 241 BIG_DECIMAL_91 = BigDecimal.valueOf(91); 242 BIG_DECIMAL_92 = BigDecimal.valueOf(92); 243 BIG_DECIMAL_99 = BigDecimal.valueOf(99); 244 BIG_DECIMAL_100 = BigDecimal.valueOf(100); 245 BIG_DECIMAL_1_000_000 = BigDecimal.valueOf(1_000_000); 246 247 CARDINALITIES_BY_NAME = Collections.unmodifiableMap(Arrays.stream( 248 Cardinality.values()).collect(Collectors.toMap(cardinality -> cardinality.name(), cardinality -> cardinality))); 249 } 250 251 /** 252 * Gets an appropriate plural cardinality for the given number and locale. 253 * <p> 254 * Negative numbers are evaluated using their absolute value. 255 * <p> 256 * When determining cardinality, the decimal places of {@code number} will be computed and used. 257 * Note that if trailing zeroes are important, e.g. {@code 1.00} instead of {@code 1}, you must either specify a {@link BigDecimal} with appropriate 258 * scale or supply a non-null {@code visibleDecimalPlaces} value. 259 * <p> 260 * If you do not provide a {@link BigDecimal} and wish to manually specify the number of visible decimals, use {@link #forNumber(Number, Integer, Locale)} instead. 261 * <p> 262 * See the <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">CLDR Language Plural Rules</a> 263 * for further details. 264 * 265 * @param number the number that drives pluralization, not null 266 * @param locale the locale that drives pluralization, not null 267 * @return an appropriate plural cardinality, not null 268 * @throws UnsupportedLocaleException if the locale is not supported 269 */ 270 @NonNull 271 public static Cardinality forNumber(@NonNull Number number, @NonNull Locale locale) { 272 requireNonNull(number); 273 requireNonNull(locale); 274 275 return forNumber(number, null, locale); 276 } 277 278 /** 279 * Gets an appropriate plural cardinality for the given number, visible decimal places, and locale. 280 * <p> 281 * Negative numbers are evaluated using their absolute value. 282 * <p> 283 * If {@code visibleDecimalPlaces} is null, then the decimal places of {@code number} will be computed and used. 284 * Note that if trailing zeroes are important, e.g. {@code 1.00} instead of {@code 1}, you must either specify a {@link BigDecimal} with appropriate 285 * scale or supply a non-null {@code visibleDecimalPlaces} value. 286 * <p> 287 * See the <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">CLDR Language Plural Rules</a> 288 * for further details. 289 * 290 * @param number the number that drives pluralization, not null 291 * @param visibleDecimalPlaces the number of decimal places that will ultimately be displayed, may be null 292 * @param locale the locale that drives pluralization, not null 293 * @return an appropriate plural cardinality, not null 294 * @throws UnsupportedLocaleException if the locale is not supported 295 */ 296 @NonNull 297 public static Cardinality forNumber(@NonNull Number number, @Nullable Integer visibleDecimalPlaces, @NonNull Locale locale) { 298 requireNonNull(number); 299 requireNonNull(locale); 300 301 boolean numberIsBigDecimal = number instanceof BigDecimal; 302 BigDecimal numberAsBigDecimal = numberIsBigDecimal ? (BigDecimal) number : NumberUtils.toBigDecimal(number); 303 numberAsBigDecimal = numberAsBigDecimal.abs(); 304 305 // If number of visible decimal places is not specified, compute the number of decimal places. 306 // If the number is a BigDecimal, then we have access to trailing zeroes. 307 // We cannot know the number of trailing zeroes otherwise - onus is on caller to explicitly specify if she cares about this 308 if (visibleDecimalPlaces == null) { 309 if (!numberIsBigDecimal) 310 numberAsBigDecimal = numberAsBigDecimal.setScale(NumberUtils.numberOfDecimalPlaces(number), RoundingMode.FLOOR); 311 } else { 312 numberAsBigDecimal = numberAsBigDecimal.setScale(visibleDecimalPlaces, RoundingMode.FLOOR); 313 } 314 315 Optional<CardinalityFamily> cardinalityFamily = CardinalityFamily.cardinalityFamilyForLocale(locale); 316 317 // TODO: throwing an exception might not be the best solution here...need to think about it 318 if (!cardinalityFamily.isPresent()) 319 throw new UnsupportedLocaleException(locale); 320 321 return cardinalityFamily.get().getCardinalityFunction().apply(numberAsBigDecimal); 322 } 323 324 /** 325 * Gets an appropriate plural cardinality for the given range (start, end) and locale. 326 * <p> 327 * For example, a range might be {@code "1-3 hours"}. 328 * <p> 329 * Note that the cardinality of the end of the range does not necessarily 330 * determine the range's cardinality. In English, we say {@code "0–1 days"} - the value {@code 1} is {@code CARDINALITY_ONE} 331 * but the range is {@code CARDINALITY_OTHER}. 332 * <p> 333 * See the <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">CLDR Language Plural Rules</a> 334 * for further details. 335 * 336 * @param start the cardinality for the start of the range, not null 337 * @param end the cardinality for the end of the range, not null 338 * @param locale the locale that drives pluralization, not null 339 * @return an appropriate plural cardinality for the range, not null 340 * @throws UnsupportedLocaleException if the locale is not supported 341 */ 342 @NonNull 343 public static Cardinality forRange(@NonNull Cardinality start, @NonNull Cardinality end, @NonNull Locale locale) { 344 requireNonNull(start); 345 requireNonNull(end); 346 requireNonNull(locale); 347 348 Optional<CardinalityRangeFamily> cardinalityRangeFamily = CardinalityRangeFamily.cardinalityRangeFamilyForLocale(locale); 349 350 // TODO: throwing an exception might not be the best solution here...need to think about it 351 if (!cardinalityRangeFamily.isPresent()) 352 throw new UnsupportedLocaleException(locale); 353 354 CardinalityRange cardinalityRange = CardinalityRange.of(start, end); 355 Cardinality cardinality = cardinalityRangeFamily.get().getCardinalitiesByCardinalityRange().get(cardinalityRange); 356 357 return cardinality == null ? Cardinality.OTHER : cardinality; 358 } 359 360 /** 361 * Gets the set of cardinalities supported for the given locale. 362 * <p> 363 * The empty set will be returned if the locale is not supported. 364 * <p> 365 * The set's values are sorted by the natural ordering of the {@link Cardinality} enumeration. 366 * 367 * @param locale the locale to use for lookup, not null 368 * @return the cardinalities supported by the given locale, not null 369 */ 370 @NonNull 371 public static SortedSet<@NonNull Cardinality> supportedCardinalitiesForLocale(@NonNull Locale locale) { 372 requireNonNull(locale); 373 374 Optional<CardinalityFamily> cardinalityFamily = CardinalityFamily.cardinalityFamilyForLocale(locale); 375 return cardinalityFamily.isPresent() ? cardinalityFamily.get().getSupportedCardinalities() : Collections.emptySortedSet(); 376 } 377 378 /** 379 * Gets a mapping of cardinalities to example integer values for the given locale. 380 * <p> 381 * The empty map will be returned if the locale is not supported or if no example values are available. 382 * <p> 383 * The map's keys are sorted by the natural ordering of the {@link Cardinality} enumeration. 384 * 385 * @param locale the locale to use for lookup, not null 386 * @return a mapping of cardinalities to example integer values, not null 387 */ 388 @NonNull 389 public static SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull Integer>> exampleIntegerValuesForLocale(@NonNull Locale locale) { 390 requireNonNull(locale); 391 392 Optional<CardinalityFamily> cardinalityFamily = CardinalityFamily.cardinalityFamilyForLocale(locale); 393 return cardinalityFamily.isPresent() ? cardinalityFamily.get().getExampleIntegerValuesByCardinality() : Collections.emptySortedMap(); 394 } 395 396 /** 397 * Gets a mapping of cardinalities to example decimal values for the given locale. 398 * <p> 399 * The empty map will be returned if the locale is not supported or if no example values are available. 400 * <p> 401 * The map's keys are sorted by the natural ordering of the {@link Cardinality} enumeration. 402 * 403 * @param locale the locale to use for lookup, not null 404 * @return a mapping of cardinalities to example decimal values, not null 405 */ 406 @NonNull 407 public static SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull BigDecimal>> exampleDecimalValuesForLocale(@NonNull Locale locale) { 408 requireNonNull(locale); 409 410 Optional<CardinalityFamily> cardinalityFamily = CardinalityFamily.cardinalityFamilyForLocale(locale); 411 return cardinalityFamily.isPresent() ? cardinalityFamily.get().getExampleDecimalValuesByCardinality() : Collections.emptySortedMap(); 412 } 413 414 /** 415 * Gets the ISO 639 language codes for which cardinality operations are supported. 416 * <p> 417 * The set's values are ISO 639 codes and therefore sorted using English collation. 418 * 419 * @return the ISO 639 language codes for which cardinality operations are supported, not null 420 */ 421 @NonNull 422 public static SortedSet<@NonNull String> getSupportedLanguageCodes() { 423 return CardinalityFamily.getSupportedLanguageCodes(); 424 } 425 426 /** 427 * Gets the mapping of cardinality names to values. 428 * 429 * @return the mapping of cardinality names to values, not null 430 */ 431 @NonNull 432 static Map<@NonNull String, @NonNull Cardinality> getCardinalitiesByName() { 433 return CARDINALITIES_BY_NAME; 434 } 435 436 /** 437 * Plural cardinality forms grouped by language family. 438 * <p> 439 * Each family has a distinct cardinality calculation rule. 440 * <p> 441 * For example, Germanic languages {@link CardinalityFamily#FAMILY_3} support two {@link Cardinality} types: {@link Cardinality#ONE} for {@code 1} 442 * and {@link Cardinality#OTHER} for all other values. 443 * <p> 444 * See <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">CLDR Language Plural Rules</a> 445 * for more information. 446 * <p> 447 * Cardinality functions are driven by CLDR data. 448 * <p> 449 * The expression format as specified by http://www.unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules 450 * uses the following notation: 451 * <ul> 452 * <li>{@code n} absolute value of the source number (integer and decimals).</li> 453 * <li>{@code i} integer digits of n.</li> 454 * <li>{@code v} number of visible fraction digits in n, with trailing zeros.</li> 455 * <li>{@code w} number of visible fraction digits in n, without trailing zeros.</li> 456 * <li>{@code f} visible fractional digits in n, with trailing zeros.</li> 457 * <li>{@code t} visible fractional digits in n, without trailing zeros.</li> 458 * </ul> 459 * <p> 460 * Some examples follow: 461 * <ul> 462 * <li>{@code n=1: i=1, v=0, w=0, f=0, t=0}</li> 463 * <li>{@code n=1.0: i=1, v=1, w=0, f=0, t=0}</li> 464 * <li>{@code n=1.00: i=1, v=2, w=0, f=0, t=0}</li> 465 * <li>{@code n=1.3: i=1, v=1, w=1, f=3, t=3}</li> 466 * <li>{@code n=1.30: i=1, v=2, w=1, f=30, t=3}</li> 467 * <li>{@code n=1.03: i=1, v=2, w=2, f=3, t=3}</li> 468 * <li>{@code n=1.230: i=1, v=3, w=2, f=230, t=23}</li> 469 * </ul> 470 */ 471 enum CardinalityFamily { 472 /** 473 * Languages Include: 474 * <p> 475 * <ul> 476 * <li>Afrikaans (af)</li> 477 * <li>Asu (asa)</li> 478 * <li>Azeri (az)</li> 479 * <li>Bemba (bem)</li> 480 * <li>Bena (bez)</li> 481 * <li>Bulgarian (bg)</li> 482 * <li>Bodo (brx)</li> 483 * <li>Chechen (ce)</li> 484 * <li>Chiga (cgg)</li> 485 * <li>Cherokee (chr)</li> 486 * <li>Central Kurdish (ckb)</li> 487 * <li>Divehi (dv)</li> 488 * <li>Ewe (ee)</li> 489 * <li>Greek (el)</li> 490 * <li>Esperanto (eo)</li> 491 * <li>Spanish (es)</li> 492 * <li>Basque (eu)</li> 493 * <li>Faroese (fo)</li> 494 * <li>Friulian (fur)</li> 495 * <li>Swiss German (gsw)</li> 496 * <li>Hausa (ha)</li> 497 * <li>Hawaiian (haw)</li> 498 * <li>Hungarian (hu)</li> 499 * <li>Ngomba (jgo)</li> 500 * <li>Machame (jmc)</li> 501 * <li>Georgian (ka)</li> 502 * <li>Jju (kaj)</li> 503 * <li>Tyap (kcg)</li> 504 * <li>Kazakh (kk)</li> 505 * <li>Kako (kkj)</li> 506 * <li>Greenlandic (kl)</li> 507 * <li>Kashmiri (ks)</li> 508 * <li>Shambala (ksb)</li> 509 * <li>Kurdish (ku)</li> 510 * <li>Kirghiz (ky)</li> 511 * <li>Luxembourgish (lb)</li> 512 * <li>Ganda (lg)</li> 513 * <li>Masai (mas)</li> 514 * <li>Metaʼ (mgo)</li> 515 * <li>Malayalam (ml)</li> 516 * <li>Mongolian (mn)</li> 517 * <li>Nahuatl (nah)</li> 518 * <li>Norwegian Bokmål (nb)</li> 519 * <li>North Ndebele (nd)</li> 520 * <li>Nepali (ne)</li> 521 * <li>Norwegian Nynorsk (nn)</li> 522 * <li>Ngiemboon (nnh)</li> 523 * <li>Norwegian (no)</li> 524 * <li>South Ndebele (nr)</li> 525 * <li>Nyanja (ny)</li> 526 * <li>Nyankole (nyn)</li> 527 * <li>Oromo (om)</li> 528 * <li>Odia (or)</li> 529 * <li>Ossetian (os)</li> 530 * <li>Papiamento (pap)</li> 531 * <li>Pushto (ps)</li> 532 * <li>Romansh (rm)</li> 533 * <li>Rombo (rof)</li> 534 * <li>Rwa (rwk)</li> 535 * <li>Samburu (saq)</li> 536 * <li>Southern Kurdish (sdh)</li> 537 * <li>Sena (seh)</li> 538 * <li>Shona (sn)</li> 539 * <li>Somali (so)</li> 540 * <li>Albanian (sq)</li> 541 * <li>Swati (ss)</li> 542 * <li>Saho (ssy)</li> 543 * <li>Southern Sotho (st)</li> 544 * <li>Syriac (syr)</li> 545 * <li>Tamil (ta)</li> 546 * <li>Telugu (te)</li> 547 * <li>Teso (teo)</li> 548 * <li>Tigre (tig)</li> 549 * <li>Turkmen (tk)</li> 550 * <li>Tswana (tn)</li> 551 * <li>Turkish (tr)</li> 552 * <li>Tsonga (ts)</li> 553 * <li>Uighur (ug)</li> 554 * <li>Uzbek (uz)</li> 555 * <li>Venda (ve)</li> 556 * <li>Volapük (vo)</li> 557 * <li>Vunjo (vun)</li> 558 * <li>Walser (wae)</li> 559 * <li>Xhosa (xh)</li> 560 * <li>Soga (xog)</li> 561 * </ul> 562 */ 563 FAMILY_1( 564 (n) -> { 565 // n = 1 566 if (equal(n, BIG_DECIMAL_1)) 567 return ONE; 568 569 return OTHER; 570 }, 571 Sets.sortedSet( 572 ONE, 573 OTHER 574 ), 575 Maps.sortedMap( 576 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 577 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 1000, 10000, 100000, 1000000)) 578 ), 579 Maps.sortedMap( 580 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"))) 581 ) 582 ), 583 584 /** 585 * Languages Include: 586 * <p> 587 * <ul> 588 * <li>Bambara (bm)</li> 589 * <li>Tibetan (bo)</li> 590 * <li>Dzongkha (dz)</li> 591 * <li>Indonesian (id)</li> 592 * <li>Igbo (ig)</li> 593 * <li>Sichuan Yi (ii)</li> 594 * <li>Japanese (ja)</li> 595 * <li>Lojban (jbo)</li> 596 * <li>Javanese (jv)</li> 597 * <li>Javanese (jw)</li> 598 * <li>Makonde (kde)</li> 599 * <li>Kabuverdianu (kea)</li> 600 * <li>Khmer (km)</li> 601 * <li>Korean (ko)</li> 602 * <li>Lakota (lkt)</li> 603 * <li>Lao (lo)</li> 604 * <li>Malay (ms)</li> 605 * <li>Burmese (my)</li> 606 * <li>N’Ko (nqo)</li> 607 * <li>Root (root)</li> 608 * <li>Sakha (sah)</li> 609 * <li>Koyraboro Senni (ses)</li> 610 * <li>Sango (sg)</li> 611 * <li>Thai (th)</li> 612 * <li>Tongan (to)</li> 613 * <li>Vietnamese (vi)</li> 614 * <li>Wolof (wo)</li> 615 * <li>Yoruba (yo)</li> 616 * <li>Cantonese (yue)</li> 617 * <li>Mandarin Chinese (zh)</li> 618 * </ul> 619 */ 620 FAMILY_2( 621 (n) -> { 622 // No cardinality rules for this family 623 return OTHER; 624 }, 625 Sets.sortedSet( 626 OTHER 627 ), 628 Maps.sortedMap( 629 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 100, 1000, 10000, 100000, 1000000)) 630 ), 631 Maps.sortedMap( 632 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 633 ) 634 ), 635 636 /** 637 * Languages Include: 638 * <p> 639 * <ul> 640 * <li>Asturian (ast)</li> 641 * <li>Catalan (ca)</li> 642 * <li>German (de)</li> 643 * <li>English (en)</li> 644 * <li>Estonian (et)</li> 645 * <li>Finnish (fi)</li> 646 * <li>Western Frisian (fy)</li> 647 * <li>Galician (gl)</li> 648 * <li>Italian (it)</li> 649 * <li>Dutch (nl)</li> 650 * <li>Swedish (sv)</li> 651 * <li>Swahili (sw)</li> 652 * <li>Urdu (ur)</li> 653 * <li>Yiddish (yi)</li> 654 * </ul> 655 */ 656 FAMILY_3( 657 (n) -> { 658 BigInteger i = NumberUtils.integerComponent(n); 659 int v = NumberUtils.numberOfDecimalPlaces(n); 660 661 // i = 1 and v = 0 662 if (equal(i, BIG_INTEGER_1) && v == 0) 663 return ONE; 664 665 return OTHER; 666 }, 667 Sets.sortedSet( 668 ONE, 669 OTHER 670 ), 671 Maps.sortedMap( 672 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 673 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 1000, 10000, 100000, 1000000)) 674 ), 675 Maps.sortedMap( 676 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 677 ) 678 ), 679 680 /** 681 * Languages Include: 682 * <p> 683 * <ul> 684 * <li>Akan (ak)</li> 685 * <li>Bihari (bh)</li> 686 * <li>Gun (guw)</li> 687 * <li>Lingala (ln)</li> 688 * <li>Malagasy (mg)</li> 689 * <li>Northern Sotho (nso)</li> 690 * <li>Punjabi (pa)</li> 691 * <li>Tigrinya (ti)</li> 692 * <li>Walloon (wa)</li> 693 * </ul> 694 */ 695 FAMILY_4( 696 (n) -> { 697 // n = 0..1 698 if (inRange(n, BIG_DECIMAL_0, BIG_DECIMAL_1)) 699 return ONE; 700 701 return OTHER; 702 }, 703 Sets.sortedSet( 704 ONE, 705 OTHER 706 ), 707 Maps.sortedMap( 708 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1)), 709 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 710 ), 711 Maps.sortedMap( 712 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"))) 713 ) 714 ), 715 716 /** 717 * Languages Include: 718 * <p> 719 * <ul> 720 * <li>Amharic (am)</li> 721 * <li>Assamese (as)</li> 722 * <li>Bangla (bn)</li> 723 * <li>Persian (fa)</li> 724 * <li>Gujarati (gu)</li> 725 * <li>Hindi (hi)</li> 726 * <li>Kannada (kn)</li> 727 * <li>Marathi (mr)</li> 728 * <li>Zulu (zu)</li> 729 * </ul> 730 */ 731 FAMILY_5( 732 (n) -> { 733 // i = 0 or n = 1 734 BigInteger i = NumberUtils.integerComponent(n); 735 736 if (equal(i, BIG_INTEGER_0) || equal(n, BIG_DECIMAL_1)) 737 return ONE; 738 739 return OTHER; 740 }, 741 Sets.sortedSet( 742 ONE, 743 OTHER 744 ), 745 Maps.sortedMap( 746 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1)), 747 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 748 ), 749 Maps.sortedMap( 750 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.0"), new BigDecimal("0.01"), new BigDecimal("0.02"), new BigDecimal("0.03"), new BigDecimal("0.04"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"))), 751 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("1.8"), new BigDecimal("1.9"), new BigDecimal("2.0"), new BigDecimal("2.1"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("2.5"), new BigDecimal("2.6"))) 752 ) 753 ), 754 755 /** 756 * Languages Include: 757 * <p> 758 * <ul> 759 * <li>Inuktitut (iu)</li> 760 * <li>Cornish (kw)</li> 761 * <li>Nama (naq)</li> 762 * <li>Northern Sami (se)</li> 763 * <li>Southern Sami (sma)</li> 764 * <li>Sami (smi)</li> 765 * <li>Lule Sami (smj)</li> 766 * <li>Inari Sami (smn)</li> 767 * <li>Skolt Sami (sms)</li> 768 * </ul> 769 */ 770 FAMILY_6( 771 (n) -> { 772 // n = 1 773 if (equal(n, BIG_DECIMAL_1)) 774 return ONE; 775 // n = 2 776 if (equal(n, BIG_DECIMAL_2)) 777 return TWO; 778 779 return OTHER; 780 }, 781 Sets.sortedSet( 782 ONE, 783 TWO, 784 OTHER 785 ), 786 Maps.sortedMap( 787 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 788 MapEntry.of(Cardinality.TWO, Range.ofFiniteValues(2)), 789 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 790 ), 791 Maps.sortedMap( 792 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"))) 793 ) 794 ), 795 796 /** 797 * Languages Include: 798 * <p> 799 * <ul> 800 * <li>Bosnian (bs)</li> 801 * <li>Croatian (hr)</li> 802 * <li>Serbo-Croatian (sh)</li> 803 * <li>Serbian (sr)</li> 804 * </ul> 805 */ 806 FAMILY_7( 807 (n) -> { 808 int v = NumberUtils.numberOfDecimalPlaces(n); 809 BigInteger i = NumberUtils.integerComponent(n); 810 BigInteger f = NumberUtils.fractionalComponent(n); 811 812 // v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11 813 if ((v == 0 && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_1) && notEqual(i.mod(BIG_INTEGER_100), BIG_INTEGER_11)) 814 || (equal(f.mod(BIG_INTEGER_10), BIG_INTEGER_1) && notEqual(f.mod(BIG_INTEGER_100), BIG_INTEGER_11))) 815 return ONE; 816 // v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14 817 if ((v == 0 818 && inRange(i.mod(BIG_INTEGER_10), BIG_INTEGER_2, BIG_INTEGER_4) 819 && notInRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_12, BIG_INTEGER_14)) 820 || 821 (inRange(f.mod(BIG_INTEGER_10), BIG_INTEGER_2, BIG_INTEGER_4) 822 && notInRange(f.mod(BIG_INTEGER_100), BIG_INTEGER_12, BIG_INTEGER_14))) 823 return FEW; 824 825 return OTHER; 826 }, 827 Sets.sortedSet( 828 ONE, 829 FEW, 830 OTHER 831 ), 832 Maps.sortedMap( 833 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 834 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(2, 3, 4, 22, 23, 24, 32, 33, 34, 42, 43, 44, 52, 53, 54, 62, 102, 1002)), 835 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 836 ), 837 Maps.sortedMap( 838 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("1.1"), new BigDecimal("2.1"), new BigDecimal("3.1"), new BigDecimal("4.1"), new BigDecimal("5.1"), new BigDecimal("6.1"), new BigDecimal("7.1"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))), 839 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("3.2"), new BigDecimal("3.3"), new BigDecimal("3.4"), new BigDecimal("4.2"), new BigDecimal("4.3"), new BigDecimal("4.4"), new BigDecimal("5.2"), new BigDecimal("10.2"), new BigDecimal("100.2"), new BigDecimal("1000.2"))), 840 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("1.8"), new BigDecimal("1.9"), new BigDecimal("2.0"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"))) 841 ) 842 ), 843 844 /** 845 * Languages Include: 846 * <p> 847 * <ul> 848 * <li>Fulah (ff)</li> 849 * <li>French (fr)</li> 850 * <li>Armenian (hy)</li> 851 * <li>Kabyle (kab)</li> 852 * </ul> 853 */ 854 FAMILY_8( 855 (n) -> { 856 BigInteger i = NumberUtils.integerComponent(n); 857 858 // i = 0,1 859 if (inSet(i, BIG_INTEGER_0, BIG_INTEGER_1)) 860 return ONE; 861 862 return OTHER; 863 }, 864 Sets.sortedSet( 865 ONE, 866 OTHER 867 ), 868 Maps.sortedMap( 869 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1)), 870 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 871 ), 872 Maps.sortedMap( 873 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))), 874 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("2.0"), new BigDecimal("2.1"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"), new BigDecimal("2.8"), new BigDecimal("2.9"), new BigDecimal("3.0"), new BigDecimal("3.1"), new BigDecimal("3.2"), new BigDecimal("3.3"), new BigDecimal("3.4"), new BigDecimal("3.5"))) 875 ) 876 ), 877 878 /** 879 * Languages Include: 880 * <p> 881 * <ul> 882 * <li>Arabic (ar)</li> 883 * <li>Najdi Arabic (ars)</li> 884 * </ul> 885 */ 886 FAMILY_9( 887 (n) -> { 888 // n = 0 889 if (equal(n, BIG_DECIMAL_0)) 890 return ZERO; 891 // n = 1 892 if (equal(n, BIG_DECIMAL_1)) 893 return ONE; 894 // n = 2 895 if (equal(n, BIG_DECIMAL_2)) 896 return TWO; 897 // n % 100 = 3..10 898 if (inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_3, BIG_DECIMAL_10)) 899 return FEW; 900 // n % 100 = 11..99 901 if (inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_99)) 902 return MANY; 903 904 return OTHER; 905 }, 906 Sets.sortedSet( 907 ZERO, 908 ONE, 909 TWO, 910 FEW, 911 MANY, 912 OTHER 913 ), 914 Maps.sortedMap( 915 MapEntry.of(Cardinality.ZERO, Range.ofFiniteValues(0)), 916 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 917 MapEntry.of(Cardinality.TWO, Range.ofFiniteValues(2)), 918 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(3, 4, 5, 6, 7, 8, 9, 10, 103, 104, 105, 106, 107, 108, 109, 110, 1003)), 919 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 111, 1011)), 920 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(100, 101, 102, 200, 201, 202, 300, 301, 302, 400, 401, 402, 500, 501, 502, 600, 1000, 10000, 100000, 1000000)) 921 ), 922 Maps.sortedMap( 923 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("10.1"))) 924 ) 925 ), 926 927 /** 928 * Languages Include: 929 * <p> 930 * <ul> 931 * <li>Czech (cs)</li> 932 * <li>Slovak (sk)</li> 933 * </ul> 934 */ 935 FAMILY_10( 936 (n) -> { 937 int v = NumberUtils.numberOfDecimalPlaces(n); 938 BigInteger i = NumberUtils.integerComponent(n); 939 940 // i = 1 and v = 0 941 if (equal(i, BIG_INTEGER_1) && v == 0) 942 return ONE; 943 // i = 2..4 and v = 0 944 if (inRange(i, BIG_INTEGER_2, BIG_INTEGER_4) && v == 0) 945 return FEW; 946 // v != 0 947 if (v != 0) 948 return MANY; 949 950 return OTHER; 951 }, 952 Sets.sortedSet( 953 ONE, 954 FEW, 955 MANY, 956 OTHER 957 ), 958 Maps.sortedMap( 959 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 960 MapEntry.of(Cardinality.FEW, Range.ofFiniteValues(2, 3, 4)), 961 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 962 ), 963 Maps.sortedMap( 964 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 965 ) 966 ), 967 968 /** 969 * Languages Include: 970 * <p> 971 * <ul> 972 * <li>Lower Sorbian (dsb)</li> 973 * <li>Upper Sorbian (hsb)</li> 974 * </ul> 975 */ 976 FAMILY_11( 977 (n) -> { 978 int v = NumberUtils.numberOfDecimalPlaces(n); 979 BigInteger i = NumberUtils.integerComponent(n); 980 BigInteger f = NumberUtils.fractionalComponent(n); 981 982 // v = 0 and i % 100 = 1 or f % 100 = 1 983 if ((v == 0 && equal(i.mod(BIG_INTEGER_100), BIG_INTEGER_1)) 984 || (equal(f.mod(BIG_INTEGER_100), BIG_INTEGER_1))) 985 return ONE; 986 // v = 0 and i % 100 = 2 or f % 100 = 2 987 if ((v == 0 && equal(i.mod(BIG_INTEGER_100), BIG_INTEGER_2)) 988 || equal(f.mod(BIG_INTEGER_100), BIG_INTEGER_2)) 989 return TWO; 990 // v = 0 and i % 100 = 3..4 or f % 100 = 3..4 991 if ((v == 0 && inRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_3, BIG_INTEGER_4)) 992 || inRange(f.mod(BIG_INTEGER_100), BIG_INTEGER_3, BIG_INTEGER_4)) 993 return FEW; 994 995 return OTHER; 996 }, 997 Sets.sortedSet( 998 ONE, 999 TWO, 1000 FEW, 1001 OTHER 1002 ), 1003 Maps.sortedMap( 1004 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 101, 201, 301, 401, 501, 601, 701, 1001)), 1005 MapEntry.of(Cardinality.TWO, Range.ofInfiniteValues(2, 102, 202, 302, 402, 502, 602, 702, 1002)), 1006 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003)), 1007 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1008 ), 1009 Maps.sortedMap( 1010 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("1.1"), new BigDecimal("2.1"), new BigDecimal("3.1"), new BigDecimal("4.1"), new BigDecimal("5.1"), new BigDecimal("6.1"), new BigDecimal("7.1"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))), 1011 MapEntry.of(Cardinality.TWO, Range.ofInfiniteValues(new BigDecimal("0.2"), new BigDecimal("1.2"), new BigDecimal("2.2"), new BigDecimal("3.2"), new BigDecimal("4.2"), new BigDecimal("5.2"), new BigDecimal("6.2"), new BigDecimal("7.2"), new BigDecimal("10.2"), new BigDecimal("100.2"), new BigDecimal("1000.2"))), 1012 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("3.3"), new BigDecimal("3.4"), new BigDecimal("4.3"), new BigDecimal("4.4"), new BigDecimal("5.3"), new BigDecimal("5.4"), new BigDecimal("6.3"), new BigDecimal("6.4"), new BigDecimal("7.3"), new BigDecimal("7.4"), new BigDecimal("10.3"), new BigDecimal("100.3"), new BigDecimal("1000.3"))), 1013 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("1.8"), new BigDecimal("1.9"), new BigDecimal("2.0"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"))) 1014 ) 1015 ), 1016 1017 /** 1018 * Languages Include: 1019 * <p> 1020 * <ul> 1021 * <li>Filipino (fil)</li> 1022 * <li>Tagalog (tl)</li> 1023 * </ul> 1024 */ 1025 FAMILY_12( 1026 (n) -> { 1027 int v = NumberUtils.numberOfDecimalPlaces(n); 1028 BigInteger i = NumberUtils.integerComponent(n); 1029 BigInteger f = NumberUtils.fractionalComponent(n); 1030 1031 // 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 1032 if ((v == 0 && inSet(i, BIG_INTEGER_1, BIG_INTEGER_2, BIG_INTEGER_3)) 1033 || (v == 0 && notInSet(i.mod(BIG_INTEGER_10), BIG_INTEGER_4, BIG_INTEGER_6, BIG_INTEGER_9)) 1034 || (v != 0 && notInSet(f.mod(BIG_INTEGER_10), BIG_INTEGER_4, BIG_INTEGER_6, BIG_INTEGER_9))) 1035 return ONE; 1036 1037 return OTHER; 1038 }, 1039 Sets.sortedSet( 1040 ONE, 1041 OTHER 1042 ), 1043 Maps.sortedMap( 1044 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(0, 1, 2, 3, 5, 7, 8, 10, 11, 12, 13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000)), 1045 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(4, 6, 9, 14, 16, 19, 24, 26, 104, 1004)) 1046 ), 1047 Maps.sortedMap( 1048 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.5"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.5"), new BigDecimal("1.7"), new BigDecimal("1.8"), new BigDecimal("2.1"))), 1049 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.4"), new BigDecimal("0.6"), new BigDecimal("0.9"), new BigDecimal("1.4"), new BigDecimal("1.6"), new BigDecimal("1.9"), new BigDecimal("2.4"), new BigDecimal("2.6"), new BigDecimal("10.4"), new BigDecimal("100.4"), new BigDecimal("1000.4"))) 1050 ) 1051 ), 1052 1053 /** 1054 * Languages Include: 1055 * <p> 1056 * <ul> 1057 * <li>Latvian (lv)</li> 1058 * <li>Prussian (prg)</li> 1059 * </ul> 1060 */ 1061 FAMILY_13( 1062 (n) -> { 1063 int v = NumberUtils.numberOfDecimalPlaces(n); 1064 BigInteger f = NumberUtils.fractionalComponent(n); 1065 1066 // n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19 1067 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_0) 1068 || inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_19) 1069 || (v == 2 && inRange(f.mod(BIG_INTEGER_100), BIG_INTEGER_11, BIG_INTEGER_19))) 1070 return ZERO; 1071 // 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 1072 if ((equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_1) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11)) 1073 || (v == 2 && equal(f.mod(BIG_INTEGER_10), BIG_INTEGER_1) && notEqual(f.mod(BIG_INTEGER_100), BIG_INTEGER_11)) 1074 || (v != 2 && equal(f.mod(BIG_INTEGER_10), BIG_INTEGER_1))) 1075 return ONE; 1076 1077 return OTHER; 1078 }, 1079 Sets.sortedSet( 1080 ZERO, 1081 ONE, 1082 OTHER 1083 ), 1084 Maps.sortedMap( 1085 MapEntry.of(Cardinality.ZERO, Range.ofInfiniteValues(0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000)), 1086 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 1087 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 22, 23, 24, 25, 26, 27, 28, 29, 102, 1002)) 1088 ), 1089 Maps.sortedMap( 1090 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("1.1"), new BigDecimal("2.1"), new BigDecimal("3.1"), new BigDecimal("4.1"), new BigDecimal("5.1"), new BigDecimal("6.1"), new BigDecimal("7.1"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))), 1091 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("1.8"), new BigDecimal("1.9"), new BigDecimal("10.2"), new BigDecimal("100.2"), new BigDecimal("1000.2"))) 1092 ) 1093 ), 1094 1095 /** 1096 * Languages Include: 1097 * <p> 1098 * <ul> 1099 * <li>Moldovan (mo)</li> 1100 * <li>Romanian (ro)</li> 1101 * </ul> 1102 */ 1103 FAMILY_14( 1104 (n) -> { 1105 int v = NumberUtils.numberOfDecimalPlaces(n); 1106 BigInteger i = NumberUtils.integerComponent(n); 1107 1108 // i = 1 and v = 0 1109 if (equal(i, BIG_INTEGER_1) && v == 0) 1110 return ONE; 1111 // v != 0 or n = 0 or n != 1 and n % 100 = 1..19 1112 if (v != 0 1113 || equal(n, BIG_DECIMAL_0) 1114 || (notEqual(n, BIG_DECIMAL_1) && inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_1, BIG_DECIMAL_19))) 1115 return FEW; 1116 1117 return OTHER; 1118 }, 1119 Sets.sortedSet( 1120 ONE, 1121 FEW, 1122 OTHER 1123 ), 1124 Maps.sortedMap( 1125 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1126 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 101, 1001)), 1127 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 100, 1000, 10000, 100000, 1000000)) 1128 ), 1129 Maps.sortedMap( 1130 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 1131 ) 1132 ), 1133 1134 /** 1135 * Languages Include: 1136 * <p> 1137 * <ul> 1138 * <li>Russian (ru)</li> 1139 * <li>Ukrainian (uk)</li> 1140 * </ul> 1141 */ 1142 FAMILY_15( 1143 (n) -> { 1144 int v = NumberUtils.numberOfDecimalPlaces(n); 1145 BigInteger i = NumberUtils.integerComponent(n); 1146 1147 // v = 0 and i % 10 = 1 and i % 100 != 11 1148 if (v == 0 && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_1) && notEqual(i.mod(BIG_INTEGER_100), BIG_INTEGER_11)) 1149 return ONE; 1150 // v = 0 and i % 10 = 2..4 and i % 100 != 12..14 1151 if (v == 0 1152 && inRange(i.mod(BIG_INTEGER_10), BIG_INTEGER_2, BIG_INTEGER_4) 1153 && notInRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_12, BIG_INTEGER_14)) 1154 return FEW; 1155 // v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14 1156 if ((v == 0 && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_0)) 1157 || (v == 0 && inRange(i.mod(BIG_INTEGER_10), BIG_INTEGER_5, BIG_INTEGER_9)) 1158 || (v == 0 && inRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_11, BIG_INTEGER_14))) 1159 return MANY; 1160 1161 return OTHER; 1162 }, 1163 Sets.sortedSet( 1164 ONE, 1165 FEW, 1166 MANY, 1167 OTHER 1168 ), 1169 Maps.sortedMap( 1170 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 1171 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(2, 3, 4, 22, 23, 24, 32, 33, 34, 42, 43, 44, 52, 53, 54, 62, 102, 1002)), 1172 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1173 ), 1174 Maps.sortedMap( 1175 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 1176 ) 1177 ), 1178 1179 /** 1180 * Languages Include: 1181 * <p> 1182 * <ul> 1183 * <li>Belarusian (be)</li> 1184 * </ul> 1185 */ 1186 FAMILY_16( 1187 (n) -> { 1188 // n % 10 = 1 and n % 100 != 11 1189 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_1) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11)) 1190 return ONE; 1191 // n % 10 = 2..4 and n % 100 != 12..14 1192 if (inRange(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_2, BIG_DECIMAL_4) 1193 && notInRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_12, BIG_DECIMAL_14)) 1194 return FEW; 1195 // n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14 1196 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_0) 1197 || inRange(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_5, BIG_DECIMAL_9) 1198 || inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_14)) 1199 return MANY; 1200 1201 return OTHER; 1202 }, 1203 Sets.sortedSet( 1204 ONE, 1205 FEW, 1206 MANY, 1207 OTHER 1208 ), 1209 Maps.sortedMap( 1210 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 1211 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(2, 3, 4, 22, 23, 24, 32, 33, 34, 42, 43, 44, 52, 53, 54, 62, 102, 1002)), 1212 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1213 ), 1214 Maps.sortedMap( 1215 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))) 1216 ) 1217 ), 1218 1219 /** 1220 * Languages Include: 1221 * <p> 1222 * <ul> 1223 * <li>Breton (br)</li> 1224 * </ul> 1225 */ 1226 FAMILY_17( 1227 (n) -> { 1228 // n % 10 = 1 and n % 100 != 11,71,91 1229 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_1) 1230 && notInSet(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_71, BIG_DECIMAL_91)) 1231 return ONE; 1232 // n % 10 = 2 and n % 100 != 12,72,92 1233 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_2) 1234 && notInSet(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_12, BIG_DECIMAL_72, BIG_DECIMAL_92)) 1235 return TWO; 1236 // n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99 1237 if ((inRange(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_3, BIG_DECIMAL_4) || equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_9)) 1238 && notInRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_10, BIG_DECIMAL_19) 1239 && notInRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_70, BIG_DECIMAL_79) 1240 && notInRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_90, BIG_DECIMAL_99)) 1241 return FEW; 1242 // n != 0 and n % 1000000 = 0 1243 if (notEqual(n, BIG_DECIMAL_0) && equal(n.remainder(BIG_DECIMAL_1_000_000), BIG_DECIMAL_0)) 1244 return MANY; 1245 1246 return OTHER; 1247 }, 1248 Sets.sortedSet( 1249 ONE, 1250 TWO, 1251 FEW, 1252 MANY, 1253 OTHER 1254 ), 1255 Maps.sortedMap( 1256 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 81, 101, 1001)), 1257 MapEntry.of(Cardinality.TWO, Range.ofInfiniteValues(2, 22, 32, 42, 52, 62, 82, 102, 1002)), 1258 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003)), 1259 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(1000000)), 1260 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 100, 1000, 10000, 100000)) 1261 ), 1262 Maps.sortedMap( 1263 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"))) 1264 ) 1265 ), 1266 1267 /** 1268 * Languages Include: 1269 * <p> 1270 * <ul> 1271 * <li>Welsh (cy)</li> 1272 * </ul> 1273 */ 1274 FAMILY_18( 1275 (n) -> { 1276 // n = 0 1277 if (equal(n, BIG_DECIMAL_0)) 1278 return ZERO; 1279 // n = 1 1280 if (equal(n, BIG_DECIMAL_1)) 1281 return ONE; 1282 // n = 2 1283 if (equal(n, BIG_DECIMAL_2)) 1284 return TWO; 1285 // n = 3 1286 if (equal(n, BIG_DECIMAL_3)) 1287 return FEW; 1288 // n = 6 1289 if (equal(n, BIG_DECIMAL_6)) 1290 return MANY; 1291 1292 return OTHER; 1293 }, 1294 Sets.sortedSet( 1295 ZERO, 1296 ONE, 1297 TWO, 1298 FEW, 1299 MANY, 1300 OTHER 1301 ), 1302 Maps.sortedMap( 1303 MapEntry.of(Cardinality.ZERO, Range.ofFiniteValues(0)), 1304 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1305 MapEntry.of(Cardinality.TWO, Range.ofFiniteValues(2)), 1306 MapEntry.of(Cardinality.FEW, Range.ofFiniteValues(3)), 1307 MapEntry.of(Cardinality.MANY, Range.ofFiniteValues(6)), 1308 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 100, 1000, 10000, 100000, 1000000)) 1309 ), 1310 Maps.sortedMap( 1311 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"))) 1312 ) 1313 ), 1314 1315 /** 1316 * Languages Include: 1317 * <p> 1318 * <ul> 1319 * <li>Danish (da)</li> 1320 * </ul> 1321 */ 1322 FAMILY_19( 1323 (n) -> { 1324 BigInteger i = NumberUtils.integerComponent(n); 1325 BigInteger t = NumberUtils.fractionalComponent(n.stripTrailingZeros()); 1326 1327 // n = 1 or t != 0 and i = 0,1 1328 if (equal(n, BIG_DECIMAL_1) || (notEqual(t, BIG_INTEGER_0) && inSet(i, BIG_INTEGER_0, BIG_INTEGER_1))) 1329 return ONE; 1330 1331 return OTHER; 1332 }, 1333 Sets.sortedSet( 1334 ONE, 1335 OTHER 1336 ), 1337 Maps.sortedMap( 1338 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1339 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 1000, 10000, 100000, 1000000)) 1340 ), 1341 Maps.sortedMap( 1342 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"))), 1343 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("2.0"), new BigDecimal("2.1"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"), new BigDecimal("2.8"), new BigDecimal("2.9"), new BigDecimal("3.0"), new BigDecimal("3.1"), new BigDecimal("3.2"), new BigDecimal("3.3"), new BigDecimal("3.4"))) 1344 ) 1345 ), 1346 1347 /** 1348 * Languages Include: 1349 * <p> 1350 * <ul> 1351 * <li>Irish (ga)</li> 1352 * </ul> 1353 */ 1354 FAMILY_20( 1355 (n) -> { 1356 // n = 1 1357 if (equal(n, BIG_DECIMAL_1)) 1358 return ONE; 1359 // n = 2 1360 if (equal(n, BIG_DECIMAL_2)) 1361 return TWO; 1362 // n = 3..6 1363 if (inRange(n, BIG_DECIMAL_3, BIG_DECIMAL_6)) 1364 return FEW; 1365 // n = 7..10 1366 if (inRange(n, BIG_DECIMAL_7, BIG_DECIMAL_10)) 1367 return MANY; 1368 1369 return OTHER; 1370 }, 1371 Sets.sortedSet( 1372 ONE, 1373 TWO, 1374 FEW, 1375 MANY, 1376 OTHER 1377 ), 1378 Maps.sortedMap( 1379 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1380 MapEntry.of(Cardinality.TWO, Range.ofFiniteValues(2)), 1381 MapEntry.of(Cardinality.FEW, Range.ofFiniteValues(3, 4, 5, 6)), 1382 MapEntry.of(Cardinality.MANY, Range.ofFiniteValues(7, 8, 9, 10)), 1383 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 100, 1000, 10000, 100000, 1000000)) 1384 ), 1385 Maps.sortedMap( 1386 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("10.1"))) 1387 ) 1388 ), 1389 1390 /** 1391 * Languages Include: 1392 * <p> 1393 * <ul> 1394 * <li>Scottish Gaelic (gd)</li> 1395 * </ul> 1396 */ 1397 FAMILY_21( 1398 (n) -> { 1399 // n = 1,11 1400 if (inSet(n, BIG_DECIMAL_1, BIG_DECIMAL_11)) 1401 return ONE; 1402 // n = 2,12 1403 if (inSet(n, BIG_DECIMAL_2, BIG_DECIMAL_12)) 1404 return TWO; 1405 // n = 3..10,13..19 1406 if (inRange(n, BIG_DECIMAL_3, BIG_DECIMAL_10) || inRange(n, BIG_DECIMAL_13, BIG_DECIMAL_19)) 1407 return FEW; 1408 1409 return OTHER; 1410 }, 1411 Sets.sortedSet( 1412 ONE, 1413 TWO, 1414 FEW, 1415 OTHER 1416 ), 1417 Maps.sortedMap( 1418 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1, 11)), 1419 MapEntry.of(Cardinality.TWO, Range.ofFiniteValues(2, 12)), 1420 MapEntry.of(Cardinality.FEW, Range.ofFiniteValues(3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 19)), 1421 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 100, 1000, 10000, 100000, 1000000)) 1422 ), 1423 Maps.sortedMap( 1424 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("10.1"))) 1425 ) 1426 ), 1427 1428 /** 1429 * Languages Include: 1430 * <p> 1431 * <ul> 1432 * <li>Manx (gv)</li> 1433 * </ul> 1434 */ 1435 FAMILY_22( 1436 (n) -> { 1437 int v = NumberUtils.numberOfDecimalPlaces(n); 1438 BigInteger i = NumberUtils.integerComponent(n); 1439 1440 // v = 0 and i % 10 = 1 1441 if (v == 0 && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_1)) 1442 return ONE; 1443 // v = 0 and i % 10 = 2 1444 if (v == 0 && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_2)) 1445 return TWO; 1446 // v = 0 and i % 100 = 0,20,40,60,80 1447 if (v == 0 && inSet(i.mod(BIG_INTEGER_100), BIG_INTEGER_0, BIG_INTEGER_20, BIG_INTEGER_40, BIG_INTEGER_60, BIG_INTEGER_80)) 1448 return FEW; 1449 // v != 0 1450 if (v != 0) 1451 return MANY; 1452 1453 return OTHER; 1454 }, 1455 Sets.sortedSet( 1456 ONE, 1457 TWO, 1458 FEW, 1459 MANY, 1460 OTHER 1461 ), 1462 Maps.sortedMap( 1463 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 11, 21, 31, 41, 51, 61, 71, 101, 1001)), 1464 MapEntry.of(Cardinality.TWO, Range.ofInfiniteValues(2, 12, 22, 32, 42, 52, 62, 72, 102, 1002)), 1465 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000)), 1466 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 19, 23, 103, 1003)) 1467 ), 1468 Maps.sortedMap( 1469 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 1470 ) 1471 ), 1472 1473 /** 1474 * Languages Include: 1475 * <p> 1476 * <ul> 1477 * <li>Hebrew (he)</li> 1478 * </ul> 1479 */ 1480 FAMILY_23( 1481 (n) -> { 1482 int v = NumberUtils.numberOfDecimalPlaces(n); 1483 BigInteger i = NumberUtils.integerComponent(n); 1484 1485 // i = 1 and v = 0 1486 if (equal(i, BIG_INTEGER_1) && v == 0) 1487 return ONE; 1488 // i = 2 and v = 0 1489 if (equal(i, BIG_INTEGER_2) && v == 0) 1490 return TWO; 1491 // v = 0 and n != 0..10 and n % 10 = 0 1492 if (v == 0 1493 && notInRange(n, BIG_DECIMAL_0, BIG_DECIMAL_10) 1494 && equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_0)) 1495 return MANY; 1496 1497 return OTHER; 1498 }, 1499 Sets.sortedSet( 1500 ONE, 1501 TWO, 1502 MANY, 1503 OTHER 1504 ), 1505 Maps.sortedMap( 1506 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1507 MapEntry.of(Cardinality.TWO, Range.ofFiniteValues(2)), 1508 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000)), 1509 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 101, 1001)) 1510 ), 1511 Maps.sortedMap( 1512 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 1513 ) 1514 ), 1515 1516 /** 1517 * Languages Include: 1518 * <p> 1519 * <ul> 1520 * <li>Icelandic (is)</li> 1521 * </ul> 1522 */ 1523 FAMILY_24( 1524 (n) -> { 1525 BigInteger i = NumberUtils.integerComponent(n); 1526 BigInteger t = NumberUtils.fractionalComponent(n.stripTrailingZeros()); 1527 1528 // t = 0 and i % 10 = 1 and i % 100 != 11 or t != 0 1529 if ((equal(t, BIG_INTEGER_0) && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_1) && notEqual(i.mod(BIG_INTEGER_100), BIG_INTEGER_11)) 1530 || notEqual(t, BIG_INTEGER_0)) 1531 return ONE; 1532 1533 return OTHER; 1534 }, 1535 Sets.sortedSet( 1536 ONE, 1537 OTHER 1538 ), 1539 Maps.sortedMap( 1540 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 1541 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 1000, 10000, 100000, 1000000)) 1542 ), 1543 Maps.sortedMap( 1544 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))) 1545 ) 1546 ), 1547 1548 /** 1549 * Languages Include: 1550 * <p> 1551 * <ul> 1552 * <li>Colognian (ksh)</li> 1553 * </ul> 1554 */ 1555 FAMILY_25( 1556 (n) -> { 1557 // n = 0 1558 if (equal(n, BIG_DECIMAL_0)) 1559 return ZERO; 1560 // n = 1 1561 if (equal(n, BIG_DECIMAL_1)) 1562 return ONE; 1563 1564 return OTHER; 1565 }, 1566 Sets.sortedSet( 1567 ZERO, 1568 ONE, 1569 OTHER 1570 ), 1571 Maps.sortedMap( 1572 MapEntry.of(Cardinality.ZERO, Range.ofFiniteValues(0)), 1573 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1574 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1575 ), 1576 Maps.sortedMap( 1577 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"))) 1578 ) 1579 ), 1580 1581 /** 1582 * Languages Include: 1583 * <p> 1584 * <ul> 1585 * <li>Langi (lag)</li> 1586 * </ul> 1587 */ 1588 FAMILY_26( 1589 (n) -> { 1590 BigInteger i = NumberUtils.integerComponent(n); 1591 1592 // n = 0 1593 if (equal(n, BIG_DECIMAL_0)) 1594 return ZERO; 1595 // i = 0,1 and n != 0 1596 if (inSet(i, BIG_INTEGER_0, BIG_INTEGER_1) && notEqual(n, BIG_DECIMAL_0)) 1597 return ONE; 1598 1599 return OTHER; 1600 }, 1601 Sets.sortedSet( 1602 ZERO, 1603 ONE, 1604 OTHER 1605 ), 1606 Maps.sortedMap( 1607 MapEntry.of(Cardinality.ZERO, Range.ofFiniteValues(0)), 1608 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1609 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1610 ), 1611 Maps.sortedMap( 1612 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"))), 1613 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("2.0"), new BigDecimal("2.1"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"), new BigDecimal("2.8"), new BigDecimal("2.9"), new BigDecimal("3.0"), new BigDecimal("3.1"), new BigDecimal("3.2"), new BigDecimal("3.3"), new BigDecimal("3.4"), new BigDecimal("3.5"))) 1614 ) 1615 ), 1616 1617 /** 1618 * Languages Include: 1619 * <p> 1620 * <ul> 1621 * <li>Lithuanian (lt)</li> 1622 * </ul> 1623 */ 1624 FAMILY_27( 1625 (n) -> { 1626 BigInteger f = NumberUtils.fractionalComponent(n); 1627 1628 // n % 10 = 1 and n % 100 != 11..19 1629 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_1) 1630 && notInRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_19)) 1631 return ONE; 1632 // n % 10 = 2..9 and n % 100 != 11..19 1633 if (inRange(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_2, BIG_DECIMAL_9) 1634 && notInRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_19)) 1635 return FEW; 1636 // f != 0 1637 if (notEqual(f, BIG_INTEGER_0)) 1638 return MANY; 1639 1640 return OTHER; 1641 }, 1642 Sets.sortedSet( 1643 ONE, 1644 FEW, 1645 MANY, 1646 OTHER 1647 ), 1648 Maps.sortedMap( 1649 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 1650 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 22, 23, 24, 25, 26, 27, 28, 29, 102, 1002)), 1651 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000)) 1652 ), 1653 Maps.sortedMap( 1654 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))) 1655 ) 1656 ), 1657 1658 /** 1659 * Languages Include: 1660 * <p> 1661 * <ul> 1662 * <li>Macedonian (mk)</li> 1663 * </ul> 1664 */ 1665 FAMILY_28( 1666 (n) -> { 1667 int v = NumberUtils.numberOfDecimalPlaces(n); 1668 BigInteger i = NumberUtils.integerComponent(n); 1669 BigInteger f = NumberUtils.fractionalComponent(n); 1670 1671 // v = 0 and i % 10 = 1 or f % 10 = 1 1672 if ((v == 0 && equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_1)) 1673 || equal(f.mod(BIG_INTEGER_10), BIG_INTEGER_1)) 1674 return ONE; 1675 1676 return OTHER; 1677 }, 1678 Sets.sortedSet( 1679 ONE, 1680 OTHER 1681 ), 1682 Maps.sortedMap( 1683 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 11, 21, 31, 41, 51, 61, 71, 101, 1001)), 1684 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1685 ), 1686 Maps.sortedMap( 1687 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("1.1"), new BigDecimal("2.1"), new BigDecimal("3.1"), new BigDecimal("4.1"), new BigDecimal("5.1"), new BigDecimal("6.1"), new BigDecimal("7.1"), new BigDecimal("10.1"), new BigDecimal("100.1"), new BigDecimal("1000.1"))), 1688 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"))) 1689 ) 1690 ), 1691 1692 /** 1693 * Languages Include: 1694 * <p> 1695 * <ul> 1696 * <li>Maltese (mt)</li> 1697 * </ul> 1698 */ 1699 FAMILY_29( 1700 (n) -> { 1701 // n = 1 1702 if (equal(n, BIG_DECIMAL_1)) 1703 return ONE; 1704 // n = 0 or n % 100 = 2..10 1705 if (equal(n, BIG_DECIMAL_0) || inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_2, BIG_DECIMAL_10)) 1706 return FEW; 1707 // n % 100 = 11..19 1708 if (inRange(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_19)) 1709 return MANY; 1710 1711 return OTHER; 1712 }, 1713 Sets.sortedSet( 1714 ONE, 1715 FEW, 1716 MANY, 1717 OTHER 1718 ), 1719 Maps.sortedMap( 1720 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1721 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 102, 103, 104, 105, 106, 107, 1002)), 1722 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(11, 12, 13, 14, 15, 16, 17, 18, 19, 111, 112, 113, 114, 115, 116, 117, 1011)), 1723 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 100, 1000, 10000, 100000, 1000000)) 1724 ), 1725 Maps.sortedMap( 1726 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("10.1"))) 1727 ) 1728 ), 1729 1730 /** 1731 * Languages Include: 1732 * <p> 1733 * <ul> 1734 * <li>Polish (pl)</li> 1735 * </ul> 1736 */ 1737 FAMILY_30( 1738 (n) -> { 1739 int v = NumberUtils.numberOfDecimalPlaces(n); 1740 BigInteger i = NumberUtils.integerComponent(n); 1741 1742 // i = 1 and v = 0 1743 if (equal(i, BIG_INTEGER_1) && v == 0) 1744 return ONE; 1745 // v = 0 and i % 10 = 2..4 and i % 100 != 12..14 1746 if (v == 0 1747 && inRange(i.mod(BIG_INTEGER_10), BIG_INTEGER_2, BIG_INTEGER_4) 1748 && notInRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_12, BIG_INTEGER_14)) 1749 return FEW; 1750 // 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 1751 if ((v == 0 && notEqual(i, BIG_INTEGER_1) && inRange(i.mod(BIG_INTEGER_10), BIG_INTEGER_0, BIG_INTEGER_1)) 1752 || (v == 0 && inRange(i.mod(BIG_INTEGER_10), BIG_INTEGER_5, BIG_INTEGER_9)) 1753 || (v == 0 && inRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_12, BIG_INTEGER_14))) 1754 return MANY; 1755 1756 return OTHER; 1757 }, 1758 Sets.sortedSet( 1759 ONE, 1760 FEW, 1761 MANY, 1762 OTHER 1763 ), 1764 Maps.sortedMap( 1765 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(1)), 1766 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(2, 3, 4, 22, 23, 24, 32, 33, 34, 42, 43, 44, 52, 53, 54, 62, 102, 1002)), 1767 MapEntry.of(Cardinality.MANY, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1768 ), 1769 Maps.sortedMap( 1770 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 1771 ) 1772 ), 1773 1774 /** 1775 * Languages Include: 1776 * <p> 1777 * <ul> 1778 * <li>Portuguese (pt)</li> 1779 * </ul> 1780 */ 1781 FAMILY_31( 1782 (n) -> { 1783 BigInteger i = NumberUtils.integerComponent(n); 1784 1785 // i = 0..1 1786 if (inRange(i, BIG_INTEGER_0, BIG_INTEGER_1)) 1787 return ONE; 1788 1789 return OTHER; 1790 }, 1791 Sets.sortedSet( 1792 ONE, 1793 OTHER 1794 ), 1795 Maps.sortedMap( 1796 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1)), 1797 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1798 ), 1799 Maps.sortedMap( 1800 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))), 1801 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("2.0"), new BigDecimal("2.1"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"), new BigDecimal("2.8"), new BigDecimal("2.9"), new BigDecimal("3.0"), new BigDecimal("3.1"), new BigDecimal("3.2"), new BigDecimal("3.3"), new BigDecimal("3.4"), new BigDecimal("3.5"))) 1802 ) 1803 ), 1804 1805 /** 1806 * Languages Include: 1807 * <p> 1808 * <ul> 1809 * <li>Tachelhit (shi)</li> 1810 * </ul> 1811 */ 1812 FAMILY_32( 1813 (n) -> { 1814 BigInteger i = NumberUtils.integerComponent(n); 1815 1816 // i = 0 or n = 1 1817 if (equal(i, BIG_INTEGER_0) || equal(n, BIG_DECIMAL_1)) 1818 return ONE; 1819 // n = 2..10 1820 if (inRange(n, BIG_DECIMAL_2, BIG_DECIMAL_10)) 1821 return FEW; 1822 1823 return OTHER; 1824 }, 1825 Sets.sortedSet( 1826 ONE, 1827 FEW, 1828 OTHER 1829 ), 1830 Maps.sortedMap( 1831 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1)), 1832 MapEntry.of(Cardinality.FEW, Range.ofFiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10)), 1833 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 100, 1000, 10000, 100000, 1000000)) 1834 ), 1835 Maps.sortedMap( 1836 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.0"), new BigDecimal("0.01"), new BigDecimal("0.02"), new BigDecimal("0.03"), new BigDecimal("0.04"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"))), 1837 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("1.8"), new BigDecimal("1.9"), new BigDecimal("2.1"), new BigDecimal("2.2"), new BigDecimal("2.3"), new BigDecimal("2.4"), new BigDecimal("2.5"), new BigDecimal("2.6"), new BigDecimal("2.7"), new BigDecimal("10.1"))) 1838 ) 1839 ), 1840 1841 /** 1842 * Languages Include: 1843 * <p> 1844 * <ul> 1845 * <li>Sinhalese (si)</li> 1846 * </ul> 1847 */ 1848 FAMILY_33( 1849 (n) -> { 1850 BigInteger i = NumberUtils.integerComponent(n); 1851 BigInteger f = NumberUtils.fractionalComponent(n); 1852 1853 // n = 0,1 or i = 0 and f = 1 1854 if (inSet(n, BIG_DECIMAL_0, BIG_DECIMAL_1) 1855 || (equal(i, BIG_INTEGER_0) && equal(f, BIG_INTEGER_1))) 1856 return ONE; 1857 1858 return OTHER; 1859 }, 1860 Sets.sortedSet( 1861 ONE, 1862 OTHER 1863 ), 1864 Maps.sortedMap( 1865 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1)), 1866 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1867 ), 1868 Maps.sortedMap( 1869 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(new BigDecimal("0.0001"), new BigDecimal("0.001"), new BigDecimal("0.01"), new BigDecimal("0.1"))), 1870 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"), new BigDecimal("1.8"))) 1871 ) 1872 ), 1873 1874 /** 1875 * Languages Include: 1876 * <p> 1877 * <ul> 1878 * <li>Slovenian (sl)</li> 1879 * </ul> 1880 */ 1881 FAMILY_34( 1882 (n) -> { 1883 int v = NumberUtils.numberOfDecimalPlaces(n); 1884 BigInteger i = NumberUtils.integerComponent(n); 1885 1886 // v = 0 and i % 100 = 1 1887 if (v == 0 && equal(i.mod(BIG_INTEGER_100), BIG_INTEGER_1)) 1888 return ONE; 1889 // v = 0 and i % 100 = 2 1890 if (v == 0 && equal(i.mod(BIG_INTEGER_100), BIG_INTEGER_2)) 1891 return TWO; 1892 // v = 0 and i % 100 = 3..4 or v != 0 1893 if ((v == 0 && inRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_3, BIG_INTEGER_4)) 1894 || v != 0) 1895 return FEW; 1896 1897 return OTHER; 1898 }, 1899 Sets.sortedSet( 1900 ONE, 1901 TWO, 1902 FEW, 1903 OTHER 1904 ), 1905 Maps.sortedMap( 1906 MapEntry.of(Cardinality.ONE, Range.ofInfiniteValues(1, 101, 201, 301, 401, 501, 601, 701, 1001)), 1907 MapEntry.of(Cardinality.TWO, Range.ofInfiniteValues(2, 102, 202, 302, 402, 502, 602, 702, 1002)), 1908 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003)), 1909 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1910 ), 1911 Maps.sortedMap( 1912 MapEntry.of(Cardinality.FEW, Range.ofInfiniteValues(new BigDecimal("0.0"), new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.0"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"))) 1913 ) 1914 ), 1915 1916 /** 1917 * Languages Include: 1918 * <p> 1919 * <ul> 1920 * <li>Central Atlas Tamazight (tzm)</li> 1921 * </ul> 1922 */ 1923 FAMILY_35( 1924 (n) -> { 1925 // n = 0..1 or n = 11..99 1926 if (inRange(n, BIG_DECIMAL_0, BIG_DECIMAL_1) || inRange(n, BIG_DECIMAL_11, BIG_DECIMAL_99)) 1927 return ONE; 1928 1929 return OTHER; 1930 }, 1931 Sets.sortedSet( 1932 ONE, 1933 OTHER 1934 ), 1935 Maps.sortedMap( 1936 MapEntry.of(Cardinality.ONE, Range.ofFiniteValues(0, 1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24)), 1937 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 1000, 10000, 100000, 1000000)) 1938 ), 1939 Maps.sortedMap( 1940 MapEntry.of(Cardinality.OTHER, Range.ofInfiniteValues(new BigDecimal("0.1"), new BigDecimal("0.2"), new BigDecimal("0.3"), new BigDecimal("0.4"), new BigDecimal("0.5"), new BigDecimal("0.6"), new BigDecimal("0.7"), new BigDecimal("0.8"), new BigDecimal("0.9"), new BigDecimal("1.1"), new BigDecimal("1.2"), new BigDecimal("1.3"), new BigDecimal("1.4"), new BigDecimal("1.5"), new BigDecimal("1.6"), new BigDecimal("1.7"))) 1941 ) 1942 ); 1943 1944 @NonNull 1945 private static final Map<@NonNull String, @NonNull CardinalityFamily> CARDINALITY_FAMILIES_BY_LANGUAGE_CODE; 1946 @NonNull 1947 private static final SortedSet<@NonNull String> SUPPORTED_LANGUAGE_CODES; 1948 1949 @NonNull 1950 private final Function<BigDecimal, Cardinality> cardinalityFunction; 1951 @NonNull 1952 private final SortedSet<@NonNull Cardinality> supportedCardinalities; 1953 @NonNull 1954 private final SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull Integer>> exampleIntegerValuesByCardinality; 1955 @NonNull 1956 private final SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull BigDecimal>> exampleDecimalValuesByCardinality; 1957 1958 /** 1959 * Constructs a cardinality family. 1960 * 1961 * @param cardinalityFunction the cardinality-determining function for this cardinality family, not null 1962 * @param supportedCardinalities the cardinalities supported by this family sorted by the natural ordering of {@link Cardinality}, not null 1963 * @param exampleIntegerValuesByCardinality a mapping of cardinalities to example integer values for this cardinality family sorted by the natural ordering of {@link Cardinality}, not null 1964 * @param exampleDecimalValuesByCardinality a mapping of cardinalities to example decimal values for this cardinality family sorted by the natural ordering of {@link Cardinality}, not null 1965 */ 1966 CardinalityFamily(@NonNull Function<BigDecimal, Cardinality> cardinalityFunction, 1967 @NonNull SortedSet<@NonNull Cardinality> supportedCardinalities, 1968 @NonNull SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull Integer>> exampleIntegerValuesByCardinality, 1969 @NonNull SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull BigDecimal>> exampleDecimalValuesByCardinality) { 1970 requireNonNull(cardinalityFunction); 1971 requireNonNull(supportedCardinalities); 1972 requireNonNull(exampleIntegerValuesByCardinality); 1973 requireNonNull(exampleDecimalValuesByCardinality); 1974 1975 this.cardinalityFunction = cardinalityFunction; 1976 this.supportedCardinalities = supportedCardinalities; 1977 this.exampleIntegerValuesByCardinality = exampleIntegerValuesByCardinality; 1978 this.exampleDecimalValuesByCardinality = exampleDecimalValuesByCardinality; 1979 } 1980 1981 static { 1982 CARDINALITY_FAMILIES_BY_LANGUAGE_CODE = Collections.unmodifiableMap(new HashMap<@NonNull String, @NonNull CardinalityFamily>() {{ 1983 put("af", CardinalityFamily.FAMILY_1); // Afrikaans 1984 put("ak", CardinalityFamily.FAMILY_4); // Akan 1985 put("am", CardinalityFamily.FAMILY_5); // Amharic 1986 put("ar", CardinalityFamily.FAMILY_9); // Arabic 1987 put("ars", CardinalityFamily.FAMILY_9); // Najdi Arabic 1988 put("as", CardinalityFamily.FAMILY_5); // Assamese 1989 put("asa", CardinalityFamily.FAMILY_1); // Asu 1990 put("ast", CardinalityFamily.FAMILY_3); // Asturian 1991 put("az", CardinalityFamily.FAMILY_1); // Azeri 1992 put("be", CardinalityFamily.FAMILY_16); // Belarusian 1993 put("bem", CardinalityFamily.FAMILY_1); // Bemba 1994 put("bez", CardinalityFamily.FAMILY_1); // Bena 1995 put("bg", CardinalityFamily.FAMILY_1); // Bulgarian 1996 put("bh", CardinalityFamily.FAMILY_4); // Bihari 1997 put("bm", CardinalityFamily.FAMILY_2); // Bambara 1998 put("bn", CardinalityFamily.FAMILY_5); // Bangla 1999 put("bo", CardinalityFamily.FAMILY_2); // Tibetan 2000 put("br", CardinalityFamily.FAMILY_17); // Breton 2001 put("brx", CardinalityFamily.FAMILY_1); // Bodo 2002 put("bs", CardinalityFamily.FAMILY_7); // Bosnian 2003 put("ca", CardinalityFamily.FAMILY_3); // Catalan 2004 put("ce", CardinalityFamily.FAMILY_1); // Chechen 2005 put("cgg", CardinalityFamily.FAMILY_1); // Chiga 2006 put("chr", CardinalityFamily.FAMILY_1); // Cherokee 2007 put("ckb", CardinalityFamily.FAMILY_1); // Central Kurdish 2008 put("cs", CardinalityFamily.FAMILY_10); // Czech 2009 put("cy", CardinalityFamily.FAMILY_18); // Welsh 2010 put("da", CardinalityFamily.FAMILY_19); // Danish 2011 put("de", CardinalityFamily.FAMILY_3); // German 2012 put("dsb", CardinalityFamily.FAMILY_11); // Lower Sorbian 2013 put("dv", CardinalityFamily.FAMILY_1); // Divehi 2014 put("dz", CardinalityFamily.FAMILY_2); // Dzongkha 2015 put("ee", CardinalityFamily.FAMILY_1); // Ewe 2016 put("el", CardinalityFamily.FAMILY_1); // Greek 2017 put("en", CardinalityFamily.FAMILY_3); // English 2018 put("eo", CardinalityFamily.FAMILY_1); // Esperanto 2019 put("es", CardinalityFamily.FAMILY_1); // Spanish 2020 put("et", CardinalityFamily.FAMILY_3); // Estonian 2021 put("eu", CardinalityFamily.FAMILY_1); // Basque 2022 put("fa", CardinalityFamily.FAMILY_5); // Persian 2023 put("ff", CardinalityFamily.FAMILY_8); // Fulah 2024 put("fi", CardinalityFamily.FAMILY_3); // Finnish 2025 put("fil", CardinalityFamily.FAMILY_12); // Filipino 2026 put("fo", CardinalityFamily.FAMILY_1); // Faroese 2027 put("fr", CardinalityFamily.FAMILY_8); // French 2028 put("fur", CardinalityFamily.FAMILY_1); // Friulian 2029 put("fy", CardinalityFamily.FAMILY_3); // Western Frisian 2030 put("ga", CardinalityFamily.FAMILY_20); // Irish 2031 put("gd", CardinalityFamily.FAMILY_21); // Scottish Gaelic 2032 put("gl", CardinalityFamily.FAMILY_3); // Galician 2033 put("gsw", CardinalityFamily.FAMILY_1); // Swiss German 2034 put("gu", CardinalityFamily.FAMILY_5); // Gujarati 2035 put("guw", CardinalityFamily.FAMILY_4); // Gun 2036 put("gv", CardinalityFamily.FAMILY_22); // Manx 2037 put("ha", CardinalityFamily.FAMILY_1); // Hausa 2038 put("haw", CardinalityFamily.FAMILY_1); // Hawaiian 2039 put("he", CardinalityFamily.FAMILY_23); // Hebrew 2040 put("hi", CardinalityFamily.FAMILY_5); // Hindi 2041 put("hr", CardinalityFamily.FAMILY_7); // Croatian 2042 put("hsb", CardinalityFamily.FAMILY_11); // Upper Sorbian 2043 put("hu", CardinalityFamily.FAMILY_1); // Hungarian 2044 put("hy", CardinalityFamily.FAMILY_8); // Armenian 2045 put("id", CardinalityFamily.FAMILY_2); // Indonesian 2046 put("ig", CardinalityFamily.FAMILY_2); // Igbo 2047 put("ii", CardinalityFamily.FAMILY_2); // Sichuan Yi 2048 put("is", CardinalityFamily.FAMILY_24); // Icelandic 2049 put("it", CardinalityFamily.FAMILY_3); // Italian 2050 put("iu", CardinalityFamily.FAMILY_6); // Inuktitut 2051 put("ja", CardinalityFamily.FAMILY_2); // Japanese 2052 put("jbo", CardinalityFamily.FAMILY_2); // Lojban 2053 put("jgo", CardinalityFamily.FAMILY_1); // Ngomba 2054 put("jmc", CardinalityFamily.FAMILY_1); // Machame 2055 put("jv", CardinalityFamily.FAMILY_2); // Javanese 2056 put("jw", CardinalityFamily.FAMILY_2); // Javanese 2057 put("ka", CardinalityFamily.FAMILY_1); // Georgian 2058 put("kab", CardinalityFamily.FAMILY_8); // Kabyle 2059 put("kaj", CardinalityFamily.FAMILY_1); // Jju 2060 put("kcg", CardinalityFamily.FAMILY_1); // Tyap 2061 put("kde", CardinalityFamily.FAMILY_2); // Makonde 2062 put("kea", CardinalityFamily.FAMILY_2); // Kabuverdianu 2063 put("kk", CardinalityFamily.FAMILY_1); // Kazakh 2064 put("kkj", CardinalityFamily.FAMILY_1); // Kako 2065 put("kl", CardinalityFamily.FAMILY_1); // Greenlandic 2066 put("km", CardinalityFamily.FAMILY_2); // Khmer 2067 put("kn", CardinalityFamily.FAMILY_5); // Kannada 2068 put("ko", CardinalityFamily.FAMILY_2); // Korean 2069 put("ks", CardinalityFamily.FAMILY_1); // Kashmiri 2070 put("ksb", CardinalityFamily.FAMILY_1); // Shambala 2071 put("ksh", CardinalityFamily.FAMILY_25); // Colognian 2072 put("ku", CardinalityFamily.FAMILY_1); // Kurdish 2073 put("kw", CardinalityFamily.FAMILY_6); // Cornish 2074 put("ky", CardinalityFamily.FAMILY_1); // Kirghiz 2075 put("lag", CardinalityFamily.FAMILY_26); // Langi 2076 put("lb", CardinalityFamily.FAMILY_1); // Luxembourgish 2077 put("lg", CardinalityFamily.FAMILY_1); // Ganda 2078 put("lkt", CardinalityFamily.FAMILY_2); // Lakota 2079 put("ln", CardinalityFamily.FAMILY_4); // Lingala 2080 put("lo", CardinalityFamily.FAMILY_2); // Lao 2081 put("lt", CardinalityFamily.FAMILY_27); // Lithuanian 2082 put("lv", CardinalityFamily.FAMILY_13); // Latvian 2083 put("mas", CardinalityFamily.FAMILY_1); // Masai 2084 put("mg", CardinalityFamily.FAMILY_4); // Malagasy 2085 put("mgo", CardinalityFamily.FAMILY_1); // Metaʼ 2086 put("mk", CardinalityFamily.FAMILY_28); // Macedonian 2087 put("ml", CardinalityFamily.FAMILY_1); // Malayalam 2088 put("mn", CardinalityFamily.FAMILY_1); // Mongolian 2089 put("mo", CardinalityFamily.FAMILY_14); // Moldovan 2090 put("mr", CardinalityFamily.FAMILY_5); // Marathi 2091 put("ms", CardinalityFamily.FAMILY_2); // Malay 2092 put("mt", CardinalityFamily.FAMILY_29); // Maltese 2093 put("my", CardinalityFamily.FAMILY_2); // Burmese 2094 put("nah", CardinalityFamily.FAMILY_1); // Nahuatl 2095 put("naq", CardinalityFamily.FAMILY_6); // Nama 2096 put("nb", CardinalityFamily.FAMILY_1); // Norwegian Bokmål 2097 put("nd", CardinalityFamily.FAMILY_1); // North Ndebele 2098 put("ne", CardinalityFamily.FAMILY_1); // Nepali 2099 put("nl", CardinalityFamily.FAMILY_3); // Dutch 2100 put("nn", CardinalityFamily.FAMILY_1); // Norwegian Nynorsk 2101 put("nnh", CardinalityFamily.FAMILY_1); // Ngiemboon 2102 put("no", CardinalityFamily.FAMILY_1); // Norwegian 2103 put("nqo", CardinalityFamily.FAMILY_2); // N’Ko 2104 put("nr", CardinalityFamily.FAMILY_1); // South Ndebele 2105 put("nso", CardinalityFamily.FAMILY_4); // Northern Sotho 2106 put("ny", CardinalityFamily.FAMILY_1); // Nyanja 2107 put("nyn", CardinalityFamily.FAMILY_1); // Nyankole 2108 put("om", CardinalityFamily.FAMILY_1); // Oromo 2109 put("or", CardinalityFamily.FAMILY_1); // Odia 2110 put("os", CardinalityFamily.FAMILY_1); // Ossetian 2111 put("pa", CardinalityFamily.FAMILY_4); // Punjabi 2112 put("pap", CardinalityFamily.FAMILY_1); // Papiamento 2113 put("pl", CardinalityFamily.FAMILY_30); // Polish 2114 put("prg", CardinalityFamily.FAMILY_13); // Prussian 2115 put("ps", CardinalityFamily.FAMILY_1); // Pushto 2116 put("pt", CardinalityFamily.FAMILY_31); // Portuguese 2117 put("rm", CardinalityFamily.FAMILY_1); // Romansh 2118 put("ro", CardinalityFamily.FAMILY_14); // Romanian 2119 put("rof", CardinalityFamily.FAMILY_1); // Rombo 2120 put("root", CardinalityFamily.FAMILY_2); // Root 2121 put("ru", CardinalityFamily.FAMILY_15); // Russian 2122 put("rwk", CardinalityFamily.FAMILY_1); // Rwa 2123 put("sah", CardinalityFamily.FAMILY_2); // Sakha 2124 put("saq", CardinalityFamily.FAMILY_1); // Samburu 2125 put("sdh", CardinalityFamily.FAMILY_1); // Southern Kurdish 2126 put("se", CardinalityFamily.FAMILY_6); // Northern Sami 2127 put("seh", CardinalityFamily.FAMILY_1); // Sena 2128 put("ses", CardinalityFamily.FAMILY_2); // Koyraboro Senni 2129 put("sg", CardinalityFamily.FAMILY_2); // Sango 2130 put("sh", CardinalityFamily.FAMILY_7); // Serbo-Croatian 2131 put("shi", CardinalityFamily.FAMILY_32); // Tachelhit 2132 put("si", CardinalityFamily.FAMILY_33); // Sinhalese 2133 put("sk", CardinalityFamily.FAMILY_10); // Slovak 2134 put("sl", CardinalityFamily.FAMILY_34); // Slovenian 2135 put("sma", CardinalityFamily.FAMILY_6); // Southern Sami 2136 put("smi", CardinalityFamily.FAMILY_6); // Sami 2137 put("smj", CardinalityFamily.FAMILY_6); // Lule Sami 2138 put("smn", CardinalityFamily.FAMILY_6); // Inari Sami 2139 put("sms", CardinalityFamily.FAMILY_6); // Skolt Sami 2140 put("sn", CardinalityFamily.FAMILY_1); // Shona 2141 put("so", CardinalityFamily.FAMILY_1); // Somali 2142 put("sq", CardinalityFamily.FAMILY_1); // Albanian 2143 put("sr", CardinalityFamily.FAMILY_7); // Serbian 2144 put("ss", CardinalityFamily.FAMILY_1); // Swati 2145 put("ssy", CardinalityFamily.FAMILY_1); // Saho 2146 put("st", CardinalityFamily.FAMILY_1); // Southern Sotho 2147 put("sv", CardinalityFamily.FAMILY_3); // Swedish 2148 put("sw", CardinalityFamily.FAMILY_3); // Swahili 2149 put("syr", CardinalityFamily.FAMILY_1); // Syriac 2150 put("ta", CardinalityFamily.FAMILY_1); // Tamil 2151 put("te", CardinalityFamily.FAMILY_1); // Telugu 2152 put("teo", CardinalityFamily.FAMILY_1); // Teso 2153 put("th", CardinalityFamily.FAMILY_2); // Thai 2154 put("ti", CardinalityFamily.FAMILY_4); // Tigrinya 2155 put("tig", CardinalityFamily.FAMILY_1); // Tigre 2156 put("tk", CardinalityFamily.FAMILY_1); // Turkmen 2157 put("tl", CardinalityFamily.FAMILY_12); // Tagalog 2158 put("tn", CardinalityFamily.FAMILY_1); // Tswana 2159 put("to", CardinalityFamily.FAMILY_2); // Tongan 2160 put("tr", CardinalityFamily.FAMILY_1); // Turkish 2161 put("ts", CardinalityFamily.FAMILY_1); // Tsonga 2162 put("tzm", CardinalityFamily.FAMILY_35); // Central Atlas Tamazight 2163 put("ug", CardinalityFamily.FAMILY_1); // Uighur 2164 put("uk", CardinalityFamily.FAMILY_15); // Ukrainian 2165 put("ur", CardinalityFamily.FAMILY_3); // Urdu 2166 put("uz", CardinalityFamily.FAMILY_1); // Uzbek 2167 put("ve", CardinalityFamily.FAMILY_1); // Venda 2168 put("vi", CardinalityFamily.FAMILY_2); // Vietnamese 2169 put("vo", CardinalityFamily.FAMILY_1); // Volapük 2170 put("vun", CardinalityFamily.FAMILY_1); // Vunjo 2171 put("wa", CardinalityFamily.FAMILY_4); // Walloon 2172 put("wae", CardinalityFamily.FAMILY_1); // Walser 2173 put("wo", CardinalityFamily.FAMILY_2); // Wolof 2174 put("xh", CardinalityFamily.FAMILY_1); // Xhosa 2175 put("xog", CardinalityFamily.FAMILY_1); // Soga 2176 put("yi", CardinalityFamily.FAMILY_3); // Yiddish 2177 put("yo", CardinalityFamily.FAMILY_2); // Yoruba 2178 put("yue", CardinalityFamily.FAMILY_2); // Cantonese 2179 put("zh", CardinalityFamily.FAMILY_2); // Mandarin Chinese 2180 put("zu", CardinalityFamily.FAMILY_5); // Zulu 2181 }}); 2182 2183 // Language codes are in English - force collation for sorting 2184 SortedSet<@NonNull String> supportedLanguageCodes = new TreeSet<>(Collator.getInstance(Locale.ENGLISH)); 2185 supportedLanguageCodes.addAll(CARDINALITY_FAMILIES_BY_LANGUAGE_CODE.keySet()); 2186 2187 SUPPORTED_LANGUAGE_CODES = Collections.unmodifiableSortedSet(supportedLanguageCodes); 2188 } 2189 2190 /** 2191 * Gets the cardinality-determining function for this cardinality family. 2192 * <p> 2193 * The function takes a numeric value as input and returns the appropriate cardinal form. 2194 * <p> 2195 * The function's input must not be null and its output is guaranteed non-null. 2196 * 2197 * @return the cardinality-determining function for this cardinality family, not null 2198 */ 2199 @NonNull 2200 Function<BigDecimal, Cardinality> getCardinalityFunction() { 2201 return cardinalityFunction; 2202 } 2203 2204 /** 2205 * Gets the cardinalities supported by this cardinality family. 2206 * <p> 2207 * There will always be at least one value - {@link Cardinality#OTHER} - in the set. 2208 * <p> 2209 * The set's values are sorted by the natural ordering of the {@link Cardinality} enumeration. 2210 * 2211 * @return the cardinalities supported by this cardinality family, not null 2212 */ 2213 @NonNull 2214 SortedSet<@NonNull Cardinality> getSupportedCardinalities() { 2215 return supportedCardinalities; 2216 } 2217 2218 /** 2219 * Gets a mapping of cardinalities to example integer values for this cardinality family. 2220 * <p> 2221 * The map may be empty. 2222 * <p> 2223 * The map's keys are sorted by the natural ordering of the {@link Cardinality} enumeration. 2224 * 2225 * @return a mapping of cardinalities to example integer values, not null 2226 */ 2227 @NonNull 2228 SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull Integer>> getExampleIntegerValuesByCardinality() { 2229 return exampleIntegerValuesByCardinality; 2230 } 2231 2232 /** 2233 * Gets a mapping of cardinalities to example decimal values for this cardinality family. 2234 * <p> 2235 * The map may be empty. 2236 * <p> 2237 * The map's keys are sorted by the natural ordering of the {@link Cardinality} enumeration. 2238 * 2239 * @return a mapping of cardinalities to example decimal values, not null 2240 */ 2241 @NonNull 2242 SortedMap<@NonNull Cardinality, @NonNull Range<@NonNull BigDecimal>> getExampleDecimalValuesByCardinality() { 2243 return exampleDecimalValuesByCardinality; 2244 } 2245 2246 /** 2247 * Gets the ISO 639 language codes for which cardinality operations are supported. 2248 * <p> 2249 * The set's values are ISO 639 codes and therefore sorted using English collation. 2250 * 2251 * @return the ISO 639 language codes for which cardinality operations are supported, not null 2252 */ 2253 @NonNull 2254 static SortedSet<@NonNull String> getSupportedLanguageCodes() { 2255 return SUPPORTED_LANGUAGE_CODES; 2256 } 2257 2258 /** 2259 * Gets an appropriate plural cardinality family for the given locale. 2260 * 2261 * @param locale the locale to check, not null 2262 * @return the appropriate plural cardinality family (if one exists) for the given locale, not null 2263 */ 2264 @NonNull 2265 static Optional<CardinalityFamily> cardinalityFamilyForLocale(@NonNull Locale locale) { 2266 requireNonNull(locale); 2267 2268 String language = LocaleUtils.normalizedLanguage(locale).orElse(null); 2269 String country = locale.getCountry(); 2270 2271 CardinalityFamily cardinalityFamily = null; 2272 2273 if (language != null && country != null) 2274 cardinalityFamily = CARDINALITY_FAMILIES_BY_LANGUAGE_CODE.get(format("%s-%s", language, country)); 2275 2276 if (cardinalityFamily != null) 2277 return Optional.of(cardinalityFamily); 2278 2279 if (language != null) 2280 cardinalityFamily = CARDINALITY_FAMILIES_BY_LANGUAGE_CODE.get(language); 2281 2282 return Optional.ofNullable(cardinalityFamily); 2283 } 2284 } 2285 2286 2287 enum CardinalityRangeFamily { 2288 /** 2289 * Languages Include: 2290 * <p> 2291 * <ul> 2292 * <li>Akan (ak)</li> 2293 * <li>Najdi Arabic (ars)</li> 2294 * <li>Assamese (as)</li> 2295 * <li>Asu (asa)</li> 2296 * <li>Asturian (ast)</li> 2297 * <li>Bemba (bem)</li> 2298 * <li>Bena (bez)</li> 2299 * <li>Bihari (bh)</li> 2300 * <li>Bambara (bm)</li> 2301 * <li>Tibetan (bo)</li> 2302 * <li>Breton (br)</li> 2303 * <li>Bodo (brx)</li> 2304 * <li>Chechen (ce)</li> 2305 * <li>Chiga (cgg)</li> 2306 * <li>Cherokee (chr)</li> 2307 * <li>Central Kurdish (ckb)</li> 2308 * <li>Lower Sorbian (dsb)</li> 2309 * <li>Divehi (dv)</li> 2310 * <li>Dzongkha (dz)</li> 2311 * <li>Ewe (ee)</li> 2312 * <li>Esperanto (eo)</li> 2313 * <li>Fulah (ff)</li> 2314 * <li>Faroese (fo)</li> 2315 * <li>Friulian (fur)</li> 2316 * <li>Western Frisian (fy)</li> 2317 * <li>Scottish Gaelic (gd)</li> 2318 * <li>Gun (guw)</li> 2319 * <li>Manx (gv)</li> 2320 * <li>Hausa (ha)</li> 2321 * <li>Hawaiian (haw)</li> 2322 * <li>Upper Sorbian (hsb)</li> 2323 * <li>Igbo (ig)</li> 2324 * <li>Sichuan Yi (ii)</li> 2325 * <li>Inuktitut (iu)</li> 2326 * <li>Lojban (jbo)</li> 2327 * <li>Ngomba (jgo)</li> 2328 * <li>Machame (jmc)</li> 2329 * <li>Javanese (jv)</li> 2330 * <li>Javanese (jw)</li> 2331 * <li>Kabyle (kab)</li> 2332 * <li>Jju (kaj)</li> 2333 * <li>Tyap (kcg)</li> 2334 * <li>Makonde (kde)</li> 2335 * <li>Kabuverdianu (kea)</li> 2336 * <li>Kako (kkj)</li> 2337 * <li>Greenlandic (kl)</li> 2338 * <li>Kashmiri (ks)</li> 2339 * <li>Shambala (ksb)</li> 2340 * <li>Colognian (ksh)</li> 2341 * <li>Kurdish (ku)</li> 2342 * <li>Cornish (kw)</li> 2343 * <li>Langi (lag)</li> 2344 * <li>Luxembourgish (lb)</li> 2345 * <li>Ganda (lg)</li> 2346 * <li>Lakota (lkt)</li> 2347 * <li>Lingala (ln)</li> 2348 * <li>Masai (mas)</li> 2349 * <li>Malagasy (mg)</li> 2350 * <li>Metaʼ (mgo)</li> 2351 * <li>Moldovan (mo)</li> 2352 * <li>Maltese (mt)</li> 2353 * <li>Nahuatl (nah)</li> 2354 * <li>Nama (naq)</li> 2355 * <li>North Ndebele (nd)</li> 2356 * <li>Norwegian Nynorsk (nn)</li> 2357 * <li>Ngiemboon (nnh)</li> 2358 * <li>Norwegian (no)</li> 2359 * <li>N’Ko (nqo)</li> 2360 * <li>South Ndebele (nr)</li> 2361 * <li>Northern Sotho (nso)</li> 2362 * <li>Nyanja (ny)</li> 2363 * <li>Nyankole (nyn)</li> 2364 * <li>Oromo (om)</li> 2365 * <li>Odia (or)</li> 2366 * <li>Ossetian (os)</li> 2367 * <li>Papiamento (pap)</li> 2368 * <li>Prussian (prg)</li> 2369 * <li>Pushto (ps)</li> 2370 * <li>Romansh (rm)</li> 2371 * <li>Rombo (rof)</li> 2372 * <li>Root (root)</li> 2373 * <li>Rwa (rwk)</li> 2374 * <li>Sakha (sah)</li> 2375 * <li>Samburu (saq)</li> 2376 * <li>Southern Kurdish (sdh)</li> 2377 * <li>Northern Sami (se)</li> 2378 * <li>Sena (seh)</li> 2379 * <li>Koyraboro Senni (ses)</li> 2380 * <li>Sango (sg)</li> 2381 * <li>Serbo-Croatian (sh)</li> 2382 * <li>Tachelhit (shi)</li> 2383 * <li>Southern Sami (sma)</li> 2384 * <li>Sami (smi)</li> 2385 * <li>Lule Sami (smj)</li> 2386 * <li>Inari Sami (smn)</li> 2387 * <li>Skolt Sami (sms)</li> 2388 * <li>Shona (sn)</li> 2389 * <li>Somali (so)</li> 2390 * <li>Swati (ss)</li> 2391 * <li>Saho (ssy)</li> 2392 * <li>Southern Sotho (st)</li> 2393 * <li>Syriac (syr)</li> 2394 * <li>Teso (teo)</li> 2395 * <li>Tigrinya (ti)</li> 2396 * <li>Tigre (tig)</li> 2397 * <li>Turkmen (tk)</li> 2398 * <li>Tagalog (tl)</li> 2399 * <li>Tswana (tn)</li> 2400 * <li>Tongan (to)</li> 2401 * <li>Tsonga (ts)</li> 2402 * <li>Central Atlas Tamazight (tzm)</li> 2403 * <li>Venda (ve)</li> 2404 * <li>Volapük (vo)</li> 2405 * <li>Vunjo (vun)</li> 2406 * <li>Walloon (wa)</li> 2407 * <li>Walser (wae)</li> 2408 * <li>Wolof (wo)</li> 2409 * <li>Xhosa (xh)</li> 2410 * <li>Soga (xog)</li> 2411 * <li>Yiddish (yi)</li> 2412 * <li>Yoruba (yo)</li> 2413 * </ul> 2414 */ 2415 FAMILY_1( 2416 // There are no cardinality ranges for this family 2417 Collections.emptySortedMap() 2418 ), 2419 2420 /** 2421 * Languages Include: 2422 * <p> 2423 * <ul> 2424 * <li>Azeri (az)</li> 2425 * <li>German (de)</li> 2426 * <li>Greek (el)</li> 2427 * <li>Galician (gl)</li> 2428 * <li>Swiss German (gsw)</li> 2429 * <li>Hungarian (hu)</li> 2430 * <li>Italian (it)</li> 2431 * <li>Kazakh (kk)</li> 2432 * <li>Kirghiz (ky)</li> 2433 * <li>Malayalam (ml)</li> 2434 * <li>Mongolian (mn)</li> 2435 * <li>Nepali (ne)</li> 2436 * <li>Dutch (nl)</li> 2437 * <li>Albanian (sq)</li> 2438 * <li>Swahili (sw)</li> 2439 * <li>Tamil (ta)</li> 2440 * <li>Telugu (te)</li> 2441 * <li>Turkish (tr)</li> 2442 * <li>Uighur (ug)</li> 2443 * <li>Uzbek (uz)</li> 2444 * </ul> 2445 */ 2446 FAMILY_2( 2447 Maps.sortedMap( 2448 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2449 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2450 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2451 ) 2452 ), 2453 2454 /** 2455 * Languages Include: 2456 * <p> 2457 * <ul> 2458 * <li>Afrikaans (af)</li> 2459 * <li>Bulgarian (bg)</li> 2460 * <li>Catalan (ca)</li> 2461 * <li>English (en)</li> 2462 * <li>Spanish (es)</li> 2463 * <li>Estonian (et)</li> 2464 * <li>Basque (eu)</li> 2465 * <li>Finnish (fi)</li> 2466 * <li>Norwegian Bokmål (nb)</li> 2467 * <li>Swedish (sv)</li> 2468 * <li>Urdu (ur)</li> 2469 * </ul> 2470 */ 2471 FAMILY_3( 2472 Maps.sortedMap( 2473 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2474 MapEntry.of(CardinalityRange.of(OTHER, ONE), OTHER), 2475 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2476 ) 2477 ), 2478 2479 /** 2480 * Languages Include: 2481 * <p> 2482 * <ul> 2483 * <li>Indonesian (id)</li> 2484 * <li>Japanese (ja)</li> 2485 * <li>Khmer (km)</li> 2486 * <li>Korean (ko)</li> 2487 * <li>Lao (lo)</li> 2488 * <li>Malay (ms)</li> 2489 * <li>Burmese (my)</li> 2490 * <li>Thai (th)</li> 2491 * <li>Vietnamese (vi)</li> 2492 * <li>Cantonese (yue)</li> 2493 * <li>Mandarin Chinese (zh)</li> 2494 * </ul> 2495 */ 2496 FAMILY_4( 2497 Maps.sortedMap( 2498 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2499 ) 2500 ), 2501 2502 /** 2503 * Languages Include: 2504 * <p> 2505 * <ul> 2506 * <li>Amharic (am)</li> 2507 * <li>Bangla (bn)</li> 2508 * <li>French (fr)</li> 2509 * <li>Gujarati (gu)</li> 2510 * <li>Hindi (hi)</li> 2511 * <li>Armenian (hy)</li> 2512 * <li>Kannada (kn)</li> 2513 * <li>Marathi (mr)</li> 2514 * <li>Zulu (zu)</li> 2515 * </ul> 2516 */ 2517 FAMILY_5( 2518 Maps.sortedMap( 2519 MapEntry.of(CardinalityRange.of(ONE, ONE), ONE), 2520 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2521 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2522 ) 2523 ), 2524 2525 /** 2526 * Languages Include: 2527 * <p> 2528 * <ul> 2529 * <li>Danish (da)</li> 2530 * <li>Filipino (fil)</li> 2531 * <li>Icelandic (is)</li> 2532 * <li>Punjabi (pa)</li> 2533 * <li>Portuguese (pt)</li> 2534 * </ul> 2535 */ 2536 FAMILY_6( 2537 Maps.sortedMap( 2538 MapEntry.of(CardinalityRange.of(ONE, ONE), ONE), 2539 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2540 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2541 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2542 ) 2543 ), 2544 2545 /** 2546 * Languages Include: 2547 * <p> 2548 * <ul> 2549 * <li>Belarusian (be)</li> 2550 * <li>Lithuanian (lt)</li> 2551 * <li>Russian (ru)</li> 2552 * <li>Ukrainian (uk)</li> 2553 * </ul> 2554 */ 2555 FAMILY_7( 2556 Maps.sortedMap( 2557 MapEntry.of(CardinalityRange.of(ONE, ONE), ONE), 2558 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2559 MapEntry.of(CardinalityRange.of(ONE, MANY), MANY), 2560 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2561 MapEntry.of(CardinalityRange.of(FEW, ONE), ONE), 2562 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2563 MapEntry.of(CardinalityRange.of(FEW, MANY), MANY), 2564 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2565 MapEntry.of(CardinalityRange.of(MANY, ONE), ONE), 2566 MapEntry.of(CardinalityRange.of(MANY, FEW), FEW), 2567 MapEntry.of(CardinalityRange.of(MANY, MANY), MANY), 2568 MapEntry.of(CardinalityRange.of(MANY, OTHER), OTHER), 2569 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2570 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2571 MapEntry.of(CardinalityRange.of(OTHER, MANY), MANY), 2572 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2573 ) 2574 ), 2575 2576 /** 2577 * Languages Include: 2578 * <p> 2579 * <ul> 2580 * <li>Bosnian (bs)</li> 2581 * <li>Croatian (hr)</li> 2582 * <li>Serbian (sr)</li> 2583 * </ul> 2584 */ 2585 FAMILY_8( 2586 Maps.sortedMap( 2587 MapEntry.of(CardinalityRange.of(ONE, ONE), ONE), 2588 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2589 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2590 MapEntry.of(CardinalityRange.of(FEW, ONE), ONE), 2591 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2592 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2593 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2594 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2595 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2596 ) 2597 ), 2598 2599 /** 2600 * Languages Include: 2601 * <p> 2602 * <ul> 2603 * <li>Czech (cs)</li> 2604 * <li>Polish (pl)</li> 2605 * <li>Slovak (sk)</li> 2606 * </ul> 2607 */ 2608 FAMILY_9( 2609 Maps.sortedMap( 2610 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2611 MapEntry.of(CardinalityRange.of(ONE, MANY), MANY), 2612 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2613 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2614 MapEntry.of(CardinalityRange.of(FEW, MANY), MANY), 2615 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2616 MapEntry.of(CardinalityRange.of(MANY, ONE), ONE), 2617 MapEntry.of(CardinalityRange.of(MANY, FEW), FEW), 2618 MapEntry.of(CardinalityRange.of(MANY, MANY), MANY), 2619 MapEntry.of(CardinalityRange.of(MANY, OTHER), OTHER), 2620 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2621 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2622 MapEntry.of(CardinalityRange.of(OTHER, MANY), MANY), 2623 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2624 ) 2625 ), 2626 2627 /** 2628 * Languages Include: 2629 * <p> 2630 * <ul> 2631 * <li>Arabic (ar)</li> 2632 * </ul> 2633 */ 2634 FAMILY_10( 2635 Maps.sortedMap( 2636 MapEntry.of(CardinalityRange.of(ZERO, ONE), ZERO), 2637 MapEntry.of(CardinalityRange.of(ZERO, TWO), ZERO), 2638 MapEntry.of(CardinalityRange.of(ZERO, FEW), FEW), 2639 MapEntry.of(CardinalityRange.of(ZERO, MANY), MANY), 2640 MapEntry.of(CardinalityRange.of(ZERO, OTHER), OTHER), 2641 MapEntry.of(CardinalityRange.of(ONE, TWO), OTHER), 2642 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2643 MapEntry.of(CardinalityRange.of(ONE, MANY), MANY), 2644 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2645 MapEntry.of(CardinalityRange.of(TWO, FEW), FEW), 2646 MapEntry.of(CardinalityRange.of(TWO, MANY), MANY), 2647 MapEntry.of(CardinalityRange.of(TWO, OTHER), OTHER), 2648 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2649 MapEntry.of(CardinalityRange.of(FEW, MANY), MANY), 2650 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2651 MapEntry.of(CardinalityRange.of(MANY, FEW), FEW), 2652 MapEntry.of(CardinalityRange.of(MANY, MANY), MANY), 2653 MapEntry.of(CardinalityRange.of(MANY, OTHER), OTHER), 2654 MapEntry.of(CardinalityRange.of(OTHER, ONE), OTHER), 2655 MapEntry.of(CardinalityRange.of(OTHER, TWO), OTHER), 2656 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2657 MapEntry.of(CardinalityRange.of(OTHER, MANY), MANY), 2658 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2659 ) 2660 ), 2661 2662 /** 2663 * Languages Include: 2664 * <p> 2665 * <ul> 2666 * <li>Welsh (cy)</li> 2667 * </ul> 2668 */ 2669 FAMILY_11( 2670 Maps.sortedMap( 2671 MapEntry.of(CardinalityRange.of(ZERO, ONE), ONE), 2672 MapEntry.of(CardinalityRange.of(ZERO, TWO), TWO), 2673 MapEntry.of(CardinalityRange.of(ZERO, FEW), FEW), 2674 MapEntry.of(CardinalityRange.of(ZERO, MANY), MANY), 2675 MapEntry.of(CardinalityRange.of(ZERO, OTHER), OTHER), 2676 MapEntry.of(CardinalityRange.of(ONE, TWO), TWO), 2677 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2678 MapEntry.of(CardinalityRange.of(ONE, MANY), MANY), 2679 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2680 MapEntry.of(CardinalityRange.of(TWO, FEW), FEW), 2681 MapEntry.of(CardinalityRange.of(TWO, MANY), MANY), 2682 MapEntry.of(CardinalityRange.of(TWO, OTHER), OTHER), 2683 MapEntry.of(CardinalityRange.of(FEW, MANY), MANY), 2684 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2685 MapEntry.of(CardinalityRange.of(MANY, OTHER), OTHER), 2686 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2687 MapEntry.of(CardinalityRange.of(OTHER, TWO), TWO), 2688 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2689 MapEntry.of(CardinalityRange.of(OTHER, MANY), MANY), 2690 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2691 ) 2692 ), 2693 2694 /** 2695 * Languages Include: 2696 * <p> 2697 * <ul> 2698 * <li>Persian (fa)</li> 2699 * </ul> 2700 */ 2701 FAMILY_12( 2702 Maps.sortedMap( 2703 MapEntry.of(CardinalityRange.of(ONE, ONE), OTHER), 2704 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2705 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2706 ) 2707 ), 2708 2709 /** 2710 * Languages Include: 2711 * <p> 2712 * <ul> 2713 * <li>Irish (ga)</li> 2714 * </ul> 2715 */ 2716 FAMILY_13( 2717 Maps.sortedMap( 2718 MapEntry.of(CardinalityRange.of(ONE, TWO), TWO), 2719 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2720 MapEntry.of(CardinalityRange.of(ONE, MANY), MANY), 2721 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2722 MapEntry.of(CardinalityRange.of(TWO, FEW), FEW), 2723 MapEntry.of(CardinalityRange.of(TWO, MANY), MANY), 2724 MapEntry.of(CardinalityRange.of(TWO, OTHER), OTHER), 2725 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2726 MapEntry.of(CardinalityRange.of(FEW, MANY), MANY), 2727 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2728 MapEntry.of(CardinalityRange.of(MANY, MANY), MANY), 2729 MapEntry.of(CardinalityRange.of(MANY, OTHER), OTHER), 2730 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2731 MapEntry.of(CardinalityRange.of(OTHER, TWO), TWO), 2732 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2733 MapEntry.of(CardinalityRange.of(OTHER, MANY), MANY), 2734 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2735 ) 2736 ), 2737 2738 /** 2739 * Languages Include: 2740 * <p> 2741 * <ul> 2742 * <li>Hebrew (he)</li> 2743 * </ul> 2744 */ 2745 FAMILY_14( 2746 Maps.sortedMap( 2747 MapEntry.of(CardinalityRange.of(ONE, TWO), OTHER), 2748 MapEntry.of(CardinalityRange.of(ONE, MANY), MANY), 2749 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2750 MapEntry.of(CardinalityRange.of(TWO, MANY), OTHER), 2751 MapEntry.of(CardinalityRange.of(TWO, OTHER), OTHER), 2752 MapEntry.of(CardinalityRange.of(MANY, MANY), MANY), 2753 MapEntry.of(CardinalityRange.of(MANY, OTHER), MANY), 2754 MapEntry.of(CardinalityRange.of(OTHER, ONE), OTHER), 2755 MapEntry.of(CardinalityRange.of(OTHER, TWO), OTHER), 2756 MapEntry.of(CardinalityRange.of(OTHER, MANY), MANY), 2757 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2758 ) 2759 ), 2760 2761 /** 2762 * Languages Include: 2763 * <p> 2764 * <ul> 2765 * <li>Georgian (ka)</li> 2766 * </ul> 2767 */ 2768 FAMILY_15( 2769 Maps.sortedMap( 2770 MapEntry.of(CardinalityRange.of(ONE, OTHER), ONE), 2771 MapEntry.of(CardinalityRange.of(OTHER, ONE), OTHER), 2772 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2773 ) 2774 ), 2775 2776 /** 2777 * Languages Include: 2778 * <p> 2779 * <ul> 2780 * <li>Latvian (lv)</li> 2781 * </ul> 2782 */ 2783 FAMILY_16( 2784 Maps.sortedMap( 2785 MapEntry.of(CardinalityRange.of(ZERO, ZERO), OTHER), 2786 MapEntry.of(CardinalityRange.of(ZERO, ONE), ONE), 2787 MapEntry.of(CardinalityRange.of(ZERO, OTHER), OTHER), 2788 MapEntry.of(CardinalityRange.of(ONE, ZERO), OTHER), 2789 MapEntry.of(CardinalityRange.of(ONE, ONE), ONE), 2790 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2791 MapEntry.of(CardinalityRange.of(OTHER, ZERO), OTHER), 2792 MapEntry.of(CardinalityRange.of(OTHER, ONE), ONE), 2793 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2794 ) 2795 ), 2796 2797 /** 2798 * Languages Include: 2799 * <p> 2800 * <ul> 2801 * <li>Macedonian (mk)</li> 2802 * </ul> 2803 */ 2804 FAMILY_17( 2805 Maps.sortedMap( 2806 MapEntry.of(CardinalityRange.of(ONE, ONE), OTHER), 2807 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2808 MapEntry.of(CardinalityRange.of(OTHER, ONE), OTHER), 2809 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2810 ) 2811 ), 2812 2813 /** 2814 * Languages Include: 2815 * <p> 2816 * <ul> 2817 * <li>Romanian (ro)</li> 2818 * </ul> 2819 */ 2820 FAMILY_18( 2821 Maps.sortedMap( 2822 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2823 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2824 MapEntry.of(CardinalityRange.of(FEW, ONE), FEW), 2825 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2826 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2827 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2828 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2829 ) 2830 ), 2831 2832 /** 2833 * Languages Include: 2834 * <p> 2835 * <ul> 2836 * <li>Sinhalese (si)</li> 2837 * </ul> 2838 */ 2839 FAMILY_19( 2840 Maps.sortedMap( 2841 MapEntry.of(CardinalityRange.of(ONE, ONE), ONE), 2842 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2843 MapEntry.of(CardinalityRange.of(OTHER, ONE), OTHER), 2844 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2845 ) 2846 ), 2847 2848 /** 2849 * Languages Include: 2850 * <p> 2851 * <ul> 2852 * <li>Slovenian (sl)</li> 2853 * </ul> 2854 */ 2855 FAMILY_20( 2856 Maps.sortedMap( 2857 MapEntry.of(CardinalityRange.of(ONE, ONE), FEW), 2858 MapEntry.of(CardinalityRange.of(ONE, TWO), TWO), 2859 MapEntry.of(CardinalityRange.of(ONE, FEW), FEW), 2860 MapEntry.of(CardinalityRange.of(ONE, OTHER), OTHER), 2861 MapEntry.of(CardinalityRange.of(TWO, ONE), FEW), 2862 MapEntry.of(CardinalityRange.of(TWO, TWO), TWO), 2863 MapEntry.of(CardinalityRange.of(TWO, FEW), FEW), 2864 MapEntry.of(CardinalityRange.of(TWO, OTHER), OTHER), 2865 MapEntry.of(CardinalityRange.of(FEW, ONE), FEW), 2866 MapEntry.of(CardinalityRange.of(FEW, TWO), TWO), 2867 MapEntry.of(CardinalityRange.of(FEW, FEW), FEW), 2868 MapEntry.of(CardinalityRange.of(FEW, OTHER), OTHER), 2869 MapEntry.of(CardinalityRange.of(OTHER, ONE), FEW), 2870 MapEntry.of(CardinalityRange.of(OTHER, TWO), TWO), 2871 MapEntry.of(CardinalityRange.of(OTHER, FEW), FEW), 2872 MapEntry.of(CardinalityRange.of(OTHER, OTHER), OTHER) 2873 ) 2874 ); 2875 2876 @NonNull 2877 private static final Map<@NonNull String, @NonNull CardinalityRangeFamily> CARDINALITY_RANGE_FAMILIES_BY_LANGUAGE_CODE; 2878 2879 @NonNull 2880 private final SortedMap<@NonNull CardinalityRange, @NonNull Cardinality> cardinalitiesByCardinalityRange; 2881 2882 static { 2883 CARDINALITY_RANGE_FAMILIES_BY_LANGUAGE_CODE = Collections.unmodifiableMap(new HashMap<@NonNull String, @NonNull CardinalityRangeFamily>() { 2884 { 2885 put("af", CardinalityRangeFamily.FAMILY_3); // Afrikaans 2886 put("ak", CardinalityRangeFamily.FAMILY_1); // Akan 2887 put("am", CardinalityRangeFamily.FAMILY_5); // Amharic 2888 put("ar", CardinalityRangeFamily.FAMILY_10); // Arabic 2889 put("ars", CardinalityRangeFamily.FAMILY_1); // Najdi Arabic 2890 put("as", CardinalityRangeFamily.FAMILY_1); // Assamese 2891 put("asa", CardinalityRangeFamily.FAMILY_1); // Asu 2892 put("ast", CardinalityRangeFamily.FAMILY_1); // Asturian 2893 put("az", CardinalityRangeFamily.FAMILY_2); // Azeri 2894 put("be", CardinalityRangeFamily.FAMILY_7); // Belarusian 2895 put("bem", CardinalityRangeFamily.FAMILY_1); // Bemba 2896 put("bez", CardinalityRangeFamily.FAMILY_1); // Bena 2897 put("bg", CardinalityRangeFamily.FAMILY_3); // Bulgarian 2898 put("bh", CardinalityRangeFamily.FAMILY_1); // Bihari 2899 put("bm", CardinalityRangeFamily.FAMILY_1); // Bambara 2900 put("bn", CardinalityRangeFamily.FAMILY_5); // Bangla 2901 put("bo", CardinalityRangeFamily.FAMILY_1); // Tibetan 2902 put("br", CardinalityRangeFamily.FAMILY_1); // Breton 2903 put("brx", CardinalityRangeFamily.FAMILY_1); // Bodo 2904 put("bs", CardinalityRangeFamily.FAMILY_8); // Bosnian 2905 put("ca", CardinalityRangeFamily.FAMILY_3); // Catalan 2906 put("ce", CardinalityRangeFamily.FAMILY_1); // Chechen 2907 put("cgg", CardinalityRangeFamily.FAMILY_1); // Chiga 2908 put("chr", CardinalityRangeFamily.FAMILY_1); // Cherokee 2909 put("ckb", CardinalityRangeFamily.FAMILY_1); // Central Kurdish 2910 put("cs", CardinalityRangeFamily.FAMILY_9); // Czech 2911 put("cy", CardinalityRangeFamily.FAMILY_11); // Welsh 2912 put("da", CardinalityRangeFamily.FAMILY_6); // Danish 2913 put("de", CardinalityRangeFamily.FAMILY_2); // German 2914 put("dsb", CardinalityRangeFamily.FAMILY_1); // Lower Sorbian 2915 put("dv", CardinalityRangeFamily.FAMILY_1); // Divehi 2916 put("dz", CardinalityRangeFamily.FAMILY_1); // Dzongkha 2917 put("ee", CardinalityRangeFamily.FAMILY_1); // Ewe 2918 put("el", CardinalityRangeFamily.FAMILY_2); // Greek 2919 put("en", CardinalityRangeFamily.FAMILY_3); // English 2920 put("eo", CardinalityRangeFamily.FAMILY_1); // Esperanto 2921 put("es", CardinalityRangeFamily.FAMILY_3); // Spanish 2922 put("et", CardinalityRangeFamily.FAMILY_3); // Estonian 2923 put("eu", CardinalityRangeFamily.FAMILY_3); // Basque 2924 put("fa", CardinalityRangeFamily.FAMILY_12); // Persian 2925 put("ff", CardinalityRangeFamily.FAMILY_1); // Fulah 2926 put("fi", CardinalityRangeFamily.FAMILY_3); // Finnish 2927 put("fil", CardinalityRangeFamily.FAMILY_6); // Filipino 2928 put("fo", CardinalityRangeFamily.FAMILY_1); // Faroese 2929 put("fr", CardinalityRangeFamily.FAMILY_5); // French 2930 put("fur", CardinalityRangeFamily.FAMILY_1); // Friulian 2931 put("fy", CardinalityRangeFamily.FAMILY_1); // Western Frisian 2932 put("ga", CardinalityRangeFamily.FAMILY_13); // Irish 2933 put("gd", CardinalityRangeFamily.FAMILY_1); // Scottish Gaelic 2934 put("gl", CardinalityRangeFamily.FAMILY_2); // Galician 2935 put("gsw", CardinalityRangeFamily.FAMILY_2); // Swiss German 2936 put("gu", CardinalityRangeFamily.FAMILY_5); // Gujarati 2937 put("guw", CardinalityRangeFamily.FAMILY_1); // Gun 2938 put("gv", CardinalityRangeFamily.FAMILY_1); // Manx 2939 put("ha", CardinalityRangeFamily.FAMILY_1); // Hausa 2940 put("haw", CardinalityRangeFamily.FAMILY_1); // Hawaiian 2941 put("he", CardinalityRangeFamily.FAMILY_14); // Hebrew 2942 put("hi", CardinalityRangeFamily.FAMILY_5); // Hindi 2943 put("hr", CardinalityRangeFamily.FAMILY_8); // Croatian 2944 put("hsb", CardinalityRangeFamily.FAMILY_1); // Upper Sorbian 2945 put("hu", CardinalityRangeFamily.FAMILY_2); // Hungarian 2946 put("hy", CardinalityRangeFamily.FAMILY_5); // Armenian 2947 put("id", CardinalityRangeFamily.FAMILY_4); // Indonesian 2948 put("ig", CardinalityRangeFamily.FAMILY_1); // Igbo 2949 put("ii", CardinalityRangeFamily.FAMILY_1); // Sichuan Yi 2950 put("is", CardinalityRangeFamily.FAMILY_6); // Icelandic 2951 put("it", CardinalityRangeFamily.FAMILY_2); // Italian 2952 put("iu", CardinalityRangeFamily.FAMILY_1); // Inuktitut 2953 put("ja", CardinalityRangeFamily.FAMILY_4); // Japanese 2954 put("jbo", CardinalityRangeFamily.FAMILY_1); // Lojban 2955 put("jgo", CardinalityRangeFamily.FAMILY_1); // Ngomba 2956 put("jmc", CardinalityRangeFamily.FAMILY_1); // Machame 2957 put("jv", CardinalityRangeFamily.FAMILY_1); // Javanese 2958 put("jw", CardinalityRangeFamily.FAMILY_1); // Javanese 2959 put("ka", CardinalityRangeFamily.FAMILY_15); // Georgian 2960 put("kab", CardinalityRangeFamily.FAMILY_1); // Kabyle 2961 put("kaj", CardinalityRangeFamily.FAMILY_1); // Jju 2962 put("kcg", CardinalityRangeFamily.FAMILY_1); // Tyap 2963 put("kde", CardinalityRangeFamily.FAMILY_1); // Makonde 2964 put("kea", CardinalityRangeFamily.FAMILY_1); // Kabuverdianu 2965 put("kk", CardinalityRangeFamily.FAMILY_2); // Kazakh 2966 put("kkj", CardinalityRangeFamily.FAMILY_1); // Kako 2967 put("kl", CardinalityRangeFamily.FAMILY_1); // Greenlandic 2968 put("km", CardinalityRangeFamily.FAMILY_4); // Khmer 2969 put("kn", CardinalityRangeFamily.FAMILY_5); // Kannada 2970 put("ko", CardinalityRangeFamily.FAMILY_4); // Korean 2971 put("ks", CardinalityRangeFamily.FAMILY_1); // Kashmiri 2972 put("ksb", CardinalityRangeFamily.FAMILY_1); // Shambala 2973 put("ksh", CardinalityRangeFamily.FAMILY_1); // Colognian 2974 put("ku", CardinalityRangeFamily.FAMILY_1); // Kurdish 2975 put("kw", CardinalityRangeFamily.FAMILY_1); // Cornish 2976 put("ky", CardinalityRangeFamily.FAMILY_2); // Kirghiz 2977 put("lag", CardinalityRangeFamily.FAMILY_1); // Langi 2978 put("lb", CardinalityRangeFamily.FAMILY_1); // Luxembourgish 2979 put("lg", CardinalityRangeFamily.FAMILY_1); // Ganda 2980 put("lkt", CardinalityRangeFamily.FAMILY_1); // Lakota 2981 put("ln", CardinalityRangeFamily.FAMILY_1); // Lingala 2982 put("lo", CardinalityRangeFamily.FAMILY_4); // Lao 2983 put("lt", CardinalityRangeFamily.FAMILY_7); // Lithuanian 2984 put("lv", CardinalityRangeFamily.FAMILY_16); // Latvian 2985 put("mas", CardinalityRangeFamily.FAMILY_1); // Masai 2986 put("mg", CardinalityRangeFamily.FAMILY_1); // Malagasy 2987 put("mgo", CardinalityRangeFamily.FAMILY_1); // Metaʼ 2988 put("mk", CardinalityRangeFamily.FAMILY_17); // Macedonian 2989 put("ml", CardinalityRangeFamily.FAMILY_2); // Malayalam 2990 put("mn", CardinalityRangeFamily.FAMILY_2); // Mongolian 2991 put("mo", CardinalityRangeFamily.FAMILY_1); // Moldovan 2992 put("mr", CardinalityRangeFamily.FAMILY_5); // Marathi 2993 put("ms", CardinalityRangeFamily.FAMILY_4); // Malay 2994 put("mt", CardinalityRangeFamily.FAMILY_1); // Maltese 2995 put("my", CardinalityRangeFamily.FAMILY_4); // Burmese 2996 put("nah", CardinalityRangeFamily.FAMILY_1); // Nahuatl 2997 put("naq", CardinalityRangeFamily.FAMILY_1); // Nama 2998 put("nb", CardinalityRangeFamily.FAMILY_3); // Norwegian Bokmål 2999 put("nd", CardinalityRangeFamily.FAMILY_1); // North Ndebele 3000 put("ne", CardinalityRangeFamily.FAMILY_2); // Nepali 3001 put("nl", CardinalityRangeFamily.FAMILY_2); // Dutch 3002 put("nn", CardinalityRangeFamily.FAMILY_1); // Norwegian Nynorsk 3003 put("nnh", CardinalityRangeFamily.FAMILY_1); // Ngiemboon 3004 put("no", CardinalityRangeFamily.FAMILY_1); // Norwegian 3005 put("nqo", CardinalityRangeFamily.FAMILY_1); // N’Ko 3006 put("nr", CardinalityRangeFamily.FAMILY_1); // South Ndebele 3007 put("nso", CardinalityRangeFamily.FAMILY_1); // Northern Sotho 3008 put("ny", CardinalityRangeFamily.FAMILY_1); // Nyanja 3009 put("nyn", CardinalityRangeFamily.FAMILY_1); // Nyankole 3010 put("om", CardinalityRangeFamily.FAMILY_1); // Oromo 3011 put("or", CardinalityRangeFamily.FAMILY_1); // Odia 3012 put("os", CardinalityRangeFamily.FAMILY_1); // Ossetian 3013 put("pa", CardinalityRangeFamily.FAMILY_6); // Punjabi 3014 put("pap", CardinalityRangeFamily.FAMILY_1); // Papiamento 3015 put("pl", CardinalityRangeFamily.FAMILY_9); // Polish 3016 put("prg", CardinalityRangeFamily.FAMILY_1); // Prussian 3017 put("ps", CardinalityRangeFamily.FAMILY_1); // Pushto 3018 put("pt", CardinalityRangeFamily.FAMILY_6); // Portuguese 3019 put("rm", CardinalityRangeFamily.FAMILY_1); // Romansh 3020 put("ro", CardinalityRangeFamily.FAMILY_18); // Romanian 3021 put("rof", CardinalityRangeFamily.FAMILY_1); // Rombo 3022 put("root", CardinalityRangeFamily.FAMILY_1); // Root 3023 put("ru", CardinalityRangeFamily.FAMILY_7); // Russian 3024 put("rwk", CardinalityRangeFamily.FAMILY_1); // Rwa 3025 put("sah", CardinalityRangeFamily.FAMILY_1); // Sakha 3026 put("saq", CardinalityRangeFamily.FAMILY_1); // Samburu 3027 put("sdh", CardinalityRangeFamily.FAMILY_1); // Southern Kurdish 3028 put("se", CardinalityRangeFamily.FAMILY_1); // Northern Sami 3029 put("seh", CardinalityRangeFamily.FAMILY_1); // Sena 3030 put("ses", CardinalityRangeFamily.FAMILY_1); // Koyraboro Senni 3031 put("sg", CardinalityRangeFamily.FAMILY_1); // Sango 3032 put("sh", CardinalityRangeFamily.FAMILY_1); // Serbo-Croatian 3033 put("shi", CardinalityRangeFamily.FAMILY_1); // Tachelhit 3034 put("si", CardinalityRangeFamily.FAMILY_19); // Sinhalese 3035 put("sk", CardinalityRangeFamily.FAMILY_9); // Slovak 3036 put("sl", CardinalityRangeFamily.FAMILY_20); // Slovenian 3037 put("sma", CardinalityRangeFamily.FAMILY_1); // Southern Sami 3038 put("smi", CardinalityRangeFamily.FAMILY_1); // Sami 3039 put("smj", CardinalityRangeFamily.FAMILY_1); // Lule Sami 3040 put("smn", CardinalityRangeFamily.FAMILY_1); // Inari Sami 3041 put("sms", CardinalityRangeFamily.FAMILY_1); // Skolt Sami 3042 put("sn", CardinalityRangeFamily.FAMILY_1); // Shona 3043 put("so", CardinalityRangeFamily.FAMILY_1); // Somali 3044 put("sq", CardinalityRangeFamily.FAMILY_2); // Albanian 3045 put("sr", CardinalityRangeFamily.FAMILY_8); // Serbian 3046 put("ss", CardinalityRangeFamily.FAMILY_1); // Swati 3047 put("ssy", CardinalityRangeFamily.FAMILY_1); // Saho 3048 put("st", CardinalityRangeFamily.FAMILY_1); // Southern Sotho 3049 put("sv", CardinalityRangeFamily.FAMILY_3); // Swedish 3050 put("sw", CardinalityRangeFamily.FAMILY_2); // Swahili 3051 put("syr", CardinalityRangeFamily.FAMILY_1); // Syriac 3052 put("ta", CardinalityRangeFamily.FAMILY_2); // Tamil 3053 put("te", CardinalityRangeFamily.FAMILY_2); // Telugu 3054 put("teo", CardinalityRangeFamily.FAMILY_1); // Teso 3055 put("th", CardinalityRangeFamily.FAMILY_4); // Thai 3056 put("ti", CardinalityRangeFamily.FAMILY_1); // Tigrinya 3057 put("tig", CardinalityRangeFamily.FAMILY_1); // Tigre 3058 put("tk", CardinalityRangeFamily.FAMILY_1); // Turkmen 3059 put("tl", CardinalityRangeFamily.FAMILY_1); // Tagalog 3060 put("tn", CardinalityRangeFamily.FAMILY_1); // Tswana 3061 put("to", CardinalityRangeFamily.FAMILY_1); // Tongan 3062 put("tr", CardinalityRangeFamily.FAMILY_2); // Turkish 3063 put("ts", CardinalityRangeFamily.FAMILY_1); // Tsonga 3064 put("tzm", CardinalityRangeFamily.FAMILY_1); // Central Atlas Tamazight 3065 put("ug", CardinalityRangeFamily.FAMILY_2); // Uighur 3066 put("uk", CardinalityRangeFamily.FAMILY_7); // Ukrainian 3067 put("ur", CardinalityRangeFamily.FAMILY_3); // Urdu 3068 put("uz", CardinalityRangeFamily.FAMILY_2); // Uzbek 3069 put("ve", CardinalityRangeFamily.FAMILY_1); // Venda 3070 put("vi", CardinalityRangeFamily.FAMILY_4); // Vietnamese 3071 put("vo", CardinalityRangeFamily.FAMILY_1); // Volapük 3072 put("vun", CardinalityRangeFamily.FAMILY_1); // Vunjo 3073 put("wa", CardinalityRangeFamily.FAMILY_1); // Walloon 3074 put("wae", CardinalityRangeFamily.FAMILY_1); // Walser 3075 put("wo", CardinalityRangeFamily.FAMILY_1); // Wolof 3076 put("xh", CardinalityRangeFamily.FAMILY_1); // Xhosa 3077 put("xog", CardinalityRangeFamily.FAMILY_1); // Soga 3078 put("yi", CardinalityRangeFamily.FAMILY_1); // Yiddish 3079 put("yo", CardinalityRangeFamily.FAMILY_1); // Yoruba 3080 put("yue", CardinalityRangeFamily.FAMILY_4); // Cantonese 3081 put("zh", CardinalityRangeFamily.FAMILY_4); // Mandarin Chinese 3082 put("zu", CardinalityRangeFamily.FAMILY_5); // Zulu 3083 } 3084 }); 3085 } 3086 3087 /** 3088 * Gets an appropriate plural cardinality range family for the given locale. 3089 * 3090 * @param locale the locale to check, not null 3091 * @return the appropriate plural cardinality range family (if one exists) for the given locale, not null 3092 */ 3093 @NonNull 3094 static Optional<CardinalityRangeFamily> cardinalityRangeFamilyForLocale(@NonNull Locale locale) { 3095 requireNonNull(locale); 3096 3097 String language = LocaleUtils.normalizedLanguage(locale).orElse(null); 3098 String country = locale.getCountry(); 3099 3100 CardinalityRangeFamily cardinalityRangeFamily = null; 3101 3102 if (language != null && country != null) 3103 cardinalityRangeFamily = CARDINALITY_RANGE_FAMILIES_BY_LANGUAGE_CODE.get(format("%s-%s", language, country)); 3104 3105 if (cardinalityRangeFamily != null) 3106 return Optional.of(cardinalityRangeFamily); 3107 3108 if (language != null) 3109 cardinalityRangeFamily = CARDINALITY_RANGE_FAMILIES_BY_LANGUAGE_CODE.get(language); 3110 3111 return Optional.ofNullable(cardinalityRangeFamily); 3112 } 3113 3114 /** 3115 * Constructs a cardinality range family. 3116 * 3117 * @param cardinalitiesByCardinalityRange a mapping of cardinalities to example integer values for this cardinality range family sorted by the natural ordering of {@link Cardinality}, not null 3118 */ 3119 CardinalityRangeFamily(@NonNull SortedMap<@NonNull CardinalityRange, @NonNull Cardinality> cardinalitiesByCardinalityRange) { 3120 this.cardinalitiesByCardinalityRange = cardinalitiesByCardinalityRange; 3121 } 3122 3123 @NonNull 3124 SortedMap<@NonNull CardinalityRange, @NonNull Cardinality> getCardinalitiesByCardinalityRange() { 3125 return cardinalitiesByCardinalityRange; 3126 } 3127 } 3128}