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