35 36 /** 37 * Concrete implementation of the {@link java.util.spi.CalendarDataProvider 38 * CalendarDataProvider} class for the JRE LocaleProviderAdapter. 39 * 40 * @author Masayoshi Okutsu 41 * @author Naoto Sato 42 */ 43 public class CalendarNameProviderImpl extends CalendarNameProvider implements AvailableLanguageTags { 44 private final LocaleProviderAdapter.Type type; 45 private final Set<String> langtags; 46 47 public CalendarNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) { 48 this.type = type; 49 this.langtags = langtags; 50 } 51 52 @Override 53 public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { 54 String name = null; 55 String key = getKey(calendarType, field, style); 56 if (key != null) { 57 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); 58 if (rb.containsKey(key)) { 59 String[] strings = rb.getStringArray(key); 60 if (strings.length > 0) { 61 if (field == DAY_OF_WEEK || field == YEAR) { 62 --value; 63 } 64 name = strings[value]; 65 // If name is empty in standalone, try its `format' style. 66 if (name.length() == 0 67 && (style == SHORT_STANDALONE || style == LONG_STANDALONE)) { 68 name = getDisplayName(calendarType, field, value, 69 style == SHORT_STANDALONE ? SHORT_FORMAT : LONG_FORMAT, 70 locale); 71 } 72 } 73 } 74 } 75 return name; 76 } 77 78 @Override 79 public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) { 80 Map<String, Integer> names; 81 if (style == ALL_STYLES) { 82 names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); 83 if (field != AM_PM) { 84 for (int st : new int[] { SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE }) { 85 names.putAll(getDisplayNamesImpl(calendarType, field, st, locale)); 86 } 87 } 88 } else { 89 // specific style 90 names = getDisplayNamesImpl(calendarType, field, style, locale); 91 } 92 return names.isEmpty() ? null : names; 93 } 94 95 private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field, 96 int style, Locale locale) { 97 String key = getKey(calendarType, field, style); 98 Map<String, Integer> map = new TreeMap<>(LengthBasedComparator.INSTANCE); 99 if (key != null) { 100 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); 101 if (rb.containsKey(key)) { 102 String[] strings = rb.getStringArray(key); 103 if (field == YEAR) { 104 if (strings.length > 0) { 105 map.put(strings[0], 1); 106 } 107 } else { 108 int base = (field == DAY_OF_WEEK) ? 1 : 0; 109 for (int i = 0; i < strings.length; i++) { 110 String name = strings[i]; 111 // Ignore any empty string (some standalone month names 112 // are not defined) 113 if (name.length() == 0) { 114 continue; 115 } 116 map.put(name, base + i); 117 } 118 } 119 } 120 } 121 return map; 122 } 123 124 /** 125 * Comparator implementation for TreeMap which iterates keys from longest 126 * to shortest. 127 */ 128 private static class LengthBasedComparator implements Comparator<String> { 129 private static final LengthBasedComparator INSTANCE = new LengthBasedComparator(); 130 131 private LengthBasedComparator() { 132 } 133 134 @Override 135 public int compare(String o1, String o2) { 136 int n = o2.length() - o1.length(); 137 return (n == 0) ? o1.compareTo(o2) : n; 138 } 139 } 140 141 @Override 142 public Locale[] getAvailableLocales() { 143 return LocaleProviderAdapter.toLocaleArray(langtags); 163 default: 164 // Unknown calendar type 165 return false; 166 } 167 } 168 if (langtags.contains(locale.toLanguageTag())) { 169 return true; 170 } 171 if (type == LocaleProviderAdapter.Type.JRE) { 172 String oldname = locale.toString().replace('_', '-'); 173 return langtags.contains(oldname); 174 } 175 return false; 176 } 177 178 @Override 179 public Set<String> getAvailableLanguageTags() { 180 return langtags; 181 } 182 183 private int getIntData(String key, Locale locale) { 184 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getCalendarData(locale); 185 if (rb.containsKey(key)) { 186 String firstday = rb.getString(key); 187 return Integer.parseInt(firstday); 188 } 189 // Note that the base bundle of CLDR doesn't have the Calendar week parameters. 190 return 0; 191 } 192 193 private String getKey(String type, int field, int style) { 194 boolean standalone = (style & 0x8000) != 0; 195 style &= ~0x8000; 196 197 if ("gregory".equals(type)) { 198 type = null; 199 } 200 201 StringBuilder key = new StringBuilder(); 202 switch (field) { 203 case ERA: 204 if (type != null) { 205 key.append(type).append('.'); 206 } 207 if (style == SHORT) { 208 key.append("short."); 209 } 210 key.append("Eras"); 211 break; 212 213 case YEAR: 214 key.append(type).append(".FirstYear"); 215 break; 216 217 case MONTH: 218 if (standalone) { 219 key.append("standalone."); 220 } 221 key.append(style == SHORT ? "MonthAbbreviations" : "MonthNames"); 222 break; 223 224 case DAY_OF_WEEK: 225 key.append(style == SHORT ? "DayAbbreviations" : "DayNames"); 226 break; 227 228 case AM_PM: 229 key.append("AmPmMarkers"); 230 break; 231 } 232 return key.length() > 0 ? key.toString() : null; 233 } 234 } | 35 36 /** 37 * Concrete implementation of the {@link java.util.spi.CalendarDataProvider 38 * CalendarDataProvider} class for the JRE LocaleProviderAdapter. 39 * 40 * @author Masayoshi Okutsu 41 * @author Naoto Sato 42 */ 43 public class CalendarNameProviderImpl extends CalendarNameProvider implements AvailableLanguageTags { 44 private final LocaleProviderAdapter.Type type; 45 private final Set<String> langtags; 46 47 public CalendarNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) { 48 this.type = type; 49 this.langtags = langtags; 50 } 51 52 @Override 53 public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { 54 String name = null; 55 String key = getResourceKey(calendarType, field, style); 56 if (key != null) { 57 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); 58 if (rb.containsKey(key)) { 59 String[] strings = rb.getStringArray(key); 60 if (strings.length > 0) { 61 if (field == DAY_OF_WEEK || field == YEAR) { 62 --value; 63 } 64 name = strings[value]; 65 // If name is empty in standalone, try its `format' style. 66 if (name.length() == 0 67 && (style == SHORT_STANDALONE || style == LONG_STANDALONE 68 || style == NARROW_STANDALONE)) { 69 name = getDisplayName(calendarType, field, value, 70 getBaseStyle(style), 71 locale); 72 } 73 } 74 } 75 } 76 return name; 77 } 78 79 @Override 80 public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) { 81 Map<String, Integer> names; 82 if (style == ALL_STYLES) { 83 names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); 84 for (int st : new int[] { SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE, 85 NARROW_FORMAT, NARROW_STANDALONE }) { 86 names.putAll(getDisplayNamesImpl(calendarType, field, st, locale)); 87 } 88 } else { 89 // specific style 90 names = getDisplayNamesImpl(calendarType, field, style, locale); 91 } 92 return names.isEmpty() ? null : names; 93 } 94 95 private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field, 96 int style, Locale locale) { 97 String key = getResourceKey(calendarType, field, style); 98 Map<String, Integer> map = new TreeMap<>(LengthBasedComparator.INSTANCE); 99 if (key != null) { 100 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); 101 if (rb.containsKey(key)) { 102 String[] strings = rb.getStringArray(key); 103 if (!hasDuplicates(strings)) { 104 if (field == YEAR) { 105 if (strings.length > 0) { 106 map.put(strings[0], 1); 107 } 108 } else { 109 int base = (field == DAY_OF_WEEK) ? 1 : 0; 110 for (int i = 0; i < strings.length; i++) { 111 String name = strings[i]; 112 // Ignore any empty string (some standalone month names 113 // are not defined) 114 if (name.length() == 0) { 115 continue; 116 } 117 map.put(name, base + i); 118 } 119 } 120 } 121 } 122 } 123 return map; 124 } 125 126 private int getBaseStyle(int style) { 127 return style & ~(SHORT_STANDALONE - SHORT_FORMAT); 128 } 129 130 /** 131 * Comparator implementation for TreeMap which iterates keys from longest 132 * to shortest. 133 */ 134 private static class LengthBasedComparator implements Comparator<String> { 135 private static final LengthBasedComparator INSTANCE = new LengthBasedComparator(); 136 137 private LengthBasedComparator() { 138 } 139 140 @Override 141 public int compare(String o1, String o2) { 142 int n = o2.length() - o1.length(); 143 return (n == 0) ? o1.compareTo(o2) : n; 144 } 145 } 146 147 @Override 148 public Locale[] getAvailableLocales() { 149 return LocaleProviderAdapter.toLocaleArray(langtags); 169 default: 170 // Unknown calendar type 171 return false; 172 } 173 } 174 if (langtags.contains(locale.toLanguageTag())) { 175 return true; 176 } 177 if (type == LocaleProviderAdapter.Type.JRE) { 178 String oldname = locale.toString().replace('_', '-'); 179 return langtags.contains(oldname); 180 } 181 return false; 182 } 183 184 @Override 185 public Set<String> getAvailableLanguageTags() { 186 return langtags; 187 } 188 189 private boolean hasDuplicates(String[] strings) { 190 int len = strings.length; 191 for (int i = 0; i < len - 1; i++) { 192 String a = strings[i]; 193 if (a != null) { 194 for (int j = i + 1; j < len; j++) { 195 if (a.equals(strings[j])) { 196 return true; 197 } 198 } 199 } 200 } 201 return false; 202 } 203 204 private String getResourceKey(String type, int field, int style) { 205 int baseStyle = getBaseStyle(style); 206 boolean isStandalone = (style != baseStyle); 207 208 if ("gregory".equals(type)) { 209 type = null; 210 } 211 boolean isNarrow = (baseStyle == NARROW_FORMAT); 212 StringBuilder key = new StringBuilder(); 213 switch (field) { 214 case ERA: 215 if (type != null) { 216 key.append(type).append('.'); 217 } 218 if (isNarrow) { 219 key.append("narrow."); 220 } else { 221 // JRE and CLDR use different resource key conventions 222 // due to historical reasons. (JRE DateFormatSymbols.getEras returns 223 // abbreviations while other getShort*() return abbreviations.) 224 if (this.type == LocaleProviderAdapter.Type.JRE) { 225 if (baseStyle == SHORT) { 226 key.append("short."); 227 } 228 } else { // CLDR 229 if (baseStyle == LONG) { 230 key.append("long."); 231 } 232 } 233 } 234 key.append("Eras"); 235 break; 236 237 case YEAR: 238 if (!isNarrow) { 239 key.append(type).append(".FirstYear"); 240 } 241 break; 242 243 case MONTH: 244 if (isStandalone) { 245 key.append("standalone."); 246 } 247 key.append("Month").append(toStyleName(baseStyle)); 248 break; 249 250 case DAY_OF_WEEK: 251 // support standalone narrow day names 252 if (isStandalone && isNarrow) { 253 key.append("standalone."); 254 } 255 key.append("Day").append(toStyleName(baseStyle)); 256 break; 257 258 case AM_PM: 259 if (isNarrow) { 260 key.append("narrow."); 261 } 262 key.append("AmPmMarkers"); 263 break; 264 } 265 return key.length() > 0 ? key.toString() : null; 266 } 267 268 private String toStyleName(int baseStyle) { 269 switch (baseStyle) { 270 case SHORT: 271 return "Abbreviations"; 272 case NARROW_FORMAT: 273 return "Narrows"; 274 } 275 return "Names"; 276 } 277 } |