package com.ibm.icu.text; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import com.ibm.icu.util.ULocale; /** * Provide information about gender in locales based on data in CLDR. Currently just gender of lists. * * @author markdavis */ public class GenderInfo { private final ListGenderStyle style; // set based on locale /** * Gender: OTHER means either the information is unavailable, or the person has declined to state MALE or FEMALE. */ public enum Gender { MALE, FEMALE, OTHER } /** * Create GenderInfo from a ULocale. * * @param uLocale */ public GenderInfo(ULocale uLocale) { ULocale language = new ULocale(uLocale.getLanguage()); // in the hard coded data, the language is sufficient. // Will change with RB. ListGenderStyle tempStyle = localeToListGender.get(language); style = tempStyle == null ? ListGenderStyle.NEUTRAL : tempStyle; } /** * Create GenderInfo from a Locale. * * @param uLocale */ public GenderInfo(Locale locale) { this(ULocale.forLocale(locale)); } /** * Enum only meant for use in CLDR and in testing. Indicates the category for the locale. */ public enum ListGenderStyle { /** * Always OTHER (if more than one) */ NEUTRAL, /** * gender(all male) = male, gender(all female) = female, otherwise gender(list) = other */ MIXED_NEUTRAL, /** * gender(all female) = female, otherwise gender(list) = male */ MALE_TAINTS } /** * Reset the data used for mapping locales to styles. Only for use in CLDR and in testing. * * @param uLocale */ public static void setLocaleMapping(Map newULocaleToListGender) { localeToListGender.clear(); for (Entry entry : newULocaleToListGender.entrySet()) { localeToListGender.put(entry.getKey(), entry.getValue()); } } /** * Get the gender of a list, based on locale usage. * * @param genders * a list of genders. * @return the gender of the list. */ public Gender getListGender(Gender... genders) { return getListGender(Arrays.asList(genders)); } /** * Get the gender of a list, based on locale usage. * * @param genders * a list of genders. * @return the gender of the list. */ public Gender getListGender(List genders) { if (genders.size() == 0 || style == ListGenderStyle.NEUTRAL) { return Gender.OTHER; // degenerate case } if (genders.size() == 1) { return genders.get(0); // degenerate case } switch (style) { case MIXED_NEUTRAL: // gender(all male) = male, gender(all female) = female, otherwise gender(list) = other boolean hasFemale = false; boolean hasMale = false; for (Gender gender : genders) { switch (gender) { case FEMALE: if (hasMale) { return Gender.OTHER; } hasFemale = true; break; case MALE: if (hasFemale) { return Gender.OTHER; } hasMale = true; break; case OTHER: return Gender.OTHER; } } return hasMale ? Gender.MALE : hasFemale ? Gender.FEMALE : Gender.OTHER; case MALE_TAINTS: // gender(all female) = female, otherwise gender(list) = male for (Gender gender : genders) { if (gender != Gender.FEMALE) { return Gender.MALE; } } return Gender.FEMALE; default: return Gender.OTHER; } } // TODO Get this data from a resource bundle generated from CLDR. // For now, hard coded. private static Map localeToListGender = new HashMap(); static { for (String locale : Arrays.asList("ar", "ca", "cs", "hr", "es", "fr", "he", "hi", "it", "lt", "lv", "mr", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sr", "uk", "ur", "zh")) { localeToListGender.put(new ULocale(locale), ListGenderStyle.MALE_TAINTS); } for (String locale : Arrays.asList("el", "is")) { localeToListGender.put(new ULocale(locale), ListGenderStyle.MIXED_NEUTRAL); } } }