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