private void setup( String resourceKey, Map<TimeUnit, Map<String, Object[]>> timeUnitToCountToPatterns, int style) { // fill timeUnitToCountToPatterns from resource file try { ICUResourceBundle resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale); ICUResourceBundle unitsRes = resource.getWithFallback(resourceKey); int size = unitsRes.getSize(); for (int index = 0; index < size; ++index) { String timeUnitName = unitsRes.get(index).getKey(); TimeUnit timeUnit = null; if (timeUnitName.equals("year")) { timeUnit = TimeUnit.YEAR; } else if (timeUnitName.equals("month")) { timeUnit = TimeUnit.MONTH; } else if (timeUnitName.equals("day")) { timeUnit = TimeUnit.DAY; } else if (timeUnitName.equals("hour")) { timeUnit = TimeUnit.HOUR; } else if (timeUnitName.equals("minute")) { timeUnit = TimeUnit.MINUTE; } else if (timeUnitName.equals("second")) { timeUnit = TimeUnit.SECOND; } else if (timeUnitName.equals("week")) { timeUnit = TimeUnit.WEEK; } else { continue; } ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(timeUnitName); int count = oneUnitRes.getSize(); Map<String, Object[]> countToPatterns = timeUnitToCountToPatterns.get(timeUnit); if (countToPatterns == null) { countToPatterns = new TreeMap<String, Object[]>(); timeUnitToCountToPatterns.put(timeUnit, countToPatterns); } for (int pluralIndex = 0; pluralIndex < count; ++pluralIndex) { String pluralCount = oneUnitRes.get(pluralIndex).getKey(); String pattern = oneUnitRes.get(pluralIndex).getString(); final MessageFormat messageFormat = new MessageFormat(pattern, locale); if (format != null) { messageFormat.setFormatByArgumentIndex(0, format); } // save both full name and abbreviated name in one table // is good space-wise, but it degrades performance, // since it needs to check whether the needed space // is already allocated or not. Object[] pair = countToPatterns.get(pluralCount); if (pair == null) { pair = new Object[2]; countToPatterns.put(pluralCount, pair); } pair[style] = messageFormat; } } } catch (MissingResourceException e) { } // there should be patterns for each plural rule in each time unit. // For each time unit, // for each plural rule, following is unit pattern fall-back rule: // ( for example: "one" hour ) // look for its unit pattern in its locale tree. // if pattern is not found in its own locale, such as de_DE, // look for the pattern in its parent, such as de, // keep looking till found or till root. // if the pattern is not found in root either, // fallback to plural count "other", // look for the pattern of "other" in the locale tree: // "de_DE" to "de" to "root". // If not found, fall back to value of // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". // // Following is consistency check to create pattern for each // plural rule in each time unit using above fall-back rule. // final TimeUnit[] timeUnits = TimeUnit.values(); Set<String> keywords = pluralRules.getKeywords(); for (int i = 0; i < timeUnits.length; ++i) { // for each time unit, // get all the patterns for each plural rule in this locale. final TimeUnit timeUnit = timeUnits[i]; Map<String, Object[]> countToPatterns = timeUnitToCountToPatterns.get(timeUnit); if (countToPatterns == null) { countToPatterns = new TreeMap<String, Object[]>(); timeUnitToCountToPatterns.put(timeUnit, countToPatterns); } for (String pluralCount : keywords) { if (countToPatterns.get(pluralCount) == null || countToPatterns.get(pluralCount)[style] == null) { // look through parents searchInTree(resourceKey, style, timeUnit, pluralCount, pluralCount, countToPatterns); } } } }
// srcPluralCount is the original plural count on which the pattern is // searched for. // searchPluralCount is the fallback plural count. // For example, to search for pattern for ""one" hour", // "one" is the srcPluralCount, // if the pattern is not found even in root, fallback to // using patterns of plural count "other", // then, "other" is the searchPluralCount. private void searchInTree( String resourceKey, int styl, TimeUnit timeUnit, String srcPluralCount, String searchPluralCount, Map<String, Object[]> countToPatterns) { ULocale parentLocale = locale; String srcTimeUnitName = timeUnit.toString(); while (parentLocale != null) { try { // look for pattern for srcPluralCount in locale tree ICUResourceBundle unitsRes = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, parentLocale); unitsRes = unitsRes.getWithFallback(resourceKey); ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(srcTimeUnitName); String pattern = oneUnitRes.getStringWithFallback(searchPluralCount); final MessageFormat messageFormat = new MessageFormat(pattern, locale); if (format != null) { messageFormat.setFormatByArgumentIndex(0, format); } Object[] pair = countToPatterns.get(srcPluralCount); if (pair == null) { pair = new Object[2]; countToPatterns.put(srcPluralCount, pair); } pair[styl] = messageFormat; return; } catch (MissingResourceException e) { } parentLocale = parentLocale.getFallback(); } // if no unitsShort resource was found even after fallback to root locale // then search the units resource fallback from the current level to root if (parentLocale == null && resourceKey.equals("unitsShort")) { searchInTree("units", styl, timeUnit, srcPluralCount, searchPluralCount, countToPatterns); if (countToPatterns != null && countToPatterns.get(srcPluralCount) != null && countToPatterns.get(srcPluralCount)[styl] != null) { return; } } // if not found the pattern for this plural count at all, // fall-back to plural count "other" if (searchPluralCount.equals("other")) { // set default fall back the same as the resource in root MessageFormat messageFormat = null; if (timeUnit == TimeUnit.SECOND) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, locale); } else if (timeUnit == TimeUnit.MINUTE) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, locale); } else if (timeUnit == TimeUnit.HOUR) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, locale); } else if (timeUnit == TimeUnit.WEEK) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, locale); } else if (timeUnit == TimeUnit.DAY) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, locale); } else if (timeUnit == TimeUnit.MONTH) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, locale); } else if (timeUnit == TimeUnit.YEAR) { messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, locale); } if (format != null && messageFormat != null) { messageFormat.setFormatByArgumentIndex(0, format); } Object[] pair = countToPatterns.get(srcPluralCount); if (pair == null) { pair = new Object[2]; countToPatterns.put(srcPluralCount, pair); } pair[styl] = messageFormat; } else { // fall back to rule "other", and search in parents searchInTree(resourceKey, styl, timeUnit, srcPluralCount, "other", countToPatterns); } }
/* * Initialize DateIntervalInfo from calendar data * @param calData calendar data */ private void setup(ULocale locale) { int DEFAULT_HASH_SIZE = 19; fIntervalPatterns = new HashMap<String, Map<String, PatternInfo>>(DEFAULT_HASH_SIZE); // initialize to guard if there is no interval date format defined in // resource files fFallbackIntervalPattern = "{0} \u2013 {1}"; HashSet<String> skeletonSet = new HashSet<String>(); try { // loop through all locales to get all available skeletons' // interval format ULocale currentLocale = locale; // Get the correct calendar type String calendarTypeToUse = locale.getKeywordValue("calendar"); if (calendarTypeToUse == null) { String[] preferredCalendarTypes = Calendar.getKeywordValuesForLocale("calendar", locale, true); calendarTypeToUse = preferredCalendarTypes[0]; // the most preferred calendar } if (calendarTypeToUse == null) { calendarTypeToUse = "gregorian"; // fallback } do { String name = currentLocale.getName(); if (name.length() == 0) { break; } ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, currentLocale); // Note: // ICU4J getWithFallback does not work well when // 1) A nested table is an alias to /LOCALE/... // 2) getWithFallback is called multiple times for going down hierarchical resource // path // #9987 resolved the issue of alias table when full path is specified in // getWithFallback, // but there is no easy solution when the equivalent operation is done by multiple // operations. // This issue is addressed in #9964. // ICUResourceBundle calBundle = rb.getWithFallback("calendar"); // ICUResourceBundle calTypeBundle = // calBundle.getWithFallback(calendarTypeToUse); ICUResourceBundle itvDtPtnResource = rb.getWithFallback("calendar/" + calendarTypeToUse + "/intervalFormats"); // look for fallback first, since it establishes the default order String fallback = itvDtPtnResource.getStringWithFallback(FALLBACK_STRING); setFallbackIntervalPattern(fallback); int size = itvDtPtnResource.getSize(); for (int index = 0; index < size; ++index) { String skeleton = itvDtPtnResource.get(index).getKey(); if (skeletonSet.contains(skeleton)) { continue; } skeletonSet.add(skeleton); if (skeleton.compareTo(FALLBACK_STRING) == 0) { continue; } ICUResourceBundle intervalPatterns = (ICUResourceBundle) itvDtPtnResource.get(skeleton); int ptnNum = intervalPatterns.getSize(); for (int ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex) { String key = intervalPatterns.get(ptnIndex).getKey(); String pattern = intervalPatterns.get(ptnIndex).getString(); int calendarField = -1; // initialize with an invalid value. if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR]) == 0) { calendarField = Calendar.YEAR; } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH]) == 0) { calendarField = Calendar.MONTH; } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE]) == 0) { calendarField = Calendar.DATE; } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.AM_PM]) == 0) { calendarField = Calendar.AM_PM; } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.HOUR]) == 0) { calendarField = Calendar.HOUR; } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MINUTE]) == 0) { calendarField = Calendar.MINUTE; } if (calendarField != -1) { setIntervalPatternInternally(skeleton, key, pattern); } } } try { UResourceBundle parentNameBundle = rb.get("%%Parent"); currentLocale = new ULocale(parentNameBundle.getString()); } catch (MissingResourceException e) { currentLocale = currentLocale.getFallback(); } } while (currentLocale != null && !currentLocale.getBaseName().equals("root")); } catch (MissingResourceException e) { // ok, will fallback to {data0} - {date1} } }