• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.icu;
2 
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 
9 import org.unicode.cldr.util.SupplementalDataInfo.PluralType;
10 import org.xml.sax.Attributes;
11 import org.xml.sax.SAXException;
12 
13 import com.ibm.icu.impl.Row.R2;
14 
15 /**
16  * Class for converting CLDR plurals files to a format suitable for outputting
17  * ICU data with. It might be possible for PluralsMapper and LdmlLocaleMapper to
18  * share a parent class, but there isn't currently a need for that so they're
19  * kept separate for the time being.
20  *
21  * @author jchye
22  */
23 public class PluralsMapper {
24     private int numRuleSets = 0;
25     private String supplementalDir;
26     private Map<String, Integer> ruleOrder;
27 
28     /**
29      * Constructor. A SupplementalDataInfo object is used rather than the
30      * supplemental directory because the supplemental data parsing is already
31      * done for us. The RegexLookup method used by LdmlLocaleMapper wouldn't
32      * work well, since there would only be one regex.
33      *
34      * @param supplementalDataInfo
35      */
PluralsMapper(String supplementalDir)36     public PluralsMapper(String supplementalDir) {
37         this.supplementalDir = supplementalDir;
38         ruleOrder = new HashMap<String, Integer>();
39     }
40 
41     /**
42      * @return CLDR data converted to an ICU-friendly format
43      */
fillFromCldr()44     public IcuData fillFromCldr() {
45         IcuData icuData = new IcuData("plurals.xml, ordinals.xml", "plurals", false);
46         fillType(PluralType.cardinal, icuData);
47         fillType(PluralType.ordinal, icuData);
48         return icuData;
49     }
50 
fillType(PluralType type, IcuData icuData)51     private void fillType(PluralType type, IcuData icuData) {
52         PluralsHandler handler = new PluralsHandler(type, icuData);
53         String filename = type == PluralType.cardinal ? "plurals.xml" : "ordinals.xml";
54         File inputFile = new File(supplementalDir, filename); // handle ordinals too.
55         MapperUtils.parseFile(inputFile, handler);
56     }
57 
58     private class PluralsHandler extends MapperUtils.EmptyHandler {
59         private StringBuffer currentText;
60         private String currentCount;
61         private String[] currentLocales;
62         // List of plural counts and corresponding rules.
63         private List<R2<String, String>> currentRules;
64         private IcuData icuData;
65         String prefix;
66 
PluralsHandler(PluralType type, IcuData icuData)67         public PluralsHandler(PluralType type, IcuData icuData) {
68             this.icuData = icuData;
69             prefix = type == PluralType.cardinal ? "/locales/" : "/locales_ordinals/";
70             currentText = new StringBuffer();
71             currentRules = new ArrayList<R2<String, String>>();
72         }
73 
74         @Override
characters(char[] ch, int start, int length)75         public void characters(char[] ch, int start, int length) throws SAXException {
76             currentText.append(ch, start, length);
77         }
78 
79         @Override
startElement(String uri, String localName, String qName, Attributes attr)80         public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException {
81             if (qName.equals("pluralRules")) {
82                 currentLocales = attr.getValue("locales").split("\\s+");
83             } else if (qName.equals("pluralRule")) {
84                 currentCount = attr.getValue("count");
85             }
86         }
87 
88         @Override
endElement(String uri, String localName, String qName)89         public void endElement(String uri, String localName, String qName) throws SAXException {
90             if (qName.equals("pluralRules")) {
91                 // add locale path to ICU data
92                 StringBuffer ruleBuffer = new StringBuffer();
93                 for (R2<String, String> rule : currentRules) {
94                     ruleBuffer.append(rule.toString() + '\n');
95                 }
96                 Integer setNum = ruleOrder.get(ruleBuffer.toString());
97                 // Only add the rules to the ICU file if they aren't a duplicate
98                 // of an earlier rule set.
99                 if (setNum == null) {
100                     setNum = numRuleSets;
101                     ruleOrder.put(ruleBuffer.toString(), setNum);
102                     for (R2<String, String> rule : currentRules) {
103                         icuData.add("/rules/set" + numRuleSets + '/' + rule.get0(), rule.get1());
104                     }
105                     numRuleSets++;
106                 }
107                 String setName = currentRules.size() == 0 ? "" : "set" + setNum;
108                 for (String locale : currentLocales) {
109                     icuData.add(prefix + locale, setName);
110                 }
111                 currentRules.clear();
112             } else if (qName.equals("pluralRule")) {
113                 currentRules.add(new R2<String, String>(currentCount,
114                     currentText.toString()));
115                 currentText.setLength(0);
116             }
117         }
118     }
119 }
120