• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.Collections;
4 import java.util.LinkedHashMap;
5 import java.util.Map;
6 import java.util.Map.Entry;
7 
8 import org.unicode.cldr.test.CheckCLDR.CheckStatus.Subtype;
9 import org.unicode.cldr.tool.GenerateXMB;
10 import org.unicode.cldr.util.RegexLookup.Merger;
11 
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.ImmutableSet;
14 import com.ibm.icu.text.Transform;
15 
16 public class PatternPlaceholders {
17 
18     public enum PlaceholderStatus {
19         DISALLOWED("No placeholders allowed."),//
20         REQUIRED("Specific number of placeholders allowed."),//
21         LOCALE_DEPENDENT("Some placeholders may be omitted in certain locales"),//
22         MULTIPLE("May have multiple instances of the same placeholder, eg “{0} cats and {0} dogs”.")//
23         ;
24 
25         private final String message;
26 
PlaceholderStatus(String message)27         private PlaceholderStatus(String message) {
28             this.message = message;
29         }
30         @Override
toString()31         public String toString() {
32             return name() + ": " + message;
33         }
34     }
35 
36     public static final ImmutableSet<Subtype> PLACEHOLDER_SUBTYPES = ImmutableSet.of(
37         Subtype.gapsInPlaceholderNumbers,
38         Subtype.duplicatePlaceholders,
39         Subtype.missingPlaceholders,
40         Subtype.extraPlaceholders);
41 
42     private static class PlaceholderData {
43         PlaceholderStatus status = PlaceholderStatus.REQUIRED;
44         Map<String, PlaceholderInfo> data = new LinkedHashMap<>();
45 
add(String id, String name, String example)46         public void add(String id, String name, String example) {
47             PlaceholderInfo row = new PlaceholderInfo(name, example);
48             data.put(id, row);
49         }
50     }
51 
52     public static class PlaceholderInfo {
53         public String name;
54         public String example;
55 
PlaceholderInfo(String name, String example)56         private PlaceholderInfo(String name, String example) {
57             this.name = name;
58             this.example = example;
59         }
60 
61         @Override
toString()62         public String toString() {
63             return "{" + name + "}, e.g. “" + example + "”";
64         }
65     }
66 
67     private static final class MyMerger implements Merger<PlaceholderData> {
68         @Override
merge(PlaceholderData a, PlaceholderData into)69         public PlaceholderData merge(PlaceholderData a, PlaceholderData into) {
70             // check unique
71             for (String key : a.data.keySet()) {
72                 if (into.data.containsKey(key)) {
73                     throw new IllegalArgumentException("Duplicate placeholder: " + key);
74                 }
75             }
76             into.data.putAll(a.data);
77             if (into.status != a.status) {
78                 throw new IllegalArgumentException("Different optional status");
79             }
80             return into;
81         }
82     }
83 
84     private static final class MapTransform implements Transform<String, PlaceholderData> {
85 
86         @Override
transform(String source)87         public PlaceholderData transform(String source) {
88             PlaceholderData result = new PlaceholderData();
89             try {
90                 String[] parts = source.split("\\s*;\\s+");
91                 for (String part : parts) {
92                     switch (part) {
93                     case "locale":
94                         result.status = PlaceholderStatus.LOCALE_DEPENDENT;
95                         continue;
96                     case "multiple":
97                         result.status = PlaceholderStatus.MULTIPLE;
98                         continue;
99                     default:
100                         int equalsPos = part.indexOf('=');
101                         String id = part.substring(0, equalsPos).trim();
102                         String name = part.substring(equalsPos + 1).trim();
103                         int spacePos = name.indexOf(' ');
104                         String example;
105                         if (spacePos >= 0) {
106                             example = name.substring(spacePos + 1).trim();
107                             name = name.substring(0, spacePos).trim();
108                         } else {
109                             example = "";
110                         }
111 
112                         PlaceholderInfo old = result.data.get(id);
113                         if (old != null) {
114                             throw new IllegalArgumentException("Key occurs twice: " + id + "=" + old + "!=" + name);
115                         }
116                         result.add(id, name, example);
117                     }
118                 }
119             } catch (Exception e) {
120                 throw new IllegalArgumentException("Failed to parse " + source, e);
121             }
122             for (Entry<String, PlaceholderInfo> entry : result.data.entrySet()) {
123                 if (GenerateXMB.DEBUG) System.out.println(entry);
124             }
125             return result;
126         }
127 
128     }
129 
130     private RegexLookup<PlaceholderData> patternPlaceholders;
131 
132     private static PatternPlaceholders SINGLETON;
133 
PatternPlaceholders()134     private PatternPlaceholders() {
135     }
136 
getInstance()137     public static PatternPlaceholders getInstance() {
138         if (SINGLETON == null) {
139             SINGLETON = new PatternPlaceholders();
140             SINGLETON.patternPlaceholders = RegexLookup.of(new MapTransform())
141                 .setValueMerger(new MyMerger())
142                 .loadFromFile(PatternPlaceholders.class, "data/Placeholders.txt");
143         }
144         return SINGLETON;
145     }
146 
get(String path)147     public Map<String, PlaceholderInfo> get(String path) {
148         // TODO change the original map to be unmodifiable, to avoid this step. Need to add a "finalize" to the lookup.
149         final PlaceholderData map = patternPlaceholders.get(path);
150         return map == null ? ImmutableMap.of() : Collections.unmodifiableMap(map.data);
151     }
152 
getStatus(String path)153     public PlaceholderStatus getStatus(String path) {
154         // TODO change the original map to be unmodifiable, to avoid this step. Need to add a "finalize" to the lookup.
155         final PlaceholderData map = patternPlaceholders.get(path);
156         return map == null ? PlaceholderStatus.DISALLOWED : map.status;
157     }
158 }