001/* 002 * Copyright 2017-2022 Product Mog LLC, 2022-2026 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.lokalized; 018 019import com.lokalized.Maps.MapEntry; 020import org.jspecify.annotations.NonNull; 021 022import java.math.BigDecimal; 023import java.math.BigInteger; 024import java.text.Collator; 025import java.util.Arrays; 026import java.util.Collections; 027import java.util.HashMap; 028import java.util.Locale; 029import java.util.Map; 030import java.util.Optional; 031import java.util.SortedMap; 032import java.util.SortedSet; 033import java.util.TreeSet; 034import java.util.function.Function; 035import java.util.stream.Collectors; 036 037import static com.lokalized.NumberUtils.equal; 038import static com.lokalized.NumberUtils.inRange; 039import static com.lokalized.NumberUtils.inSet; 040import static com.lokalized.NumberUtils.notEqual; 041import static com.lokalized.NumberUtils.notInSet; 042import static java.lang.String.format; 043import static java.util.Objects.requireNonNull; 044 045/** 046 * Language plural ordinality forms. 047 * <p> 048 * For example, English has four: {@code 1st, 2nd, 3rd, 4th}, while Swedish has two: {@code 1:a, 3:e}. 049 * <p> 050 * See the <a href="http://cldr.unicode.org/index/cldr-spec/plural-rules">Unicode Common Locale Data Repository</a> 051 * and its <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">Language Plural Rules</a> for details. 052 * <p> 053 * Per the CLDR: 054 * <blockquote> 055 * These categories are only mnemonics -- the names don't necessarily imply the exact contents of the category. 056 * For example, for both English and French the number 1 has the category one (singular). 057 * <p> 058 * In English, every other number has a plural form, and is given the category other. 059 * French is similar, except that the number 0 also has the category one and not other or zero, because the form of 060 * units qualified by 0 is also singular. 061 * <p> 062 * This is worth emphasizing: A common mistake is to think that "one" is only for only the number 1. 063 * Instead, "one" is a category for any number that behaves like 1. So in some languages, for example, 064 * one → numbers that end in "1" (like 1, 21, 151) but that don't end in 11 (like "11, 111, 10311). 065 * </blockquote> 066 * 067 * @author <a href="https://revetkn.com">Mark Allen</a> 068 */ 069public enum Ordinality implements LanguageForm { 070 /** 071 * Normally the form used with 0, if it is limited to numbers whose integer values end with 0. 072 * <p> 073 * For example: the Welsh {@code 0fed ci} means "{@code 0th dog}" in English. 074 */ 075 ZERO, 076 /** 077 * The form used with 1. 078 * <p> 079 * For example: the Welsh {@code ci 1af} means {@code 1st dog} in English. 080 */ 081 ONE, 082 /** 083 * Normally the form used with 2, if it is limited to numbers whose integer values end with 2. 084 * <p> 085 * For example: the Welsh {@code 2il gi} means {@code 2nd dog} in English. 086 */ 087 TWO, 088 /** 089 * The form that falls between {@code TWO} and {@code MANY}. 090 * <p> 091 * For example: the Welsh {@code 3ydd ci} means {@code 3rd dog} in English. 092 */ 093 FEW, 094 /** 095 * The form that falls between {@code FEW} and {@code OTHER}. 096 * <p> 097 * For example: the Welsh {@code 5ed ci} means {@code 5th dog} in English. 098 */ 099 MANY, 100 /** 101 * General "catchall" form which comprises any cases not handled by the other forms. 102 * <p> 103 * For example: the Welsh {@code ci rhif 10} means {@code 10th dog} in English. 104 */ 105 OTHER; 106 107 @NonNull 108 private static final BigInteger BIG_INTEGER_0; 109 @NonNull 110 private static final BigInteger BIG_INTEGER_1; 111 @NonNull 112 private static final BigInteger BIG_INTEGER_2; 113 @NonNull 114 private static final BigInteger BIG_INTEGER_3; 115 @NonNull 116 private static final BigInteger BIG_INTEGER_4; 117 @NonNull 118 private static final BigInteger BIG_INTEGER_5; 119 @NonNull 120 private static final BigInteger BIG_INTEGER_6; 121 @NonNull 122 private static final BigInteger BIG_INTEGER_7; 123 @NonNull 124 private static final BigInteger BIG_INTEGER_8; 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_17; 133 @NonNull 134 private static final BigInteger BIG_INTEGER_18; 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_50; 141 @NonNull 142 private static final BigInteger BIG_INTEGER_60; 143 @NonNull 144 private static final BigInteger BIG_INTEGER_70; 145 @NonNull 146 private static final BigInteger BIG_INTEGER_80; 147 @NonNull 148 private static final BigInteger BIG_INTEGER_90; 149 @NonNull 150 private static final BigInteger BIG_INTEGER_100; 151 @NonNull 152 private static final BigInteger BIG_INTEGER_200; 153 @NonNull 154 private static final BigInteger BIG_INTEGER_300; 155 @NonNull 156 private static final BigInteger BIG_INTEGER_400; 157 @NonNull 158 private static final BigInteger BIG_INTEGER_500; 159 @NonNull 160 private static final BigInteger BIG_INTEGER_600; 161 @NonNull 162 private static final BigInteger BIG_INTEGER_700; 163 @NonNull 164 private static final BigInteger BIG_INTEGER_800; 165 @NonNull 166 private static final BigInteger BIG_INTEGER_900; 167 @NonNull 168 private static final BigInteger BIG_INTEGER_1_000; 169 170 @NonNull 171 private static final BigDecimal BIG_DECIMAL_0; 172 @NonNull 173 private static final BigDecimal BIG_DECIMAL_1; 174 @NonNull 175 private static final BigDecimal BIG_DECIMAL_2; 176 @NonNull 177 private static final BigDecimal BIG_DECIMAL_3; 178 @NonNull 179 private static final BigDecimal BIG_DECIMAL_4; 180 @NonNull 181 private static final BigDecimal BIG_DECIMAL_5; 182 @NonNull 183 private static final BigDecimal BIG_DECIMAL_6; 184 @NonNull 185 private static final BigDecimal BIG_DECIMAL_7; 186 @NonNull 187 private static final BigDecimal BIG_DECIMAL_8; 188 @NonNull 189 private static final BigDecimal BIG_DECIMAL_9; 190 @NonNull 191 private static final BigDecimal BIG_DECIMAL_10; 192 @NonNull 193 private static final BigDecimal BIG_DECIMAL_11; 194 @NonNull 195 private static final BigDecimal BIG_DECIMAL_12; 196 @NonNull 197 private static final BigDecimal BIG_DECIMAL_13; 198 @NonNull 199 private static final BigDecimal BIG_DECIMAL_14; 200 @NonNull 201 private static final BigDecimal BIG_DECIMAL_80; 202 @NonNull 203 private static final BigDecimal BIG_DECIMAL_100; 204 @NonNull 205 private static final BigDecimal BIG_DECIMAL_800; 206 207 @NonNull 208 static final Map<@NonNull String, @NonNull Ordinality> ORDINALITIES_BY_NAME; 209 210 static { 211 BIG_INTEGER_0 = BigInteger.ZERO; 212 BIG_INTEGER_1 = BigInteger.ONE; 213 BIG_INTEGER_2 = BigInteger.valueOf(2); 214 BIG_INTEGER_3 = BigInteger.valueOf(3); 215 BIG_INTEGER_4 = BigInteger.valueOf(4); 216 BIG_INTEGER_5 = BigInteger.valueOf(5); 217 BIG_INTEGER_6 = BigInteger.valueOf(6); 218 BIG_INTEGER_7 = BigInteger.valueOf(7); 219 BIG_INTEGER_8 = BigInteger.valueOf(8); 220 BIG_INTEGER_10 = BigInteger.TEN; 221 BIG_INTEGER_11 = BigInteger.valueOf(11); 222 BIG_INTEGER_12 = BigInteger.valueOf(12); 223 BIG_INTEGER_17 = BigInteger.valueOf(17); 224 BIG_INTEGER_18 = BigInteger.valueOf(18); 225 BIG_INTEGER_20 = BigInteger.valueOf(20); 226 BIG_INTEGER_40 = BigInteger.valueOf(40); 227 BIG_INTEGER_50 = BigInteger.valueOf(50); 228 BIG_INTEGER_60 = BigInteger.valueOf(60); 229 BIG_INTEGER_70 = BigInteger.valueOf(70); 230 BIG_INTEGER_80 = BigInteger.valueOf(80); 231 BIG_INTEGER_90 = BigInteger.valueOf(90); 232 BIG_INTEGER_100 = BigInteger.valueOf(100); 233 BIG_INTEGER_200 = BigInteger.valueOf(200); 234 BIG_INTEGER_300 = BigInteger.valueOf(300); 235 BIG_INTEGER_400 = BigInteger.valueOf(400); 236 BIG_INTEGER_500 = BigInteger.valueOf(500); 237 BIG_INTEGER_600 = BigInteger.valueOf(600); 238 BIG_INTEGER_700 = BigInteger.valueOf(700); 239 BIG_INTEGER_800 = BigInteger.valueOf(800); 240 BIG_INTEGER_900 = BigInteger.valueOf(900); 241 BIG_INTEGER_1_000 = BigInteger.valueOf(1_000); 242 243 BIG_DECIMAL_0 = BigDecimal.ZERO; 244 BIG_DECIMAL_1 = BigDecimal.ONE; 245 BIG_DECIMAL_2 = BigDecimal.valueOf(2); 246 BIG_DECIMAL_3 = BigDecimal.valueOf(3); 247 BIG_DECIMAL_4 = BigDecimal.valueOf(4); 248 BIG_DECIMAL_5 = BigDecimal.valueOf(5); 249 BIG_DECIMAL_6 = BigDecimal.valueOf(6); 250 BIG_DECIMAL_7 = BigDecimal.valueOf(7); 251 BIG_DECIMAL_8 = BigDecimal.valueOf(8); 252 BIG_DECIMAL_9 = BigDecimal.valueOf(9); 253 BIG_DECIMAL_10 = BigDecimal.TEN; 254 BIG_DECIMAL_11 = BigDecimal.valueOf(11); 255 BIG_DECIMAL_12 = BigDecimal.valueOf(12); 256 BIG_DECIMAL_13 = BigDecimal.valueOf(13); 257 BIG_DECIMAL_14 = BigDecimal.valueOf(14); 258 BIG_DECIMAL_80 = BigDecimal.valueOf(80); 259 BIG_DECIMAL_100 = BigDecimal.valueOf(100); 260 BIG_DECIMAL_800 = BigDecimal.valueOf(800); 261 262 ORDINALITIES_BY_NAME = Collections.unmodifiableMap(Arrays.stream( 263 Ordinality.values()).collect(Collectors.toMap(ordinality -> ordinality.name(), ordinality -> ordinality))); 264 } 265 266 /** 267 * Gets an appropriate plural ordinality for the given number and locale. 268 * <p> 269 * Negative numbers are evaluated using their absolute value. 270 * <p> 271 * See <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html</a> 272 * for a cheat sheet. 273 * 274 * @param number the number that drives pluralization, not null 275 * @param locale the locale that drives pluralization, not null 276 * @return an appropriate plural ordinality, not null 277 * @throws UnsupportedLocaleException if the locale is not supported 278 */ 279 @NonNull 280 public static Ordinality forNumber(@NonNull Number number, @NonNull Locale locale) { 281 requireNonNull(number); 282 requireNonNull(locale); 283 284 BigDecimal numberAsBigDecimal = NumberUtils.toBigDecimal(number).abs(); 285 286 Optional<OrdinalityFamily> ordinalityFamily = OrdinalityFamily.ordinalityFamilyForLocale(locale); 287 288 // TODO: throwing an exception might not be the best solution here...need to think about it 289 if (!ordinalityFamily.isPresent()) 290 throw new UnsupportedLocaleException(locale); 291 292 return ordinalityFamily.get().getOrdinalityFunction().apply(numberAsBigDecimal); 293 } 294 295 /** 296 * Gets the set of ordinalities supported for the given locale. 297 * <p> 298 * The empty set will be returned if the locale is not supported. 299 * <p> 300 * The set's values are sorted by the natural ordering of the {@link Ordinality} enumeration. 301 * 302 * @param locale the locale to use for lookup, not null 303 * @return the ordinalities supported by the given locale, not null 304 */ 305 @NonNull 306 public static SortedSet<@NonNull Ordinality> supportedOrdinalitiesForLocale(@NonNull Locale locale) { 307 requireNonNull(locale); 308 309 Optional<OrdinalityFamily> ordinalityFamily = OrdinalityFamily.ordinalityFamilyForLocale(locale); 310 return ordinalityFamily.isPresent() ? ordinalityFamily.get().getSupportedOrdinalities() : Collections.emptySortedSet(); 311 } 312 313 /** 314 * Gets a mapping of ordinalities to example integer values for the given locale. 315 * <p> 316 * The empty map will be returned if the locale is not supported or if no example values are available. 317 * <p> 318 * The map's keys are sorted by the natural ordering of the {@link Ordinality} enumeration. 319 * 320 * @param locale the locale to use for lookup, not null 321 * @return a mapping of ordinalities to example integer values, not null 322 */ 323 @NonNull 324 public static SortedMap<@NonNull Ordinality, @NonNull Range<@NonNull Integer>> exampleIntegerValuesForLocale(@NonNull Locale locale) { 325 requireNonNull(locale); 326 327 Optional<OrdinalityFamily> ordinalityFamily = OrdinalityFamily.ordinalityFamilyForLocale(locale); 328 return ordinalityFamily.isPresent() ? ordinalityFamily.get().getExampleIntegerValuesByOrdinality() : Collections.emptySortedMap(); 329 } 330 331 /** 332 * Gets the ISO 639 language codes for which ordinality operations are supported. 333 * <p> 334 * The set's values are ISO 639 codes and therefore sorted using English collation. 335 * 336 * @return the ISO 639 language codes for which ordinality operations are supported, not null 337 */ 338 @NonNull 339 public static SortedSet<@NonNull String> getSupportedLanguageCodes() { 340 return OrdinalityFamily.getSupportedLanguageCodes(); 341 } 342 343 /** 344 * Gets the mapping of ordinality names to values. 345 * 346 * @return the mapping of ordinality names to values, not null 347 */ 348 @NonNull 349 static Map<@NonNull String, @NonNull Ordinality> getOrdinalitiesByName() { 350 return ORDINALITIES_BY_NAME; 351 } 352 353 /** 354 * Plural ordinality forms grouped by language family. 355 * <p> 356 * Each family has a distinct ordinality calculation rule. 357 * <p> 358 * See <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html</a> 359 * for a cheat sheet. 360 */ 361 enum OrdinalityFamily { 362 /** 363 * Languages Include: 364 * <p> 365 * <ul> 366 * <li>Afrikaans (af)</li> 367 * <li>Akan (ak) (no CLDR data available)</li> 368 * <li>Amharic (am)</li> 369 * <li>Arabic (ar)</li> 370 * <li>Najdi Arabic (ars) (no CLDR data available)</li> 371 * <li>Asu (asa) (no CLDR data available)</li> 372 * <li>Asturian (ast) (no CLDR data available)</li> 373 * <li>Bemba (bem) (no CLDR data available)</li> 374 * <li>Bena (bez) (no CLDR data available)</li> 375 * <li>Bulgarian (bg)</li> 376 * <li>Bihari (bh) (no CLDR data available)</li> 377 * <li>Bambara (bm) (no CLDR data available)</li> 378 * <li>Tibetan (bo) (no CLDR data available)</li> 379 * <li>Breton (br) (no CLDR data available)</li> 380 * <li>Bodo (brx) (no CLDR data available)</li> 381 * <li>Bosnian (bs)</li> 382 * <li>Chechen (ce)</li> 383 * <li>Chiga (cgg) (no CLDR data available)</li> 384 * <li>Cherokee (chr) (no CLDR data available)</li> 385 * <li>Central Kurdish (ckb) (no CLDR data available)</li> 386 * <li>Czech (cs)</li> 387 * <li>Danish (da)</li> 388 * <li>German (de)</li> 389 * <li>Lower Sorbian (dsb)</li> 390 * <li>Divehi (dv) (no CLDR data available)</li> 391 * <li>Dzongkha (dz) (no CLDR data available)</li> 392 * <li>Ewe (ee) (no CLDR data available)</li> 393 * <li>Greek (el)</li> 394 * <li>Esperanto (eo) (no CLDR data available)</li> 395 * <li>Spanish (es)</li> 396 * <li>Estonian (et)</li> 397 * <li>Basque (eu)</li> 398 * <li>Persian (fa)</li> 399 * <li>Fulah (ff) (no CLDR data available)</li> 400 * <li>Finnish (fi)</li> 401 * <li>Faroese (fo) (no CLDR data available)</li> 402 * <li>Friulian (fur) (no CLDR data available)</li> 403 * <li>Western Frisian (fy)</li> 404 * <li>Scottish Gaelic (gd) (no CLDR data available)</li> 405 * <li>Galician (gl)</li> 406 * <li>Swiss German (gsw)</li> 407 * <li>Gun (guw) (no CLDR data available)</li> 408 * <li>Manx (gv) (no CLDR data available)</li> 409 * <li>Hausa (ha) (no CLDR data available)</li> 410 * <li>Hawaiian (haw) (no CLDR data available)</li> 411 * <li>Hebrew (he)</li> 412 * <li>Croatian (hr)</li> 413 * <li>Upper Sorbian (hsb)</li> 414 * <li>Indonesian (id)</li> 415 * <li>Igbo (ig) (no CLDR data available)</li> 416 * <li>Sichuan Yi (ii) (no CLDR data available)</li> 417 * <li>Icelandic (is)</li> 418 * <li>Inuktitut (iu) (no CLDR data available)</li> 419 * <li>Japanese (ja)</li> 420 * <li>Lojban (jbo) (no CLDR data available)</li> 421 * <li>Ngomba (jgo) (no CLDR data available)</li> 422 * <li>Machame (jmc) (no CLDR data available)</li> 423 * <li>Javanese (jv) (no CLDR data available)</li> 424 * <li>Javanese (jw) (no CLDR data available)</li> 425 * <li>Kabyle (kab) (no CLDR data available)</li> 426 * <li>Jju (kaj) (no CLDR data available)</li> 427 * <li>Tyap (kcg) (no CLDR data available)</li> 428 * <li>Makonde (kde) (no CLDR data available)</li> 429 * <li>Kabuverdianu (kea) (no CLDR data available)</li> 430 * <li>Kako (kkj) (no CLDR data available)</li> 431 * <li>Greenlandic (kl) (no CLDR data available)</li> 432 * <li>Khmer (km)</li> 433 * <li>Kannada (kn)</li> 434 * <li>Korean (ko)</li> 435 * <li>Kashmiri (ks) (no CLDR data available)</li> 436 * <li>Shambala (ksb) (no CLDR data available)</li> 437 * <li>Colognian (ksh) (no CLDR data available)</li> 438 * <li>Kurdish (ku) (no CLDR data available)</li> 439 * <li>Cornish (kw) (no CLDR data available)</li> 440 * <li>Kirghiz (ky)</li> 441 * <li>Langi (lag) (no CLDR data available)</li> 442 * <li>Luxembourgish (lb) (no CLDR data available)</li> 443 * <li>Ganda (lg) (no CLDR data available)</li> 444 * <li>Lakota (lkt) (no CLDR data available)</li> 445 * <li>Lingala (ln) (no CLDR data available)</li> 446 * <li>Lithuanian (lt)</li> 447 * <li>Latvian (lv)</li> 448 * <li>Masai (mas) (no CLDR data available)</li> 449 * <li>Malagasy (mg) (no CLDR data available)</li> 450 * <li>Metaʼ (mgo) (no CLDR data available)</li> 451 * <li>Malayalam (ml)</li> 452 * <li>Mongolian (mn)</li> 453 * <li>Maltese (mt) (no CLDR data available)</li> 454 * <li>Burmese (my)</li> 455 * <li>Nahuatl (nah) (no CLDR data available)</li> 456 * <li>Nama (naq) (no CLDR data available)</li> 457 * <li>Norwegian Bokmål (nb)</li> 458 * <li>North Ndebele (nd) (no CLDR data available)</li> 459 * <li>Dutch (nl)</li> 460 * <li>Norwegian Nynorsk (nn) (no CLDR data available)</li> 461 * <li>Ngiemboon (nnh) (no CLDR data available)</li> 462 * <li>Norwegian (no) (no CLDR data available)</li> 463 * <li>N’Ko (nqo) (no CLDR data available)</li> 464 * <li>South Ndebele (nr) (no CLDR data available)</li> 465 * <li>Northern Sotho (nso) (no CLDR data available)</li> 466 * <li>Nyanja (ny) (no CLDR data available)</li> 467 * <li>Nyankole (nyn) (no CLDR data available)</li> 468 * <li>Oromo (om) (no CLDR data available)</li> 469 * <li>Odia (or) (no CLDR data available)</li> 470 * <li>Ossetian (os) (no CLDR data available)</li> 471 * <li>Punjabi (pa)</li> 472 * <li>Papiamento (pap) (no CLDR data available)</li> 473 * <li>Polish (pl)</li> 474 * <li>Prussian (prg)</li> 475 * <li>Pushto (ps) (no CLDR data available)</li> 476 * <li>Portuguese (pt)</li> 477 * <li>Romansh (rm) (no CLDR data available)</li> 478 * <li>Rombo (rof) (no CLDR data available)</li> 479 * <li>Root (root)</li> 480 * <li>Russian (ru)</li> 481 * <li>Rwa (rwk) (no CLDR data available)</li> 482 * <li>Sakha (sah) (no CLDR data available)</li> 483 * <li>Samburu (saq) (no CLDR data available)</li> 484 * <li>Southern Kurdish (sdh) (no CLDR data available)</li> 485 * <li>Northern Sami (se) (no CLDR data available)</li> 486 * <li>Sena (seh) (no CLDR data available)</li> 487 * <li>Koyraboro Senni (ses) (no CLDR data available)</li> 488 * <li>Sango (sg) (no CLDR data available)</li> 489 * <li>Serbo-Croatian (sh)</li> 490 * <li>Tachelhit (shi) (no CLDR data available)</li> 491 * <li>Sinhalese (si)</li> 492 * <li>Slovak (sk)</li> 493 * <li>Slovenian (sl)</li> 494 * <li>Southern Sami (sma) (no CLDR data available)</li> 495 * <li>Sami (smi) (no CLDR data available)</li> 496 * <li>Lule Sami (smj) (no CLDR data available)</li> 497 * <li>Inari Sami (smn) (no CLDR data available)</li> 498 * <li>Skolt Sami (sms) (no CLDR data available)</li> 499 * <li>Shona (sn) (no CLDR data available)</li> 500 * <li>Somali (so) (no CLDR data available)</li> 501 * <li>Serbian (sr)</li> 502 * <li>Swati (ss) (no CLDR data available)</li> 503 * <li>Saho (ssy) (no CLDR data available)</li> 504 * <li>Southern Sotho (st) (no CLDR data available)</li> 505 * <li>Swahili (sw)</li> 506 * <li>Syriac (syr) (no CLDR data available)</li> 507 * <li>Tamil (ta)</li> 508 * <li>Telugu (te)</li> 509 * <li>Teso (teo) (no CLDR data available)</li> 510 * <li>Thai (th)</li> 511 * <li>Tigrinya (ti) (no CLDR data available)</li> 512 * <li>Tigre (tig) (no CLDR data available)</li> 513 * <li>Turkmen (tk) (no CLDR data available)</li> 514 * <li>Tswana (tn) (no CLDR data available)</li> 515 * <li>Tongan (to) (no CLDR data available)</li> 516 * <li>Turkish (tr)</li> 517 * <li>Tsonga (ts) (no CLDR data available)</li> 518 * <li>Central Atlas Tamazight (tzm) (no CLDR data available)</li> 519 * <li>Uighur (ug) (no CLDR data available)</li> 520 * <li>Urdu (ur)</li> 521 * <li>Uzbek (uz)</li> 522 * <li>Venda (ve) (no CLDR data available)</li> 523 * <li>Volapük (vo) (no CLDR data available)</li> 524 * <li>Vunjo (vun) (no CLDR data available)</li> 525 * <li>Walloon (wa) (no CLDR data available)</li> 526 * <li>Walser (wae) (no CLDR data available)</li> 527 * <li>Wolof (wo) (no CLDR data available)</li> 528 * <li>Xhosa (xh) (no CLDR data available)</li> 529 * <li>Soga (xog) (no CLDR data available)</li> 530 * <li>Yiddish (yi) (no CLDR data available)</li> 531 * <li>Yoruba (yo) (no CLDR data available)</li> 532 * <li>Cantonese (yue)</li> 533 * <li>Mandarin Chinese (zh)</li> 534 * <li>Zulu (zu)</li> 535 * </ul> 536 */ 537 FAMILY_1( 538 (n) -> { 539 // No ordinality rules for this family 540 return OTHER; 541 }, 542 Sets.sortedSet( 543 OTHER 544 ), 545 Maps.sortedMap( 546 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 100, 1000, 10000, 100000, 1000000)) 547 ) 548 ), 549 550 /** 551 * Languages Include: 552 * <p> 553 * <ul> 554 * <li>Filipino (fil)</li> 555 * <li>French (fr)</li> 556 * <li>Irish (ga)</li> 557 * <li>Armenian (hy)</li> 558 * <li>Lao (lo)</li> 559 * <li>Moldovan (mo)</li> 560 * <li>Malay (ms)</li> 561 * <li>Romanian (ro)</li> 562 * <li>Tagalog (tl)</li> 563 * <li>Vietnamese (vi)</li> 564 * </ul> 565 */ 566 FAMILY_2( 567 (n) -> { 568 // n = 1 569 if (equal(n, BIG_DECIMAL_1)) 570 return ONE; 571 572 return OTHER; 573 }, 574 Sets.sortedSet( 575 ONE, 576 OTHER 577 ), 578 Maps.sortedMap( 579 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1)), 580 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 1000, 10000, 100000, 1000000)) 581 ) 582 ), 583 584 /** 585 * Languages Include: 586 * <p> 587 * <ul> 588 * <li>Assamese (as)</li> 589 * <li>Bangla (bn)</li> 590 * </ul> 591 */ 592 FAMILY_3( 593 (n) -> { 594 // n = 1,5,7,8,9,10 595 if (inSet(n, BIG_DECIMAL_1, BIG_DECIMAL_5, BIG_DECIMAL_7, BIG_DECIMAL_8, BIG_DECIMAL_9, BIG_DECIMAL_10)) 596 return ONE; 597 // n = 2,3 598 if (inSet(n, BIG_DECIMAL_2, BIG_DECIMAL_3)) 599 return TWO; 600 // n = 4 601 if (equal(n, BIG_DECIMAL_4)) 602 return FEW; 603 // n = 6 604 if (equal(n, BIG_DECIMAL_6)) 605 return MANY; 606 607 return OTHER; 608 }, 609 Sets.sortedSet( 610 ONE, 611 TWO, 612 FEW, 613 MANY, 614 OTHER 615 ), 616 Maps.sortedMap( 617 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1, 5, 7, 8, 9, 10)), 618 MapEntry.of(Ordinality.TWO, Range.ofFiniteValues(2, 3)), 619 MapEntry.of(Ordinality.FEW, Range.ofFiniteValues(4)), 620 MapEntry.of(Ordinality.MANY, Range.ofFiniteValues(6)), 621 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 100, 1000, 10000, 100000, 1000000)) 622 ) 623 ), 624 625 /** 626 * Languages Include: 627 * <p> 628 * <ul> 629 * <li>Gujarati (gu)</li> 630 * <li>Hindi (hi)</li> 631 * </ul> 632 */ 633 FAMILY_4( 634 (n) -> { 635 // n = 1 636 if (equal(n, BIG_DECIMAL_1)) 637 return ONE; 638 // n = 2,3 639 if (inSet(n, BIG_DECIMAL_2, BIG_DECIMAL_3)) 640 return TWO; 641 // n = 4 642 if (equal(n, BIG_DECIMAL_4)) 643 return FEW; 644 // n = 6 645 if (equal(n, BIG_DECIMAL_6)) 646 return MANY; 647 648 return OTHER; 649 }, 650 Sets.sortedSet( 651 ONE, 652 TWO, 653 FEW, 654 MANY, 655 OTHER 656 ), 657 Maps.sortedMap( 658 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1)), 659 MapEntry.of(Ordinality.TWO, Range.ofFiniteValues(2, 3)), 660 MapEntry.of(Ordinality.FEW, Range.ofFiniteValues(4)), 661 MapEntry.of(Ordinality.MANY, Range.ofFiniteValues(6)), 662 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 100, 1000, 10000, 100000, 1000000)) 663 ) 664 ), 665 666 /** 667 * Languages Include: 668 * <p> 669 * <ul> 670 * <li>Azeri (az)</li> 671 * </ul> 672 */ 673 FAMILY_5( 674 (n) -> { 675 BigInteger i = NumberUtils.integerComponent(n); 676 677 // i % 10 = 1,2,5,7,8 or i % 100 = 20,50,70,80 678 if (inSet(i.mod(BIG_INTEGER_10), BIG_INTEGER_1, BIG_INTEGER_2, BIG_INTEGER_5, BIG_INTEGER_7, BIG_INTEGER_8) 679 || inSet(i.mod(BIG_INTEGER_100), BIG_INTEGER_20, BIG_INTEGER_50, BIG_INTEGER_70, BIG_INTEGER_80)) 680 return ONE; 681 // i % 10 = 3,4 or i % 1000 = 100,200,300,400,500,600,700,800,900 682 if (inSet(i.mod(BIG_INTEGER_10), BIG_INTEGER_3, BIG_INTEGER_4) 683 || inSet(i.mod(BIG_INTEGER_1_000), BIG_INTEGER_100, BIG_INTEGER_200, BIG_INTEGER_300, BIG_INTEGER_400, BIG_INTEGER_500, BIG_INTEGER_600, BIG_INTEGER_700, BIG_INTEGER_800, BIG_INTEGER_900)) 684 return FEW; 685 // i = 0 or i % 10 = 6 or i % 100 = 40,60,90 686 if (equal(i, BIG_INTEGER_0) 687 || equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_6) 688 || inSet(i.mod(BIG_INTEGER_100), BIG_INTEGER_40, BIG_INTEGER_60, BIG_INTEGER_90)) 689 return MANY; 690 691 return OTHER; 692 }, 693 Sets.sortedSet( 694 ONE, 695 FEW, 696 MANY, 697 OTHER 698 ), 699 Maps.sortedMap( 700 MapEntry.of(Ordinality.ONE, Range.ofInfiniteValues(1, 2, 5, 7, 8, 11, 12, 15, 17, 18, 20, 21, 22, 25, 101, 1001)), 701 MapEntry.of(Ordinality.FEW, Range.ofInfiniteValues(3, 4, 13, 14, 23, 24, 33, 34, 43, 44, 53, 54, 63, 64, 73, 74, 100, 1003)), 702 MapEntry.of(Ordinality.MANY, Range.ofInfiniteValues(0, 6, 16, 26, 36, 40, 46, 56, 106, 1006)), 703 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(9, 10, 19, 29, 30, 39, 49, 59, 69, 79, 109, 1000, 10000, 100000, 1000000)) 704 ) 705 ), 706 707 /** 708 * Languages Include: 709 * <p> 710 * <ul> 711 * <li>Belarusian (be)</li> 712 * </ul> 713 */ 714 FAMILY_6( 715 (n) -> { 716 // n % 10 = 2,3 and n % 100 != 12,13 717 if (inSet(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_2, BIG_DECIMAL_3) 718 && notInSet(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_12, BIG_DECIMAL_13)) 719 return FEW; 720 721 return OTHER; 722 }, 723 Sets.sortedSet( 724 FEW, 725 OTHER 726 ), 727 Maps.sortedMap( 728 MapEntry.of(Ordinality.FEW, Range.ofInfiniteValues(2, 3, 22, 23, 32, 33, 42, 43, 52, 53, 62, 63, 72, 73, 82, 83, 102, 1002)), 729 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 730 ) 731 ), 732 733 /** 734 * Languages Include: 735 * <p> 736 * <ul> 737 * <li>Catalan (ca)</li> 738 * </ul> 739 */ 740 FAMILY_7( 741 (n) -> { 742 // n = 1,3 743 if (inSet(n, BIG_DECIMAL_1, BIG_DECIMAL_3)) 744 return ONE; 745 // n = 2 746 if (equal(n, BIG_DECIMAL_2)) 747 return TWO; 748 // n = 4 749 if (equal(n, BIG_DECIMAL_4)) 750 return FEW; 751 752 return OTHER; 753 }, 754 Sets.sortedSet( 755 ONE, 756 TWO, 757 FEW, 758 OTHER 759 ), 760 Maps.sortedMap( 761 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1, 3)), 762 MapEntry.of(Ordinality.TWO, Range.ofFiniteValues(2)), 763 MapEntry.of(Ordinality.FEW, Range.ofFiniteValues(4)), 764 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 765 ) 766 ), 767 768 /** 769 * Languages Include: 770 * <p> 771 * <ul> 772 * <li>Welsh (cy)</li> 773 * </ul> 774 */ 775 FAMILY_8( 776 (n) -> { 777 // n = 0,7,8,9 778 if (inSet(n, BIG_DECIMAL_0, BIG_DECIMAL_7, BIG_DECIMAL_8, BIG_DECIMAL_9)) 779 return ZERO; 780 // n = 1 781 if (equal(n, BIG_DECIMAL_1)) 782 return ONE; 783 // n = 2 784 if (equal(n, BIG_DECIMAL_2)) 785 return TWO; 786 // n = 3,4 787 if (inSet(n, BIG_DECIMAL_3, BIG_DECIMAL_4)) 788 return FEW; 789 // n = 5,6 790 if (inSet(n, BIG_DECIMAL_5, BIG_DECIMAL_6)) 791 return MANY; 792 793 return OTHER; 794 }, 795 Sets.sortedSet( 796 ZERO, 797 ONE, 798 TWO, 799 FEW, 800 MANY, 801 OTHER 802 ), 803 Maps.sortedMap( 804 MapEntry.of(Ordinality.ZERO, Range.ofFiniteValues(0, 7, 8, 9)), 805 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1)), 806 MapEntry.of(Ordinality.TWO, Range.ofFiniteValues(2)), 807 MapEntry.of(Ordinality.FEW, Range.ofFiniteValues(3, 4)), 808 MapEntry.of(Ordinality.MANY, Range.ofFiniteValues(5, 6)), 809 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 100, 1000, 10000, 100000, 1000000)) 810 ) 811 ), 812 813 /** 814 * Languages Include: 815 * <p> 816 * <ul> 817 * <li>English (en)</li> 818 * </ul> 819 */ 820 FAMILY_9( 821 (n) -> { 822 // n % 10 = 1 and n % 100 != 11 823 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_1) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11)) 824 return ONE; 825 // n % 10 = 2 and n % 100 != 12 826 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_2) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_12)) 827 return TWO; 828 // n % 10 = 3 and n % 100 != 13 829 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_3) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_13)) 830 return FEW; 831 832 return OTHER; 833 }, 834 Sets.sortedSet( 835 ONE, 836 TWO, 837 FEW, 838 OTHER 839 ), 840 Maps.sortedMap( 841 MapEntry.of(Ordinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 842 MapEntry.of(Ordinality.TWO, Range.ofInfiniteValues(2, 22, 32, 42, 52, 62, 72, 82, 102, 1002)), 843 MapEntry.of(Ordinality.FEW, Range.ofInfiniteValues(3, 23, 33, 43, 53, 63, 73, 83, 103, 1003)), 844 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 100, 1000, 10000, 100000, 1000000)) 845 ) 846 ), 847 848 /** 849 * Languages Include: 850 * <p> 851 * <ul> 852 * <li>Hungarian (hu)</li> 853 * </ul> 854 */ 855 FAMILY_10( 856 (n) -> { 857 // n = 1,5 858 if (inSet(n, BIG_DECIMAL_1, BIG_DECIMAL_5)) 859 return ONE; 860 861 return OTHER; 862 }, 863 Sets.sortedSet( 864 ONE, 865 OTHER 866 ), 867 Maps.sortedMap( 868 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1, 5)), 869 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 870 ) 871 ), 872 873 /** 874 * Languages Include: 875 * <p> 876 * <ul> 877 * <li>Italian (it)</li> 878 * </ul> 879 */ 880 FAMILY_11( 881 (n) -> { 882 // n = 11,8,80,800 883 if (inSet(n, BIG_DECIMAL_11, BIG_DECIMAL_8, BIG_DECIMAL_80, BIG_DECIMAL_800)) 884 return MANY; 885 886 return OTHER; 887 }, 888 Sets.sortedSet( 889 MANY, 890 OTHER 891 ), 892 Maps.sortedMap( 893 MapEntry.of(Ordinality.MANY, Range.ofFiniteValues(8, 11, 80, 800)), 894 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 895 ) 896 ), 897 898 /** 899 * Languages Include: 900 * <p> 901 * <ul> 902 * <li>Georgian (ka)</li> 903 * </ul> 904 */ 905 FAMILY_12( 906 (n) -> { 907 BigInteger i = NumberUtils.integerComponent(n); 908 909 // i = 1 910 if (equal(i, BIG_INTEGER_1)) 911 return ONE; 912 // i = 0 or i % 100 = 2..20,40,60,80 913 if (equal(i, BIG_INTEGER_0) || inRange(i.mod(BIG_INTEGER_100), BIG_INTEGER_2, BIG_INTEGER_20) || inSet(i.mod(BIG_INTEGER_100), BIG_INTEGER_40, BIG_INTEGER_60, BIG_INTEGER_80)) 914 return MANY; 915 916 return OTHER; 917 }, 918 Sets.sortedSet( 919 ONE, 920 MANY, 921 OTHER 922 ), 923 Maps.sortedMap( 924 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1)), 925 MapEntry.of(Ordinality.MANY, Range.ofInfiniteValues(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 102, 1002)), 926 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 100, 1000, 10000, 100000, 1000000)) 927 ) 928 ), 929 930 /** 931 * Languages Include: 932 * <p> 933 * <ul> 934 * <li>Kazakh (kk)</li> 935 * </ul> 936 */ 937 FAMILY_13( 938 (n) -> { 939 // n % 10 = 6 or n % 10 = 9 or n % 10 = 0 and n != 0 940 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_6) 941 || equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_9) 942 || (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_0) && notEqual(n, BIG_DECIMAL_0))) 943 return MANY; 944 945 return OTHER; 946 }, 947 Sets.sortedSet( 948 MANY, 949 OTHER 950 ), 951 Maps.sortedMap( 952 MapEntry.of(Ordinality.MANY, Range.ofInfiniteValues(6, 9, 10, 16, 19, 20, 26, 29, 30, 36, 39, 40, 100, 1000, 10000, 100000, 1000000)), 953 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 13, 14, 15, 17, 18, 21, 101, 1001)) 954 ) 955 ), 956 957 /** 958 * Languages Include: 959 * <p> 960 * <ul> 961 * <li>Macedonian (mk)</li> 962 * </ul> 963 */ 964 FAMILY_14( 965 (n) -> { 966 BigInteger i = NumberUtils.integerComponent(n); 967 968 // i % 10 = 1 and i % 100 != 11 969 if (equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_1) && notEqual(i.mod(BIG_INTEGER_100), BIG_INTEGER_11)) 970 return ONE; 971 // i % 10 = 2 and i % 100 != 12 972 if (equal(i.mod(BIG_INTEGER_10), BIG_INTEGER_2) && notEqual(i.mod(BIG_INTEGER_100), BIG_INTEGER_12)) 973 return TWO; 974 // i % 10 = 7,8 and i % 100 != 17,18 975 if (inSet(i.mod(BIG_INTEGER_10), BIG_INTEGER_7, BIG_INTEGER_8) && notInSet(i.mod(BIG_INTEGER_100), BIG_INTEGER_17, BIG_INTEGER_18)) 976 return MANY; 977 978 return OTHER; 979 }, 980 Sets.sortedSet( 981 ONE, 982 TWO, 983 MANY, 984 OTHER 985 ), 986 Maps.sortedMap( 987 MapEntry.of(Ordinality.ONE, Range.ofInfiniteValues(1, 21, 31, 41, 51, 61, 71, 81, 101, 1001)), 988 MapEntry.of(Ordinality.TWO, Range.ofInfiniteValues(2, 22, 32, 42, 52, 62, 72, 82, 102, 1002)), 989 MapEntry.of(Ordinality.MANY, Range.ofInfiniteValues(7, 8, 27, 28, 37, 38, 47, 48, 57, 58, 67, 68, 77, 78, 87, 88, 107, 1007)), 990 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 991 ) 992 ), 993 994 /** 995 * Languages Include: 996 * <p> 997 * <ul> 998 * <li>Marathi (mr)</li> 999 * </ul> 1000 */ 1001 FAMILY_15( 1002 (n) -> { 1003 // n = 1 1004 if (equal(n, BIG_DECIMAL_1)) 1005 return ONE; 1006 // n = 2,3 1007 if (inSet(n, BIG_DECIMAL_2, BIG_DECIMAL_3)) 1008 return TWO; 1009 // n = 4 1010 if (equal(n, BIG_DECIMAL_4)) 1011 return FEW; 1012 1013 return OTHER; 1014 }, 1015 Sets.sortedSet( 1016 ONE, 1017 TWO, 1018 FEW, 1019 OTHER 1020 ), 1021 Maps.sortedMap( 1022 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1)), 1023 MapEntry.of(Ordinality.TWO, Range.ofFiniteValues(2, 3)), 1024 MapEntry.of(Ordinality.FEW, Range.ofFiniteValues(4)), 1025 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1026 ) 1027 ), 1028 1029 /** 1030 * Languages Include: 1031 * <p> 1032 * <ul> 1033 * <li>Nepali (ne)</li> 1034 * </ul> 1035 */ 1036 FAMILY_16( 1037 (n) -> { 1038 // n = 1..4 1039 if (inRange(n, BIG_DECIMAL_1, BIG_DECIMAL_4)) 1040 return ONE; 1041 1042 return OTHER; 1043 }, 1044 Sets.sortedSet( 1045 ONE, 1046 OTHER 1047 ), 1048 Maps.sortedMap( 1049 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1, 2, 3, 4)), 1050 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 100, 1000, 10000, 100000, 1000000)) 1051 ) 1052 ), 1053 1054 /** 1055 * Languages Include: 1056 * <p> 1057 * <ul> 1058 * <li>Albanian (sq)</li> 1059 * </ul> 1060 */ 1061 FAMILY_17( 1062 (n) -> { 1063 // n = 1 1064 if (equal(n, BIG_DECIMAL_1)) 1065 return ONE; 1066 // n % 10 = 4 and n % 100 != 14 1067 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_4) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_14)) 1068 return MANY; 1069 1070 return OTHER; 1071 }, 1072 Sets.sortedSet( 1073 ONE, 1074 MANY, 1075 OTHER 1076 ), 1077 Maps.sortedMap( 1078 MapEntry.of(Ordinality.ONE, Range.ofFiniteValues(1)), 1079 MapEntry.of(Ordinality.MANY, Range.ofInfiniteValues(4, 24, 34, 44, 54, 64, 74, 84, 104, 1004)), 1080 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1081 ) 1082 ), 1083 1084 /** 1085 * Languages Include: 1086 * <p> 1087 * <ul> 1088 * <li>Swedish (sv)</li> 1089 * </ul> 1090 */ 1091 FAMILY_18( 1092 (n) -> { 1093 // n % 10 = 1,2 and n % 100 != 11,12 1094 if (inSet(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_1, BIG_DECIMAL_2) && notInSet(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_11, BIG_DECIMAL_12)) 1095 return ONE; 1096 1097 return OTHER; 1098 }, 1099 Sets.sortedSet( 1100 ONE, 1101 OTHER 1102 ), 1103 Maps.sortedMap( 1104 MapEntry.of(Ordinality.ONE, Range.ofInfiniteValues(1, 2, 21, 22, 31, 32, 41, 42, 51, 52, 61, 62, 71, 72, 81, 82, 101, 1001)), 1105 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 100, 1000, 10000, 100000, 1000000)) 1106 ) 1107 ), 1108 1109 /** 1110 * Languages Include: 1111 * <p> 1112 * <ul> 1113 * <li>Ukrainian (uk)</li> 1114 * </ul> 1115 */ 1116 FAMILY_19( 1117 (n) -> { 1118 // n % 10 = 3 and n % 100 != 13 1119 if (equal(n.remainder(BIG_DECIMAL_10), BIG_DECIMAL_3) && notEqual(n.remainder(BIG_DECIMAL_100), BIG_DECIMAL_13)) 1120 return FEW; 1121 1122 return OTHER; 1123 }, 1124 Sets.sortedSet( 1125 FEW, 1126 OTHER 1127 ), 1128 Maps.sortedMap( 1129 MapEntry.of(Ordinality.FEW, Range.ofInfiniteValues(3, 23, 33, 43, 53, 63, 73, 83, 103, 1003)), 1130 MapEntry.of(Ordinality.OTHER, Range.ofInfiniteValues(0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 1000, 10000, 100000, 1000000)) 1131 ) 1132 ); 1133 1134 @NonNull 1135 private static final Map<@NonNull String, @NonNull OrdinalityFamily> ORDINALITY_FAMILIES_BY_LANGUAGE_CODE; 1136 @NonNull 1137 private static final SortedSet<@NonNull String> SUPPORTED_LANGUAGE_CODES; 1138 1139 @NonNull 1140 private final Function<BigDecimal, Ordinality> ordinalityFunction; 1141 @NonNull 1142 private final SortedSet<@NonNull Ordinality> supportedOrdinalities; 1143 @NonNull 1144 private final SortedMap<@NonNull Ordinality, @NonNull Range<@NonNull Integer>> exampleIntegerValuesByOrdinality; 1145 1146 /** 1147 * Constructs an ordinality family. 1148 * 1149 * @param ordinalityFunction the ordinality-determining function for this ordinality family, not null 1150 * @param supportedOrdinalities the ordinalities supported by this family sorted by the natural ordering of {@link Ordinality}, not null 1151 * @param exampleIntegerValuesByOrdinality a mapping of ordinalities to example integer values for this ordinality family sorted by the natural ordering of {@link Ordinality}, not null 1152 */ 1153 OrdinalityFamily(@NonNull Function<BigDecimal, Ordinality> ordinalityFunction, 1154 @NonNull SortedSet<@NonNull Ordinality> supportedOrdinalities, 1155 @NonNull SortedMap<@NonNull Ordinality, @NonNull Range<@NonNull Integer>> exampleIntegerValuesByOrdinality) { 1156 requireNonNull(ordinalityFunction); 1157 requireNonNull(supportedOrdinalities); 1158 requireNonNull(exampleIntegerValuesByOrdinality); 1159 1160 this.ordinalityFunction = ordinalityFunction; 1161 this.supportedOrdinalities = supportedOrdinalities; 1162 this.exampleIntegerValuesByOrdinality = exampleIntegerValuesByOrdinality; 1163 } 1164 1165 static { 1166 ORDINALITY_FAMILIES_BY_LANGUAGE_CODE = Collections.unmodifiableMap(new HashMap<@NonNull String, @NonNull OrdinalityFamily>() {{ 1167 put("af", OrdinalityFamily.FAMILY_1); // Afrikaans 1168 put("ak", OrdinalityFamily.FAMILY_1); // Akan (no CLDR data available) 1169 put("am", OrdinalityFamily.FAMILY_1); // Amharic 1170 put("ar", OrdinalityFamily.FAMILY_1); // Arabic 1171 put("ars", OrdinalityFamily.FAMILY_1); // Najdi Arabic (no CLDR data available) 1172 put("as", OrdinalityFamily.FAMILY_3); // Assamese 1173 put("asa", OrdinalityFamily.FAMILY_1); // Asu (no CLDR data available) 1174 put("ast", OrdinalityFamily.FAMILY_1); // Asturian (no CLDR data available) 1175 put("az", OrdinalityFamily.FAMILY_5); // Azeri 1176 put("be", OrdinalityFamily.FAMILY_6); // Belarusian 1177 put("bem", OrdinalityFamily.FAMILY_1); // Bemba (no CLDR data available) 1178 put("bez", OrdinalityFamily.FAMILY_1); // Bena (no CLDR data available) 1179 put("bg", OrdinalityFamily.FAMILY_1); // Bulgarian 1180 put("bh", OrdinalityFamily.FAMILY_1); // Bihari (no CLDR data available) 1181 put("bm", OrdinalityFamily.FAMILY_1); // Bambara (no CLDR data available) 1182 put("bn", OrdinalityFamily.FAMILY_3); // Bangla 1183 put("bo", OrdinalityFamily.FAMILY_1); // Tibetan (no CLDR data available) 1184 put("br", OrdinalityFamily.FAMILY_1); // Breton (no CLDR data available) 1185 put("brx", OrdinalityFamily.FAMILY_1); // Bodo (no CLDR data available) 1186 put("bs", OrdinalityFamily.FAMILY_1); // Bosnian 1187 put("ca", OrdinalityFamily.FAMILY_7); // Catalan 1188 put("ce", OrdinalityFamily.FAMILY_1); // Chechen 1189 put("cgg", OrdinalityFamily.FAMILY_1); // Chiga (no CLDR data available) 1190 put("chr", OrdinalityFamily.FAMILY_1); // Cherokee (no CLDR data available) 1191 put("ckb", OrdinalityFamily.FAMILY_1); // Central Kurdish (no CLDR data available) 1192 put("cs", OrdinalityFamily.FAMILY_1); // Czech 1193 put("cy", OrdinalityFamily.FAMILY_8); // Welsh 1194 put("da", OrdinalityFamily.FAMILY_1); // Danish 1195 put("de", OrdinalityFamily.FAMILY_1); // German 1196 put("dsb", OrdinalityFamily.FAMILY_1); // Lower Sorbian 1197 put("dv", OrdinalityFamily.FAMILY_1); // Divehi (no CLDR data available) 1198 put("dz", OrdinalityFamily.FAMILY_1); // Dzongkha (no CLDR data available) 1199 put("ee", OrdinalityFamily.FAMILY_1); // Ewe (no CLDR data available) 1200 put("el", OrdinalityFamily.FAMILY_1); // Greek 1201 put("en", OrdinalityFamily.FAMILY_9); // English 1202 put("eo", OrdinalityFamily.FAMILY_1); // Esperanto (no CLDR data available) 1203 put("es", OrdinalityFamily.FAMILY_1); // Spanish 1204 put("et", OrdinalityFamily.FAMILY_1); // Estonian 1205 put("eu", OrdinalityFamily.FAMILY_1); // Basque 1206 put("fa", OrdinalityFamily.FAMILY_1); // Persian 1207 put("ff", OrdinalityFamily.FAMILY_1); // Fulah (no CLDR data available) 1208 put("fi", OrdinalityFamily.FAMILY_1); // Finnish 1209 put("fil", OrdinalityFamily.FAMILY_2); // Filipino 1210 put("fo", OrdinalityFamily.FAMILY_1); // Faroese (no CLDR data available) 1211 put("fr", OrdinalityFamily.FAMILY_2); // French 1212 put("fur", OrdinalityFamily.FAMILY_1); // Friulian (no CLDR data available) 1213 put("fy", OrdinalityFamily.FAMILY_1); // Western Frisian 1214 put("ga", OrdinalityFamily.FAMILY_2); // Irish 1215 put("gd", OrdinalityFamily.FAMILY_1); // Scottish Gaelic (no CLDR data available) 1216 put("gl", OrdinalityFamily.FAMILY_1); // Galician 1217 put("gsw", OrdinalityFamily.FAMILY_1); // Swiss German 1218 put("gu", OrdinalityFamily.FAMILY_4); // Gujarati 1219 put("guw", OrdinalityFamily.FAMILY_1); // Gun (no CLDR data available) 1220 put("gv", OrdinalityFamily.FAMILY_1); // Manx (no CLDR data available) 1221 put("ha", OrdinalityFamily.FAMILY_1); // Hausa (no CLDR data available) 1222 put("haw", OrdinalityFamily.FAMILY_1); // Hawaiian (no CLDR data available) 1223 put("he", OrdinalityFamily.FAMILY_1); // Hebrew 1224 put("hi", OrdinalityFamily.FAMILY_4); // Hindi 1225 put("hr", OrdinalityFamily.FAMILY_1); // Croatian 1226 put("hsb", OrdinalityFamily.FAMILY_1); // Upper Sorbian 1227 put("hu", OrdinalityFamily.FAMILY_10); // Hungarian 1228 put("hy", OrdinalityFamily.FAMILY_2); // Armenian 1229 put("id", OrdinalityFamily.FAMILY_1); // Indonesian 1230 put("ig", OrdinalityFamily.FAMILY_1); // Igbo (no CLDR data available) 1231 put("ii", OrdinalityFamily.FAMILY_1); // Sichuan Yi (no CLDR data available) 1232 put("is", OrdinalityFamily.FAMILY_1); // Icelandic 1233 put("it", OrdinalityFamily.FAMILY_11); // Italian 1234 put("iu", OrdinalityFamily.FAMILY_1); // Inuktitut (no CLDR data available) 1235 put("ja", OrdinalityFamily.FAMILY_1); // Japanese 1236 put("jbo", OrdinalityFamily.FAMILY_1); // Lojban (no CLDR data available) 1237 put("jgo", OrdinalityFamily.FAMILY_1); // Ngomba (no CLDR data available) 1238 put("jmc", OrdinalityFamily.FAMILY_1); // Machame (no CLDR data available) 1239 put("jv", OrdinalityFamily.FAMILY_1); // Javanese (no CLDR data available) 1240 put("jw", OrdinalityFamily.FAMILY_1); // Javanese (no CLDR data available) 1241 put("ka", OrdinalityFamily.FAMILY_12); // Georgian 1242 put("kab", OrdinalityFamily.FAMILY_1); // Kabyle (no CLDR data available) 1243 put("kaj", OrdinalityFamily.FAMILY_1); // Jju (no CLDR data available) 1244 put("kcg", OrdinalityFamily.FAMILY_1); // Tyap (no CLDR data available) 1245 put("kde", OrdinalityFamily.FAMILY_1); // Makonde (no CLDR data available) 1246 put("kea", OrdinalityFamily.FAMILY_1); // Kabuverdianu (no CLDR data available) 1247 put("kk", OrdinalityFamily.FAMILY_13); // Kazakh 1248 put("kkj", OrdinalityFamily.FAMILY_1); // Kako (no CLDR data available) 1249 put("kl", OrdinalityFamily.FAMILY_1); // Greenlandic (no CLDR data available) 1250 put("km", OrdinalityFamily.FAMILY_1); // Khmer 1251 put("kn", OrdinalityFamily.FAMILY_1); // Kannada 1252 put("ko", OrdinalityFamily.FAMILY_1); // Korean 1253 put("ks", OrdinalityFamily.FAMILY_1); // Kashmiri (no CLDR data available) 1254 put("ksb", OrdinalityFamily.FAMILY_1); // Shambala (no CLDR data available) 1255 put("ksh", OrdinalityFamily.FAMILY_1); // Colognian (no CLDR data available) 1256 put("ku", OrdinalityFamily.FAMILY_1); // Kurdish (no CLDR data available) 1257 put("kw", OrdinalityFamily.FAMILY_1); // Cornish (no CLDR data available) 1258 put("ky", OrdinalityFamily.FAMILY_1); // Kirghiz 1259 put("lag", OrdinalityFamily.FAMILY_1); // Langi (no CLDR data available) 1260 put("lb", OrdinalityFamily.FAMILY_1); // Luxembourgish (no CLDR data available) 1261 put("lg", OrdinalityFamily.FAMILY_1); // Ganda (no CLDR data available) 1262 put("lkt", OrdinalityFamily.FAMILY_1); // Lakota (no CLDR data available) 1263 put("ln", OrdinalityFamily.FAMILY_1); // Lingala (no CLDR data available) 1264 put("lo", OrdinalityFamily.FAMILY_2); // Lao 1265 put("lt", OrdinalityFamily.FAMILY_1); // Lithuanian 1266 put("lv", OrdinalityFamily.FAMILY_1); // Latvian 1267 put("mas", OrdinalityFamily.FAMILY_1); // Masai (no CLDR data available) 1268 put("mg", OrdinalityFamily.FAMILY_1); // Malagasy (no CLDR data available) 1269 put("mgo", OrdinalityFamily.FAMILY_1); // Metaʼ (no CLDR data available) 1270 put("mk", OrdinalityFamily.FAMILY_14); // Macedonian 1271 put("ml", OrdinalityFamily.FAMILY_1); // Malayalam 1272 put("mn", OrdinalityFamily.FAMILY_1); // Mongolian 1273 put("mo", OrdinalityFamily.FAMILY_2); // Moldovan 1274 put("mr", OrdinalityFamily.FAMILY_15); // Marathi 1275 put("ms", OrdinalityFamily.FAMILY_2); // Malay 1276 put("mt", OrdinalityFamily.FAMILY_1); // Maltese (no CLDR data available) 1277 put("my", OrdinalityFamily.FAMILY_1); // Burmese 1278 put("nah", OrdinalityFamily.FAMILY_1); // Nahuatl (no CLDR data available) 1279 put("naq", OrdinalityFamily.FAMILY_1); // Nama (no CLDR data available) 1280 put("nb", OrdinalityFamily.FAMILY_1); // Norwegian Bokmål 1281 put("nd", OrdinalityFamily.FAMILY_1); // North Ndebele (no CLDR data available) 1282 put("ne", OrdinalityFamily.FAMILY_16); // Nepali 1283 put("nl", OrdinalityFamily.FAMILY_1); // Dutch 1284 put("nn", OrdinalityFamily.FAMILY_1); // Norwegian Nynorsk (no CLDR data available) 1285 put("nnh", OrdinalityFamily.FAMILY_1); // Ngiemboon (no CLDR data available) 1286 put("no", OrdinalityFamily.FAMILY_1); // Norwegian (no CLDR data available) 1287 put("nqo", OrdinalityFamily.FAMILY_1); // N’Ko (no CLDR data available) 1288 put("nr", OrdinalityFamily.FAMILY_1); // South Ndebele (no CLDR data available) 1289 put("nso", OrdinalityFamily.FAMILY_1); // Northern Sotho (no CLDR data available) 1290 put("ny", OrdinalityFamily.FAMILY_1); // Nyanja (no CLDR data available) 1291 put("nyn", OrdinalityFamily.FAMILY_1); // Nyankole (no CLDR data available) 1292 put("om", OrdinalityFamily.FAMILY_1); // Oromo (no CLDR data available) 1293 put("or", OrdinalityFamily.FAMILY_1); // Odia (no CLDR data available) 1294 put("os", OrdinalityFamily.FAMILY_1); // Ossetian (no CLDR data available) 1295 put("pa", OrdinalityFamily.FAMILY_1); // Punjabi 1296 put("pap", OrdinalityFamily.FAMILY_1); // Papiamento (no CLDR data available) 1297 put("pl", OrdinalityFamily.FAMILY_1); // Polish 1298 put("prg", OrdinalityFamily.FAMILY_1); // Prussian 1299 put("ps", OrdinalityFamily.FAMILY_1); // Pushto (no CLDR data available) 1300 put("pt", OrdinalityFamily.FAMILY_1); // Portuguese 1301 put("rm", OrdinalityFamily.FAMILY_1); // Romansh (no CLDR data available) 1302 put("ro", OrdinalityFamily.FAMILY_2); // Romanian 1303 put("rof", OrdinalityFamily.FAMILY_1); // Rombo (no CLDR data available) 1304 put("root", OrdinalityFamily.FAMILY_1); // Root 1305 put("ru", OrdinalityFamily.FAMILY_1); // Russian 1306 put("rwk", OrdinalityFamily.FAMILY_1); // Rwa (no CLDR data available) 1307 put("sah", OrdinalityFamily.FAMILY_1); // Sakha (no CLDR data available) 1308 put("saq", OrdinalityFamily.FAMILY_1); // Samburu (no CLDR data available) 1309 put("sdh", OrdinalityFamily.FAMILY_1); // Southern Kurdish (no CLDR data available) 1310 put("se", OrdinalityFamily.FAMILY_1); // Northern Sami (no CLDR data available) 1311 put("seh", OrdinalityFamily.FAMILY_1); // Sena (no CLDR data available) 1312 put("ses", OrdinalityFamily.FAMILY_1); // Koyraboro Senni (no CLDR data available) 1313 put("sg", OrdinalityFamily.FAMILY_1); // Sango (no CLDR data available) 1314 put("sh", OrdinalityFamily.FAMILY_1); // Serbo-Croatian 1315 put("shi", OrdinalityFamily.FAMILY_1); // Tachelhit (no CLDR data available) 1316 put("si", OrdinalityFamily.FAMILY_1); // Sinhalese 1317 put("sk", OrdinalityFamily.FAMILY_1); // Slovak 1318 put("sl", OrdinalityFamily.FAMILY_1); // Slovenian 1319 put("sma", OrdinalityFamily.FAMILY_1); // Southern Sami (no CLDR data available) 1320 put("smi", OrdinalityFamily.FAMILY_1); // Sami (no CLDR data available) 1321 put("smj", OrdinalityFamily.FAMILY_1); // Lule Sami (no CLDR data available) 1322 put("smn", OrdinalityFamily.FAMILY_1); // Inari Sami (no CLDR data available) 1323 put("sms", OrdinalityFamily.FAMILY_1); // Skolt Sami (no CLDR data available) 1324 put("sn", OrdinalityFamily.FAMILY_1); // Shona (no CLDR data available) 1325 put("so", OrdinalityFamily.FAMILY_1); // Somali (no CLDR data available) 1326 put("sq", OrdinalityFamily.FAMILY_17); // Albanian 1327 put("sr", OrdinalityFamily.FAMILY_1); // Serbian 1328 put("ss", OrdinalityFamily.FAMILY_1); // Swati (no CLDR data available) 1329 put("ssy", OrdinalityFamily.FAMILY_1); // Saho (no CLDR data available) 1330 put("st", OrdinalityFamily.FAMILY_1); // Southern Sotho (no CLDR data available) 1331 put("sv", OrdinalityFamily.FAMILY_18); // Swedish 1332 put("sw", OrdinalityFamily.FAMILY_1); // Swahili 1333 put("syr", OrdinalityFamily.FAMILY_1); // Syriac (no CLDR data available) 1334 put("ta", OrdinalityFamily.FAMILY_1); // Tamil 1335 put("te", OrdinalityFamily.FAMILY_1); // Telugu 1336 put("teo", OrdinalityFamily.FAMILY_1); // Teso (no CLDR data available) 1337 put("th", OrdinalityFamily.FAMILY_1); // Thai 1338 put("ti", OrdinalityFamily.FAMILY_1); // Tigrinya (no CLDR data available) 1339 put("tig", OrdinalityFamily.FAMILY_1); // Tigre (no CLDR data available) 1340 put("tk", OrdinalityFamily.FAMILY_1); // Turkmen (no CLDR data available) 1341 put("tl", OrdinalityFamily.FAMILY_2); // Tagalog 1342 put("tn", OrdinalityFamily.FAMILY_1); // Tswana (no CLDR data available) 1343 put("to", OrdinalityFamily.FAMILY_1); // Tongan (no CLDR data available) 1344 put("tr", OrdinalityFamily.FAMILY_1); // Turkish 1345 put("ts", OrdinalityFamily.FAMILY_1); // Tsonga (no CLDR data available) 1346 put("tzm", OrdinalityFamily.FAMILY_1); // Central Atlas Tamazight (no CLDR data available) 1347 put("ug", OrdinalityFamily.FAMILY_1); // Uighur (no CLDR data available) 1348 put("uk", OrdinalityFamily.FAMILY_19); // Ukrainian 1349 put("ur", OrdinalityFamily.FAMILY_1); // Urdu 1350 put("uz", OrdinalityFamily.FAMILY_1); // Uzbek 1351 put("ve", OrdinalityFamily.FAMILY_1); // Venda (no CLDR data available) 1352 put("vi", OrdinalityFamily.FAMILY_2); // Vietnamese 1353 put("vo", OrdinalityFamily.FAMILY_1); // Volapük (no CLDR data available) 1354 put("vun", OrdinalityFamily.FAMILY_1); // Vunjo (no CLDR data available) 1355 put("wa", OrdinalityFamily.FAMILY_1); // Walloon (no CLDR data available) 1356 put("wae", OrdinalityFamily.FAMILY_1); // Walser (no CLDR data available) 1357 put("wo", OrdinalityFamily.FAMILY_1); // Wolof (no CLDR data available) 1358 put("xh", OrdinalityFamily.FAMILY_1); // Xhosa (no CLDR data available) 1359 put("xog", OrdinalityFamily.FAMILY_1); // Soga (no CLDR data available) 1360 put("yi", OrdinalityFamily.FAMILY_1); // Yiddish (no CLDR data available) 1361 put("yo", OrdinalityFamily.FAMILY_1); // Yoruba (no CLDR data available) 1362 put("yue", OrdinalityFamily.FAMILY_1); // Cantonese 1363 put("zh", OrdinalityFamily.FAMILY_1); // Mandarin Chinese 1364 put("zu", OrdinalityFamily.FAMILY_1); // Zulu 1365 }}); 1366 1367 // Language codes are in English - force collation for sorting 1368 SortedSet<@NonNull String> supportedLanguageCodes = new TreeSet<>(Collator.getInstance(Locale.ENGLISH)); 1369 supportedLanguageCodes.addAll(ORDINALITY_FAMILIES_BY_LANGUAGE_CODE.keySet()); 1370 1371 SUPPORTED_LANGUAGE_CODES = Collections.unmodifiableSortedSet(supportedLanguageCodes); 1372 } 1373 1374 /** 1375 * Gets the ordinality-determining function for this ordinality family. 1376 * <p> 1377 * The function takes a numeric value as input and returns the appropriate ordinal form. 1378 * <p> 1379 * The function's input must not be null and its output is guaranteed non-null. 1380 * 1381 * @return the ordinality-determining function for this ordinality family, not null 1382 */ 1383 @NonNull 1384 public Function<BigDecimal, Ordinality> getOrdinalityFunction() { 1385 return ordinalityFunction; 1386 } 1387 1388 /** 1389 * Gets the ordinalities supported by this ordinality family. 1390 * <p> 1391 * There will always be at least one value - {@link Ordinality#OTHER} - in the set. 1392 * <p> 1393 * The set's values are sorted by the natural ordering of the {@link Ordinality} enumeration. 1394 * 1395 * @return the ordinalities supported by this ordinality family, not null 1396 */ 1397 @NonNull 1398 SortedSet<@NonNull Ordinality> getSupportedOrdinalities() { 1399 return supportedOrdinalities; 1400 } 1401 1402 /** 1403 * Gets a mapping of ordinalities to example integer values for this ordinality family. 1404 * <p> 1405 * The map may be empty. 1406 * <p> 1407 * The map's keys are sorted by the natural ordering of the {@link Ordinality} enumeration. 1408 * 1409 * @return a mapping of ordinalities to example integer values, not null 1410 */ 1411 @NonNull 1412 SortedMap<@NonNull Ordinality, @NonNull Range<@NonNull Integer>> getExampleIntegerValuesByOrdinality() { 1413 return exampleIntegerValuesByOrdinality; 1414 } 1415 1416 /** 1417 * Gets the ISO 639 language codes for which ordinality operations are supported. 1418 * <p> 1419 * The set's values are ISO 639 codes and therefore sorted using English collation. 1420 * 1421 * @return the ISO 639 language codes for which ordinality operations are supported, not null 1422 */ 1423 @NonNull 1424 static SortedSet<@NonNull String> getSupportedLanguageCodes() { 1425 return SUPPORTED_LANGUAGE_CODES; 1426 } 1427 1428 /** 1429 * Gets an appropriate plural ordinality family for the given locale. 1430 * 1431 * @param locale the locale to check, not null 1432 * @return the appropriate plural ordinality family (if one exists) for the given locale, not null 1433 */ 1434 @NonNull 1435 static Optional<OrdinalityFamily> ordinalityFamilyForLocale(@NonNull Locale locale) { 1436 requireNonNull(locale); 1437 1438 String language = LocaleUtils.normalizedLanguage(locale).orElse(null); 1439 String country = locale.getCountry(); 1440 1441 OrdinalityFamily ordinalityFamily = null; 1442 1443 if (language != null && country != null) 1444 ordinalityFamily = ORDINALITY_FAMILIES_BY_LANGUAGE_CODE.get(format("%s-%s", language, country)); 1445 1446 if (ordinalityFamily != null) 1447 return Optional.of(ordinalityFamily); 1448 1449 if (language != null) 1450 ordinalityFamily = ORDINALITY_FAMILIES_BY_LANGUAGE_CODE.get(language); 1451 1452 return Optional.ofNullable(ordinalityFamily); 1453 } 1454 } 1455}