1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************** 5 * Copyright (C) 2003-2016, Google, International Business Machines Corporation 6 * and others. All Rights Reserved. 7 ******************************************************************************** 8 */ 9 package com.ibm.icu.util; 10 11 import java.util.Arrays; 12 import java.util.HashMap; 13 import java.util.List; 14 import java.util.Locale; 15 import java.util.Map; 16 import java.util.MissingResourceException; 17 18 import com.ibm.icu.impl.ICUCache; 19 import com.ibm.icu.impl.ICUData; 20 import com.ibm.icu.impl.ICUResourceBundle; 21 import com.ibm.icu.impl.SimpleCache; 22 23 /** 24 * Provide information about gender in locales based on data in CLDR. Currently supplies gender of lists. 25 * @author markdavis 26 * @internal 27 * @deprecated This API is ICU internal only. 28 */ 29 @Deprecated 30 public class GenderInfo { 31 32 private final ListGenderStyle style; // set based on locale 33 34 /** 35 * Gender: OTHER means either the information is unavailable, or the person has declined to state MALE or FEMALE. 36 * @internal 37 * @deprecated This API is ICU internal only. 38 */ 39 @Deprecated 40 public enum Gender { 41 /** 42 * @internal 43 * @deprecated This API is ICU internal only. 44 */ 45 @Deprecated 46 MALE, 47 /** 48 * @internal 49 * @deprecated This API is ICU internal only. 50 */ 51 @Deprecated 52 FEMALE, 53 /** 54 * @internal 55 * @deprecated This API is ICU internal only. 56 */ 57 @Deprecated 58 OTHER 59 } 60 61 /** 62 * Create GenderInfo from a ULocale. 63 * @param uLocale desired locale 64 * @internal 65 * @deprecated This API is ICU internal only. 66 */ 67 @Deprecated getInstance(ULocale uLocale)68 public static GenderInfo getInstance(ULocale uLocale) { 69 return genderInfoCache.get(uLocale); 70 } 71 72 /** 73 * Create GenderInfo from a Locale. 74 * @param locale desired locale 75 * @internal 76 * @deprecated This API is ICU internal only. 77 */ 78 @Deprecated getInstance(Locale locale)79 public static GenderInfo getInstance(Locale locale) { 80 return getInstance(ULocale.forLocale(locale)); 81 } 82 83 /** 84 * Enum only meant for use in CLDR and in testing. Indicates the category for the locale. 85 * This only affects gender for lists more than one. For lists of 1 item, the gender 86 * of the list always equals the gender of that sole item. 87 * @internal 88 * @deprecated This API is ICU internal only. 89 */ 90 @Deprecated 91 public enum ListGenderStyle { 92 /** 93 * For an empty list, returns OTHER; 94 * For a single item, returns its gender; 95 * Otherwise always OTHER. 96 * @internal 97 * @deprecated This API is ICU internal only. 98 */ 99 @Deprecated 100 NEUTRAL, 101 /** 102 * For an empty list, returns OTHER; 103 * For a single item, returns its gender; 104 * Otherwise gender(all male) = male, gender(all female) = female, otherwise gender(list) = other. 105 * So any 'other' value makes the overall gender be 'other'. 106 * @internal 107 * @deprecated This API is ICU internal only. 108 */ 109 @Deprecated 110 MIXED_NEUTRAL, 111 /** 112 * For an empty list, returns OTHER; 113 * For a single item, returns its gender; 114 * Otherwise, gender(all female) = female, otherwise gender(list) = male. 115 * So for more than one item, any 'other' value makes the overall gender be 'male'. 116 * @internal 117 * @deprecated This API is ICU internal only. 118 */ 119 @Deprecated 120 MALE_TAINTS; 121 122 private static Map<String, ListGenderStyle> fromNameMap = 123 new HashMap<String, ListGenderStyle>(3); 124 125 static { 126 fromNameMap.put("neutral", NEUTRAL); 127 fromNameMap.put("maleTaints", MALE_TAINTS); 128 fromNameMap.put("mixedNeutral", MIXED_NEUTRAL); 129 } 130 131 /** 132 * @internal 133 * @deprecated This API is ICU internal only. 134 */ 135 @Deprecated fromName(String name)136 public static ListGenderStyle fromName(String name) { 137 ListGenderStyle result = fromNameMap.get(name); 138 if (result == null) { 139 throw new IllegalArgumentException("Unknown gender style name: " + name); 140 } 141 return result; 142 } 143 } 144 145 /** 146 * Get the gender of a list, based on locale usage. 147 * @param genders a list of genders. 148 * @return the gender of the list. 149 * @internal 150 * @deprecated This API is ICU internal only. 151 */ 152 @Deprecated getListGender(Gender... genders)153 public Gender getListGender(Gender... genders) { 154 return getListGender(Arrays.asList(genders)); 155 } 156 157 /** 158 * Get the gender of a list, based on locale usage. 159 * @param genders a list of genders. 160 * @return the gender of the list. 161 * @internal 162 * @deprecated This API is ICU internal only. 163 */ 164 @Deprecated getListGender(List<Gender> genders)165 public Gender getListGender(List<Gender> genders) { 166 if (genders.size() == 0) { 167 return Gender.OTHER; // degenerate case 168 } 169 if (genders.size() == 1) { 170 return genders.get(0); // degenerate case 171 } 172 switch(style) { 173 case NEUTRAL: 174 return Gender.OTHER; 175 case MIXED_NEUTRAL: 176 boolean hasFemale = false; 177 boolean hasMale = false; 178 for (Gender gender : genders) { 179 switch (gender) { 180 case FEMALE: 181 if (hasMale) { 182 return Gender.OTHER; 183 } 184 hasFemale = true; 185 break; 186 case MALE: 187 if (hasFemale) { 188 return Gender.OTHER; 189 } 190 hasMale = true; 191 break; 192 case OTHER: 193 return Gender.OTHER; 194 } 195 } 196 return hasMale ? Gender.MALE : Gender.FEMALE; 197 // Note: any OTHER would have caused a return in the loop, which always happens. 198 case MALE_TAINTS: 199 for (Gender gender : genders) { 200 if (gender != Gender.FEMALE) { 201 return Gender.MALE; 202 } 203 } 204 return Gender.FEMALE; 205 default: 206 return Gender.OTHER; 207 } 208 } 209 210 /** 211 * Only for testing and use with CLDR. 212 * @param genderStyle gender style 213 * @internal 214 * @deprecated This API is ICU internal only. 215 */ 216 @Deprecated GenderInfo(ListGenderStyle genderStyle)217 public GenderInfo(ListGenderStyle genderStyle) { 218 style = genderStyle; 219 } 220 221 private static GenderInfo neutral = new GenderInfo(ListGenderStyle.NEUTRAL); 222 223 private static class Cache { 224 private final ICUCache<ULocale, GenderInfo> cache = 225 new SimpleCache<ULocale, GenderInfo>(); 226 get(ULocale locale)227 public GenderInfo get(ULocale locale) { 228 GenderInfo result = cache.get(locale); 229 if (result == null) { 230 result = load(locale); 231 if (result == null) { 232 ULocale fallback = locale.getFallback(); 233 234 // We call get() recursively so that we can leverage the cache 235 // for all fallback locales too. If we get to the root locale, 236 // and find no resource assume that list gender style is NEUTRAL. 237 result = fallback == null ? neutral : get(fallback); 238 } 239 cache.put(locale, result); 240 } 241 return result; 242 } 243 load(ULocale ulocale)244 private static GenderInfo load(ULocale ulocale) { 245 UResourceBundle rb = UResourceBundle.getBundleInstance( 246 ICUData.ICU_BASE_NAME, 247 "genderList", 248 ICUResourceBundle.ICU_DATA_CLASS_LOADER, true); 249 UResourceBundle genderList = rb.get("genderList"); 250 try { 251 return new GenderInfo( 252 ListGenderStyle.fromName(genderList.getString(ulocale.toString()))); 253 } catch (MissingResourceException mre) { 254 return null; 255 } 256 } 257 } 258 259 private static Cache genderInfoCache = new Cache(); 260 } 261