/* * ----------------------------------------------------------------------- * Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * This file (PluralProviderSPI.java) is part of project Time4J. * * Time4J is free software: You can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * Time4J is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Time4J. If not, see <http://www.gnu.org/licenses/>. * ----------------------------------------------------------------------- */ package net.time4j.i18n; import net.time4j.format.NumberType; import net.time4j.format.PluralCategory; import net.time4j.format.PluralProvider; import net.time4j.format.PluralRules; import java.util.HashMap; import java.util.Locale; import java.util.Map; import static net.time4j.format.PluralCategory.FEW; import static net.time4j.format.PluralCategory.MANY; import static net.time4j.format.PluralCategory.ONE; import static net.time4j.format.PluralCategory.OTHER; import static net.time4j.format.PluralCategory.TWO; import static net.time4j.format.PluralCategory.ZERO; /** * <p>{@code ServiceProvider}-implementation for accessing localized * plural rules. </p> * * @author Meno Hochschild * @since 2.2 */ public final class PluralProviderSPI implements PluralProvider { //~ Statische Felder/Initialisierungen -------------------------------- private static final Map<String, PluralRules> CARDINAL_MAP = new HashMap<>(140); private static final PluralRules STD_CARDINALS = new StdCardinalRules(0); static { Map<String, PluralRules> cmap = new HashMap<>(); fillC(cmap, "bm bo dz id ig ii in ja jbo jv jw kde kea km ko lkt", -1); fillC(cmap, "lo ms my nqo root sah ses sg th to vi wo yo zh", -1); fillC(cmap, "pt_PT", 0); fillC(cmap, "am as bn fa gu hi kn mr zu", 1); fillC(cmap, "ff fr hy kab pt", 1); fillC(cmap, "si", 1); fillC(cmap, "ak bh guw ln mg nso pa ti wa", 1); fillC(cmap, "tzm", 2); fillC(cmap, "is", 3); fillC(cmap, "mk", 4); fillC(cmap, "fil tl", 5); fillC(cmap, "lv prg", 6); fillC(cmap, "lag ksh", 7); fillC(cmap, "iu kw naq se sma smi smj smn sms", 8); fillC(cmap, "shi", 9); fillC(cmap, "mo ro", 10); fillC(cmap, "bs hr sh sr", 11); fillC(cmap, "gd", 12); fillC(cmap, "sl", 13); fillC(cmap, "he iw", 14); fillC(cmap, "cs sk", 15); fillC(cmap, "pl", 16); fillC(cmap, "be", 17); fillC(cmap, "lt", 18); fillC(cmap, "mt", 19); fillC(cmap, "ru uk", 17); fillC(cmap, "br", 20); fillC(cmap, "ga", 21); fillC(cmap, "gv", 22); fillC(cmap, "ar", 23); fillC(cmap, "cy", 24); fillC(cmap, "dsb hsb", 25); CARDINAL_MAP.putAll(cmap); } private static final Map<String, PluralRules> ORDINAL_MAP = new HashMap<>(140); private static final PluralRules STD_ORDINALS = new StdOrdinalRules(0); static { Map<String, PluralRules> omap = new HashMap<>(); fillO(omap, "sv", 1); fillO(omap, "fil fr ga hy lo mo ms ro tl vi", 2); fillO(omap, "hu", 3); fillO(omap, "ne", 4); fillO(omap, "kk", 5); fillO(omap, "it", 6); fillO(omap, "ka", 7); fillO(omap, "sq", 8); fillO(omap, "en", 9); fillO(omap, "mr", 10); fillO(omap, "ca", 11); fillO(omap, "mk", 12); fillO(omap, "az", 13); fillO(omap, "gu hi", 14); fillO(omap, "as bn", 15); fillO(omap, "cy", 16); fillO(omap, "be", 17); fillO(omap, "uk", 18); ORDINAL_MAP.putAll(omap); } //~ Konstruktoren ----------------------------------------------------- /** For {@code java.util.ServiceLoader}. */ public PluralProviderSPI() { super(); } //~ Methoden ---------------------------------------------------------- public PluralRules load( Locale locale, NumberType numType ) { Map<String, PluralRules> map; PluralRules stdRules; switch (numType) { case CARDINALS: map = CARDINAL_MAP; stdRules = STD_CARDINALS; break; case ORDINALS: map = ORDINAL_MAP; stdRules = STD_ORDINALS; break; default: throw new UnsupportedOperationException(numType.name()); } PluralRules rules = null; if (!locale.getCountry().equals("")) { StringBuilder kb = new StringBuilder(); kb.append(locale.getLanguage()); kb.append('_'); kb.append(locale.getCountry()); rules = map.get(kb.toString()); } if (rules == null) { rules = map.get(locale.getLanguage()); } if (rules == null) { return stdRules; } return rules; } private static void fillC( Map<String, PluralRules> map, String languages, int id ) { for (String language : languages.split(" ")) { map.put(language, new StdCardinalRules(id)); } } private static void fillO( Map<String, PluralRules> map, String languages, int id ) { for (String language : languages.split(" ")) { map.put(language, new StdOrdinalRules(id)); } } //~ Innere Klassen ---------------------------------------------------- private static class StdCardinalRules extends PluralRules { //~ Instanzvariablen ---------------------------------------------- private final int id; //~ Konstruktoren ------------------------------------------------- private StdCardinalRules(int id) { super(); this.id = id; } //~ Methoden ------------------------------------------------------ @Override public PluralCategory getCategory(long n) { long mod10; long mod100; switch (this.id) { case 0: // STD_RULES return (n == 1 ? ONE : OTHER); case 1: // französisch (fr) return ((n == 0) || (n == 1) ? ONE : OTHER); case 2: // Tamazight, Central Atlas (tzm) if (n == 0 || n == 1 || (n >= 11 && n <= 99)) { return ONE; } return OTHER; case 3: // isländisch (is) if (((n % 10) == 1) && ((n % 100) != 11)) { return ONE; } return OTHER; case 4: // mazedonisch (mk) return ((n % 10) == 1 ? ONE : OTHER); case 5: // tagalog - Philippinen (fil) if (n >= 1 && n <= 3) { return ONE; } mod10 = n % 10; if (mod10 == 4 || mod10 == 6 || mod10 == 9) { return OTHER; } else { return ONE; } case 6: // lettisch (lv) if (n % 10 == 0) { return ZERO; } mod100 = n % 100; if (mod100 >= 11 && mod100 <= 19) { return ZERO; } else if (((n % 10) == 1) && (mod100 != 11)) { return ONE; } return OTHER; case 7: // langi (lag) if (n == 0) { return ZERO; } else if (n == 1) { return ONE; } return OTHER; case 8: // Inuktitut (iu) if (n == 1) { return ONE; } else if (n == 2) { return TWO; } return OTHER; case 9: // tachelhit (shi) if (n == 0 || n == 1) { return ONE; } else if (n >= 2 && n <= 10) { return FEW; } return OTHER; case 10: // moldawisch (mo | ro) if (n == 1) { return ONE; } else if (n == 0) { return FEW; } mod100 = n % 100; if (mod100 >= 1 && mod100 <= 19 && n != 1) { return FEW; } return OTHER; case 11: // bosnisch (bs) mod100 = n % 100; if (((n % 10) == 1) && (mod100 != 11)) { return ONE; } else if ( n % 10 >= 2 && n % 10 <= 4 && mod100 != 12 && mod100 != 13 && mod100 != 14 ) { return FEW; } return OTHER; case 12: // schottisch (gd) if (n == 1 || n == 11) { return ONE; } else if (n == 2 || n == 12) { return TWO; } else if ( (n >= 3 && n <= 10) || (n >= 13 && n <= 19) ) { return FEW; } return OTHER; case 13: // slowenisch (sl) mod100 = n % 100; if (mod100 == 1) { return ONE; } else if (mod100 == 2) { return TWO; } else if (mod100 == 3 || mod100 == 4) { return FEW; } return OTHER; case 14: // hebräisch (he iw) if (n == 1) { return ONE; } else if (n == 2) { return TWO; } else if (n >= 11 && (n % 10 == 0)) { return MANY; } return OTHER; case 15: // tschechisch (cs) if (n == 1) { return ONE; } else if (n >= 2 && n <= 4) { return FEW; } return OTHER; case 16: // polnisch (pl) if (n == 1) { return ONE; } mod10 = n % 10; mod100 = n % 100; if ( mod10 >= 2 && mod10 <= 4 && mod100 != 12 && mod100 != 13 && mod100 != 14 ) { return FEW; } else if ( (n != 1 && mod10 >= 0 && mod10 <= 1) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 12 && mod100 <= 14) ) { return MANY; } return OTHER; case 17: // belorussisch (be) mod10 = n % 10; mod100 = n % 100; if (mod10 == 1 && mod100 != 11) { return ONE; } else if ( mod10 >= 2 && mod10 <= 4 && mod100 != 12 && mod100 != 13 && mod100 != 14 ) { return FEW; } else if ( (mod10 == 0) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14) ) { return MANY; } return OTHER; case 18: // litauisch (lt) mod10 = n % 10; mod100 = n % 100; if (mod10 == 1 && !(mod100 >= 11 && mod100 <= 19)) { return ONE; } else if ( mod10 >= 2 && mod10 <= 9 && !(mod100 >= 11 && mod100 <= 19) ) { return FEW; } return OTHER; case 19: // maltesisch (mt) if (n == 1) { return ONE; } mod100 = n % 100; if (n == 0 || (mod100 >= 2 && mod100 <= 10)) { return FEW; } else if (mod100 >= 11 && mod100 <= 19) { return MANY; } return OTHER; case 20: // bretonisch (br) mod10 = n % 10; mod100 = n % 100; if ( mod10 == 1 && mod100 != 11 && mod100 != 71 && mod100 != 91 ) { return ONE; } else if ( mod10 == 2 && mod100 != 12 && mod100 != 72 && mod100 != 92 ) { return TWO; } else if ( (mod10 == 3 || mod10 == 4 || mod10 == 9) && !(mod100 >= 10 && mod100 <= 19) && !(mod100 >= 70 && mod100 <= 79) && !(mod100 >= 90 && mod100 <= 99) ) { return FEW; } else if (n != 0 && ((n % 1000000) == 0)) { return MANY; } return OTHER; case 21: // irisch (ga) if (n == 1) { return ONE; } else if (n == 2) { return TWO; } else if (n >= 3 && n <= 6) { return FEW; } else if (n >= 7 && n <= 10) { return MANY; } return OTHER; case 22: // Manx - Isle Of Man (gv) mod10 = n % 10; mod100 = n % 100; if (mod10 == 1) { return ONE; } else if (mod10 == 2) { return TWO; } else if ( mod100 == 0 || mod100 == 20 || mod100 == 40 || mod100 == 60 || mod100 == 80 ) { return FEW; } return OTHER; case 23: // arabisch (ar) if (n == 0) { return ZERO; } else if (n == 1) { return ONE; } else if (n == 2) { return TWO; } mod100 = n % 100; if (mod100 >= 3 && mod100 <= 10) { return FEW; } else if (mod100 >= 11 && mod100 <= 99) { return MANY; } return OTHER; case 24: // walisisch (cy) if (n == 0) { return ZERO; } else if (n == 1) { return ONE; } else if (n == 2) { return TWO; } else if (n == 3) { return FEW; } else if (n == 6) { return MANY; } return OTHER; case 25: // sorbisch (dsb/hsb) mod100 = n % 100; if (mod100 == 1) { return ONE; } else if (mod100 == 2) { return TWO; } else if (mod100 == 3 || mod100 == 4) { return FEW; } return OTHER; default: // chinesisch (zh) return OTHER; } } @Override public NumberType getNumberType() { return NumberType.CARDINALS; } } private static class StdOrdinalRules extends PluralRules { //~ Instanzvariablen ---------------------------------------------- private final int id; //~ Konstruktoren ------------------------------------------------- private StdOrdinalRules(int id) { super(); this.id = id; } //~ Methoden ------------------------------------------------------ @Override public PluralCategory getCategory(long n) { long mod10; long mod100; switch (this.id) { case 0: // STD_RULES return OTHER; case 1: // schwedisch (sv) mod10 = n % 10; mod100 = n % 100; if ( ((mod10 == 1) || (mod10 == 2)) && !((mod100 == 11) || (mod100 == 12)) ) { return ONE; } return OTHER; case 2: // französisch (fr) if (n == 1) { return ONE; } return OTHER; case 3: // ungarisch (hu) if ((n == 1) || (n == 5)) { return ONE; } return OTHER; case 4: // nepalesisch (ne) if ((n >= 1) || (n <= 4)) { return ONE; } return OTHER; case 5: // kasachisch (kk) mod10 = n % 10; if ( (mod10 == 6) || (mod10 == 9) || ((mod10 == 0) && (n != 0)) ) { return MANY; } return OTHER; case 6: // italienisch (it) if ( (n == 8) || (n == 11) || (n == 80) || (n == 800) ) { return MANY; } return OTHER; case 7: // georgisch (ka) mod100 = n % 100; if (n == 1) { return ONE; } else if ( (n == 0) || (mod100 >= 2 && mod100 <= 20) || (mod100 == 40) || (mod100 == 60) || (mod100 == 80) ) { return MANY; } return OTHER; case 8: // albanisch (sq) if (n == 1) { return ONE; } else if (((n % 10) == 4) && ((n % 100) != 14)) { return MANY; } return OTHER; case 9: // englisch (en) mod10 = n % 10; mod100 = n % 100; if ((mod10 == 1) && (mod100 != 11)) { return ONE; } else if ((mod10 == 2) && (mod100 != 12)) { return TWO; } else if ((mod10 == 3) && (mod100 != 13)) { return FEW; } return OTHER; case 10: // Marathi - Indien (mr) if (n == 1) { return ONE; } else if ((n == 2) || (n == 3)) { return TWO; } else if (n == 4) { return FEW; } return OTHER; case 11: // katalanisch (ca) if ((n == 1) || (n == 3)) { return ONE; } else if (n == 2) { return TWO; } else if (n == 4) { return FEW; } return OTHER; case 12: // mazedonisch (mk) mod10 = n % 10; mod100 = n % 100; if ((mod10 == 1) && (mod100 != 11)) { return ONE; } else if ((mod10 == 2) && (mod100 != 12)) { return TWO; } else if ( ((mod10 == 7) || (mod10 == 8)) && !((mod100 == 17) || (mod100 == 18)) ) { return MANY; } return OTHER; case 13: // aserbeidschanisch (az) mod10 = n % 10; mod100 = n % 100; long mod1000 = n % 1000; if ( (mod10 == 1) || (mod10 == 2) || (mod10 == 5) || (mod10 == 7) || (mod10 == 8) || (mod100 == 20) || (mod100 == 50) || (mod100 == 70) || (mod100 == 80) ) { return ONE; } else if ( (mod10 == 3) || (mod10 == 4) || (mod1000 == 100) || (mod1000 == 200) || (mod1000 == 300) || (mod1000 == 400) || (mod1000 == 500) || (mod1000 == 600) || (mod1000 == 700) || (mod1000 == 800) || (mod1000 == 900) ) { return FEW; } else if ( (n == 0) || (mod10 == 6) || (mod100 == 40)|| (mod100 == 60)|| (mod100 == 90) ) { return MANY; } return OTHER; case 14: // hindi (hi) if (n == 1) { return ONE; } else if ((n == 2) || (n == 3)) { return TWO; } else if (n == 4) { return FEW; } else if (n == 6) { return MANY; } return OTHER; case 15: // bengalisch (bn) if ( (n == 1) || (n == 5) || ((n >= 7) && (n <= 10)) ) { return ONE; } else if ((n == 2) || (n == 3)) { return TWO; } else if (n == 4) { return FEW; } else if (n == 6) { return MANY; } return OTHER; case 16: // walisisch (cy) if ( (n == 0) || ((n >= 7) && (n <= 9)) ) { return ZERO; } else if (n == 1) { return ONE; } else if (n == 2) { return TWO; } else if ((n == 3) || (n == 4)) { return FEW; } else if ((n == 5) || (n == 6)) { return MANY; } return OTHER; case 17: // weißrussisch (be) mod10 = n % 10; mod100 = n % 100; if ( ((mod10 == 2) || (mod10 == 3)) && !((mod100 == 12) || (mod100 == 13)) ) { return FEW; } return OTHER; case 18: // ukrainisch (uk) mod10 = n % 10; mod100 = n % 100; if ( (mod10 == 3) && (mod100 != 13) ) { return FEW; } return OTHER; default: // fallback return OTHER; } } @Override public NumberType getNumberType() { return NumberType.ORDINALS; } } }