31 import java.util.HashMap; |
31 import java.util.HashMap; |
32 import java.util.Iterator; |
32 import java.util.Iterator; |
33 import java.util.List; |
33 import java.util.List; |
34 import java.util.Map; |
34 import java.util.Map; |
35 import java.util.Objects; |
35 import java.util.Objects; |
|
36 import java.util.Optional; |
36 |
37 |
37 class Bundle { |
38 class Bundle { |
38 static enum Type { |
39 static enum Type { |
39 LOCALENAMES, CURRENCYNAMES, TIMEZONENAMES, CALENDARDATA, FORMATDATA; |
40 LOCALENAMES, CURRENCYNAMES, TIMEZONENAMES, CALENDARDATA, FORMATDATA; |
40 |
41 |
48 private final static Map<String, Bundle> bundles = new HashMap<>(); |
49 private final static Map<String, Bundle> bundles = new HashMap<>(); |
49 |
50 |
50 private final static String[] NUMBER_PATTERN_KEYS = { |
51 private final static String[] NUMBER_PATTERN_KEYS = { |
51 "NumberPatterns/decimal", |
52 "NumberPatterns/decimal", |
52 "NumberPatterns/currency", |
53 "NumberPatterns/currency", |
53 "NumberPatterns/percent" |
54 "NumberPatterns/percent", |
|
55 "NumberPatterns/accounting" |
54 }; |
56 }; |
55 |
57 |
56 private final static String[] COMPACT_NUMBER_PATTERN_KEYS = { |
58 private final static String[] COMPACT_NUMBER_PATTERN_KEYS = { |
57 "short.CompactNumberPatterns", |
59 "short.CompactNumberPatterns", |
58 "long.CompactNumberPatterns"}; |
60 "long.CompactNumberPatterns"}; |
210 parentsMap.putAll(myMap); |
212 parentsMap.putAll(myMap); |
211 } |
213 } |
212 |
214 |
213 // merge individual strings into arrays |
215 // merge individual strings into arrays |
214 |
216 |
215 // if myMap has any of the NumberPatterns members |
217 // if myMap has any of the NumberPatterns/NumberElements members, create a |
216 for (String k : NUMBER_PATTERN_KEYS) { |
218 // complete array of patterns/elements. |
217 if (myMap.containsKey(k)) { |
219 @SuppressWarnings("unchecked") |
218 String[] numberPatterns = new String[NUMBER_PATTERN_KEYS.length]; |
220 List<String> scripts = (List<String>) myMap.get("numberingScripts"); |
219 for (int i = 0; i < NUMBER_PATTERN_KEYS.length; i++) { |
221 if (scripts != null) { |
220 String key = NUMBER_PATTERN_KEYS[i]; |
222 for (String script : scripts) { |
221 String value = (String) myMap.remove(key); |
223 myMap.put(script + ".NumberPatterns", |
222 if (value == null) { |
224 createNumberArray(myMap, parentsMap, NUMBER_PATTERN_KEYS, script)); |
223 value = (String) parentsMap.remove(key); |
225 myMap.put(script + ".NumberElements", |
224 } |
226 createNumberArray(myMap, parentsMap, NUMBER_ELEMENT_KEYS, script)); |
225 if (value.length() == 0) { |
|
226 CLDRConverter.warning("empty pattern for " + key); |
|
227 } |
|
228 numberPatterns[i] = value; |
|
229 } |
|
230 myMap.put("NumberPatterns", numberPatterns); |
|
231 break; |
|
232 } |
227 } |
233 } |
228 } |
234 |
229 |
235 for (String k : COMPACT_NUMBER_PATTERN_KEYS) { |
230 for (String k : COMPACT_NUMBER_PATTERN_KEYS) { |
236 List<String> patterns = (List<String>) myMap.remove(k); |
231 List<String> patterns = (List<String>) myMap.remove(k); |
237 if (patterns != null) { |
232 if (patterns != null) { |
238 // Replace any null entry with empty strings. |
233 // Replace any null entry with empty strings. |
239 String[] arrPatterns = patterns.stream() |
234 String[] arrPatterns = patterns.stream() |
240 .map(s -> s == null ? "" : s).toArray(String[]::new); |
235 .map(s -> s == null ? "" : s).toArray(String[]::new); |
241 myMap.put(k, arrPatterns); |
236 myMap.put(k, arrPatterns); |
242 } |
|
243 } |
|
244 |
|
245 // if myMap has any of NUMBER_ELEMENT_KEYS, create a complete NumberElements. |
|
246 String defaultScript = (String) myMap.get("DefaultNumberingSystem"); |
|
247 @SuppressWarnings("unchecked") |
|
248 List<String> scripts = (List<String>) myMap.get("numberingScripts"); |
|
249 if (scripts != null) { |
|
250 for (String script : scripts) { |
|
251 for (String k : NUMBER_ELEMENT_KEYS) { |
|
252 String[] numberElements = new String[NUMBER_ELEMENT_KEYS.length]; |
|
253 for (int i = 0; i < NUMBER_ELEMENT_KEYS.length; i++) { |
|
254 String key = script + "." + NUMBER_ELEMENT_KEYS[i]; |
|
255 String value = (String) myMap.remove(key); |
|
256 if (value == null) { |
|
257 if (key.endsWith("/pattern")) { |
|
258 value = "#"; |
|
259 } else { |
|
260 value = (String) parentsMap.get(key); |
|
261 if (value == null) { |
|
262 // the last resort is "latn" |
|
263 key = "latn." + NUMBER_ELEMENT_KEYS[i]; |
|
264 value = (String) parentsMap.get(key); |
|
265 if (value == null) { |
|
266 throw new InternalError("NumberElements: null for " + key); |
|
267 } |
|
268 } |
|
269 } |
|
270 } |
|
271 numberElements[i] = value; |
|
272 } |
|
273 myMap.put(script + "." + "NumberElements", numberElements); |
|
274 break; |
|
275 } |
|
276 } |
237 } |
277 } |
238 } |
278 |
239 |
279 // another hack: parentsMap is not used for date-time resources. |
240 // another hack: parentsMap is not used for date-time resources. |
280 if ("root".equals(id)) { |
241 if ("root".equals(id)) { |
791 |
752 |
792 @FunctionalInterface |
753 @FunctionalInterface |
793 private interface ConvertDateTimeLetters { |
754 private interface ConvertDateTimeLetters { |
794 void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb); |
755 void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb); |
795 } |
756 } |
|
757 |
|
758 /** |
|
759 * Returns a complete string array for NumberElements or NumberPatterns. If any |
|
760 * array element is missing, it will fall back to parents map, as well as |
|
761 * numbering script fallback. |
|
762 */ |
|
763 private String[] createNumberArray(Map<String, Object> myMap, Map<String, Object>parentsMap, |
|
764 String[] keys, String script) { |
|
765 String[] numArray = new String[keys.length]; |
|
766 for (int i = 0; i < keys.length; i++) { |
|
767 String key = script + "." + keys[i]; |
|
768 final int idx = i; |
|
769 Optional.ofNullable( |
|
770 myMap.getOrDefault(key, |
|
771 // if value not found in myMap, search for parentsMap |
|
772 parentsMap.getOrDefault(key, |
|
773 parentsMap.getOrDefault(keys[i], |
|
774 // the last resort is "latn" |
|
775 parentsMap.get("latn." + keys[i]))))) |
|
776 .ifPresentOrElse(v -> numArray[idx] = (String)v, () -> { |
|
777 if (keys == NUMBER_PATTERN_KEYS) { |
|
778 // NumberPatterns |
|
779 if (!key.endsWith("accounting")) { |
|
780 // throw error unless it is for "accounting", |
|
781 // which may be missing. |
|
782 throw new InternalError("NumberPatterns: null for " + |
|
783 key + ", id: " + id); |
|
784 } |
|
785 } else { |
|
786 // NumberElements |
|
787 assert keys == NUMBER_ELEMENT_KEYS; |
|
788 if (key.endsWith("/pattern")) { |
|
789 numArray[idx] = "#"; |
|
790 } else { |
|
791 throw new InternalError("NumberElements: null for " + |
|
792 key + ", id: " + id); |
|
793 } |
|
794 }}); |
|
795 } |
|
796 return numArray; |
|
797 } |
796 } |
798 } |