All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.force.i18n.grammar.impl.LanguageDeclensionFactory Maven / Gradle / Ivy

There is a newer version: 1.2.30
Show newest version
/*
 * Copyright (c) 2017, salesforce.com, inc.
 * All rights reserved.
 * Licensed under the BSD 3-Clause license.
 * For full license text, see LICENSE.txt file in the repo root  or https://opensource.org/licenses/BSD-3-Clause
 */

package com.force.i18n.grammar.impl;

import static com.force.i18n.LanguageConstants.*;

import java.util.HashMap;
import java.util.Map;

import com.force.i18n.HumanLanguage;
import com.force.i18n.I18nJavaUtil;
import com.force.i18n.LanguageProviderFactory;
import com.force.i18n.grammar.LanguageDeclension;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
/**
 * For a given language, provide the declension associated with it.
 *
 * This should be the only "public" member in this package
 *
 * @author stamm
 */
public enum LanguageDeclensionFactory {
    INSTANCE;
    public static LanguageDeclensionFactory get() { return INSTANCE; }

    private final Map declensions;
    private final LanguageDeclension defaultDeclension;  // English is asked for more than everything else, make it durn quick
    private final HumanLanguage baseLanguage;

    @SuppressWarnings({"rawtypes","unchecked"})  // Don't require humanLanguage is an enum
    private LanguageDeclensionFactory() {
        baseLanguage = LanguageProviderFactory.get().getProvider().getBaseLanguage();
        Map map;
        if (baseLanguage instanceof Enum) {
            // There's no good way to do this
            Map eMap = Maps.newEnumMap(baseLanguage.getClass().asSubclass(Enum.class));
            map = eMap;
        } else {
            map = new HashMap<>();
        }
        for (HumanLanguage language : LanguageProviderFactory.get().getProvider().getAll()) {
            LanguageDeclension declension = createDeclension(language, map);
            map.computeIfAbsent(language, l -> declension);
        }
        declensions = ImmutableMap.copyOf(map);
        defaultDeclension = declensions.get(baseLanguage);
    }

    /**
     * @return For the given language, return the associated declension
     * @param language the given language
     */
    public LanguageDeclension getDeclension(HumanLanguage language) {
        if (language == baseLanguage) return defaultDeclension;
        return declensions.get(language);
    }

    /**
     * Convenient method to determine if the desclension is forwarding proxy.
     *
     * @param declension the declension to test
     * @return {@code true} if the given declension is forwarding proxy, {@code false} otherwise.
     */
    public boolean isForwardingProxy(LanguageDeclension declension) {
        return ForwardingLanguageDeclension.isForwardingProxy(declension);
    }

    /**
     * Convenient method to determine if the desclension is forwarding proxy.
     *
     * @param language the language to test
     * @return {@code true} if the given declension is forwarding proxy, {@code false} otherwise.
     */
    public boolean isForwardingProxy(HumanLanguage language) {
        return isForwardingProxy(getDeclension(language));
    }

    // set "false" to switch back to the old behavior. giving packge-only scope for test access.
    static final boolean USE_PROXY = true;

    private LanguageDeclension createDeclension(HumanLanguage language, Map map) {
        LanguageDeclension declension = createDeclension(language);

        // skip returning a new declension object if the language can be safely re-mapped to its fallback.
        if (!language.isTranslatedLanguage() && USE_PROXY) {
            HumanLanguage fallback = language.getFallbackLanguage();
            LanguageDeclension fallbackDeclension = map.computeIfAbsent(fallback, l -> createDeclension(l, map));
            assert fallbackDeclension != null;

            // create forwarding proxy only when the fallback declension equals to the given language's.
            if (fallbackDeclension.getClass() == declension.getClass()) {
                // note that this impacts GrammaticalTerm.declension value for non-translated languages.
                //
                // for example, "en_AU" creates a proxy declension w/ en_GB as a delegate. although the
                // declesion.getLanguage() reports the right language -- "en_AU", terms in dictionary claims its
                // declension is "en_GB".
                // e.g.
                //    // assume "declension" is a LanguageDeclension object for "en_AU"
                //    assert declension.getLanguage() == "en_AU";
                //    assert declension.getNoun("account", false).getDeclension().getLanguage() == "en_GB";
                //
                // this is true even if GrammaticalLabelSetLoader.getUseTranslatedLanguage() returns "false". this is
                // because LangaugeDeclension.createNoun/Article/Adjective implementations pass itself as "this", which
                // is NOT a proxy object but proxy.delegate. (note that Proxy is not a superclass of "delegate")
                // See EnglishDeclension.createNoun for example.
                //
                // this should be okay because both en_AU and en_GB are served by the same declension class. also, when
                // GrammaticalLabelSetLoader.getUseTranslatedLanguage() is true, en_AU shares the all data from "en_GB".
                // See also: GrammaticalLabelSetLoader#compute
                return ForwardingLanguageDeclension.newInstance(language, fallbackDeclension);
            }
        }
        return declension;
    }

    private LanguageDeclension createDeclension(HumanLanguage language) {
        switch (language.getLocale().getLanguage()) {
        case ENGLISH:
            return new EnglishDeclension(language);
        case ITALIAN:
            return new ItalianDeclension(language);
        case FRENCH:
            return new FrenchDeclension(language);
        case SPANISH:
            return new RomanceDeclension.SpanishDeclension(language);
        case PORTUGUESE:
            return new RomanceDeclension.PortugueseDeclension(language);
        case GERMAN:
            return new GermanicDeclension.GermanDeclension(language);
        case SWEDISH:
            return new GermanicDeclension.SwedishDeclension(language);
        case DUTCH:
            return new GermanicDeclension.DutchDeclension(language);
        case DANISH:
            return new GermanicDeclension.DanishDeclension(language);
        case CZECH:
            return new SlavicDeclension.CzechDeclension(language);
        case POLISH:
            return new SlavicDeclension.PolishDeclension(language);
        case RUSSIAN:
            return new SlavicDeclension.RussianDeclension(language);
        case CHINESE:
        case JAPANESE:
        case BURMESE:
            return new SimpleDeclension.SimpleDeclensionWithClassifiers(language);
        case VIETNAMESE:
            return new SimpleDeclension.VietnameseDeclension(language);
        case HMONG:
            return new SimpleDeclension.HmongDeclension(language);
        case THAI:
        case TAGALOG:
        case AFRIKAANS:
        case KHMER:
            return new SimpleDeclension(language);
        case KOREAN:
            return new KoreanDeclension(language);
        case INDONESIAN:
        case INDONESIAN_ISO:
        case MALAY:
        case MAORI:
        case SAMOAN:
            return new MalayoPolynesianDeclension(language);
        case HAWAIIAN:
            return new MalayoPolynesianDeclension.HawaiianDeclension(language);
        case HUNGARIAN:
            return new HungarianDeclension(language);
        case TURKISH:
            return new TurkicDeclension.TurkishDeclension(language);
        case KAZAKH:
            return new TurkicDeclension.KazakhDeclension(language);
        case FINNISH:
            return new FinnishDeclension(language);
        case ROMANIAN:
            return new RomanianDeclension(language);
        case UKRAINIAN:
            return new SlavicDeclension.UkrainianDeclension(language);
        case HEBREW:
        case HEBREW_ISO:
            return new HebrewDeclension(language);
        case ARABIC:
            return new ArabicDeclension(language);
        case AMHARIC:
            return new AmharicDeclension(language);
        case GREEK:
            return new GreekDeclension(language);
        case BULGARIAN:
        case MACEDONIAN:
            return new BulgarianDeclension(language);
        case SERBIAN_CYRILLIC:
        case SERBIAN_LATIN:
        case BOSNIAN:
        case CROATIAN:
        case MONTENEGRIN:
            return new SlavicDeclension.VariantSerboCroatianDeclension(language);
        case LITHUANIAN:
            return new BalticDeclension(language);
        case LATVIAN:
            return new BalticDeclension(language);
        case SLOVAK:
            return new SlavicDeclension.SlovakianDeclension(language);
        case SLOVENE:
            return new SlavicDeclension.SlovenianDeclension(language);
        case NORWEGIAN:
            return new GermanicDeclension.NorwegianDeclension(language);
        case GEORGIAN:
            return new SlavicDeclension.GeorgianDeclension(language);
        case ESPERANTO:
            return new EsperantoDeclension(language);
        case ICELANDIC:
            return new GermanicDeclension.IcelandicDeclension(language);
        case ESTONIAN:
            return new FinnishDeclension.EstonianDeclension(language);
        case ALBANIAN:
            return new AlbanianDeclension(language);
        case ROMANSH:
            return new FrenchDeclension.RomanshDeclension(language);
        case LUXEMBOURGISH:
            return new GermanicDeclension.LuxembourgishDeclension(language);
        case YIDDISH:
        case YIDDISH_ISO: 
            return new GermanicDeclension.YiddishDeclension(language);
        case ARMENIAN:
            return new ArmenianDeclension(language);
        case CATALAN:
            return new CatalanDeclension(language);
        case HINDI:
        case URDU:
            return new HindiUrduDeclension(language);
        case BENGALI:
            return new BengaliDeclension(language);
        case SWAHILI:
            return new BantuDeclension.SwahiliDeclension(language);
        case ZULU:
            return new BantuDeclension.ZuluDeclension(language);
        case XHOSA:
            return new BantuDeclension.XhosaDeclension(language);
        case TAMIL:
            return new DravidianDeclension.TamilDeclension(language);
        case TELUGU:
            return new DravidianDeclension.TeluguDeclension(language);
        case KANNADA:
            return new DravidianDeclension.KannadaDeclension(language);
        case MALAYALAM:
            return new DravidianDeclension.MalayalamDeclension(language);
        case GUJARATI:
            return new IndoAryanDeclension.GujaratiDeclension(language);
        case MARATHI:
            return new IndoAryanDeclension.MarathiDeclension(language);
        case PUNJABI:
        case PUNJABI_WESTERN:
            return new IndoAryanDeclension.PunjabiDeclension(language);
        // Languages too complex to support *EVER*.  Included with ans
        case IRISH:    // Lenition
            return new UnsupportedLanguageDeclension.IrishDeclension(language);
        case WELSH:    // Lenition
            return new UnsupportedLanguageDeclension.CelticDeclension(language);
        case BASQUE:   // Agglutintive in a way that can't really be supported
            return new UnsupportedLanguageDeclension.BasqueDeclension(language);
        case MALTESE:  // More complicated than arabic: complicated starts with, dual form, etc.
            return new UnsupportedLanguageDeclension.MalteseDeclension(language);
        case PERSIAN:  // Arabic vs Persian native words have different declensions
            return new UnsupportedLanguageDeclension.PersianDeclension(language);
        case HAITIAN_CREOLE:
            return new UnsupportedLanguageDeclension.HaitianCreoleDeclension(language);
        case GREENLANDIC:
            return new UnsupportedLanguageDeclension.GreenlandicDeclension(language);
        case CHUJ:
            return new SimpleDeclension(language);
        case KICHE:
            return new SimpleDeclension(language);  
        case KAQCHIKEL:
            return new SimpleDeclension(language);            
        }

        if (FAIL_ON_MISSING) {
            throw new UnsupportedOperationException(
                    "Language " + language + " has no defined declension; the build breaker edited UserLanguage");
        } else {
            return new SimpleDeclension(language);
        }
    }

    private final boolean FAIL_ON_MISSING = "true".equals(I18nJavaUtil.getProperty("failOnMissingDeclension"));
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy