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