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