• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2019 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 package org.unicode.icu.tool.cldrtoicu.mapper;
4 
5 import static org.unicode.cldr.api.AttributeKey.keyOf;
6 import static org.unicode.cldr.api.CldrData.PathOrder.NESTED_GROUPING;
7 import static org.unicode.cldr.api.CldrDataType.SUPPLEMENTAL;
8 
9 import org.unicode.cldr.api.AttributeKey;
10 import org.unicode.cldr.api.CldrData;
11 import org.unicode.cldr.api.CldrDataSupplier;
12 import org.unicode.cldr.api.CldrDataType;
13 import org.unicode.cldr.api.CldrPath;
14 import org.unicode.cldr.api.CldrValue;
15 import org.unicode.icu.tool.cldrtoicu.IcuData;
16 import org.unicode.icu.tool.cldrtoicu.RbPath;
17 import org.unicode.icu.tool.cldrtoicu.RbValue;
18 import org.unicode.icu.tool.cldrtoicu.CldrDataProcessor;
19 
20 import com.google.common.annotations.VisibleForTesting;
21 
22 /**
23  * A mapper to collect plural data from {@link CldrDataType#SUPPLEMENTAL SUPPLEMENTAL} data via
24  * the paths:
25  * <pre>{@code
26  *   //supplementalData/plurals/pluralRanges[@locales=*]/...
27  * }</pre>
28  */
29 public final class PluralRangesMapper {
30 
31     private static final CldrDataProcessor<PluralRangesMapper> CLDR_PROCESSOR;
32     static {
33         CldrDataProcessor.Builder<PluralRangesMapper> processor = CldrDataProcessor.builder();
34         processor
35             .addAction(
36                 "//supplementalData/plurals/pluralRanges[@locales=*]", (m, p) -> m.new Ranges(p))
37             .addValueAction("pluralRange[@start=*][@end=*]", Ranges::visitRange);
38         CLDR_PROCESSOR = processor.build();
39     }
40 
41     private static final AttributeKey RANGES_LOCALES = keyOf("pluralRanges", "locales");
42     private static final AttributeKey RANGE_START = keyOf("pluralRange", "start");
43     private static final AttributeKey RANGE_END = keyOf("pluralRange", "end");
44     private static final AttributeKey RANGE_RESULT = keyOf("pluralRange", "result");
45 
46     private static final RbPath RB_RULES = RbPath.of("rules");
47     private static final RbPath RB_LOCALES = RbPath.of("locales");
48 
49     /**
50      * Processes data from the given supplier to generate plural-range ICU data.
51      *
52      * @param src the CLDR data supplier to process.
53      * @return the IcuData instance to be written to a file.
54      */
process(CldrDataSupplier src)55     public static IcuData process(CldrDataSupplier src) {
56         return process(src.getDataForType(SUPPLEMENTAL));
57     }
58 
59     @VisibleForTesting // It's easier to supply a fake data instance than a fake supplier.
process(CldrData data)60     static IcuData process(CldrData data) {
61         return CLDR_PROCESSOR.process(data, new PluralRangesMapper(), NESTED_GROUPING).icuData;
62     }
63 
64     private final IcuData icuData = new IcuData("pluralRanges", false);
65     private int setIndex = 0;
66 
PluralRangesMapper()67     private PluralRangesMapper() { }
68 
69     private final class Ranges {
70         private final String label;
71 
Ranges(CldrPath prefix)72         Ranges(CldrPath prefix) {
73             this.label = String.format("set%02d", setIndex++);
74             RANGES_LOCALES.listOfValuesFrom(prefix)
75                 .forEach(l -> icuData.add(RB_LOCALES.extendBy(l), label));
76         }
77 
visitRange(CldrValue value)78         private void visitRange(CldrValue value) {
79             // Note: "range:start" and "range:end" are optional attributes, but the CLDR DTD
80             // specifies a default via comments. They should probably be changed to just have a
81             // default in the DTD (and possibly converted to use an enum here).
82             icuData.add(RB_RULES.extendBy(label),
83                 RbValue.of(
84                     RANGE_START.valueFrom(value, "all"),
85                     RANGE_END.valueFrom(value, "all"),
86                     RANGE_RESULT.valueFrom(value)));
87         }
88     }
89 }