• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import com.google.common.base.Joiner;
4 import com.google.common.base.Splitter;
5 import com.ibm.icu.text.MessageFormat;
6 import com.ibm.icu.text.Transform;
7 import com.ibm.icu.util.Output;
8 import java.util.List;
9 import java.util.Locale;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
14 
15 /**
16  * Automatically construct language names (glossonyms)
17  *
18  * Example: in German (de), for the path
19  *
20  *       //ldml/localeDisplayNames/languages/language[@type="ro_MD"]
21  *
22  * the value "Rumänisch (Republik Moldau)" is automatically constructed based on the code "ro_MD".
23  *
24  * The constructed value is a default if no preferable value is submitted or inherited.
25  * A different (non-constructed) value, such as "Moldauisch", may become the winning
26  * value instead of the constructed value.
27  */
28 public class GlossonymConstructor {
29 
30     /**
31      * Some paths with this prefix can get automatically constructed values
32      */
33     public static final String PATH_PREFIX = "//ldml/localeDisplayNames/languages/language[@type=\"";
34 
35     /**
36      * The code such as "ro_MD" must contain an underscore, otherwise there is no constructed value.
37      * Underscore also serves as a clue for recognizing a value that is from code-fallback; for example,
38      * when the value "ro_MD" is inherited, the underscore implies it's a raw code ("bogus value") and should
39      * be replaced by a constructed value like "Rumänisch (Republik Moldau)"; but when the value "Moldauisch"
40      * (without underscore) is inherited, it should not be replaced by a constructed value
41      */
42     private static final String CODE_SEPARATOR = "_";
43 
44     /**
45      * For "pathWhereFound" when the value is constructed.
46      * It is non-null to satisfy TestPathHeadersAndValues.
47      * It should not be treated as an actual path; for example, the
48      * Survey Tool Info Panel should not show a broken "Jump to original" link.
49      */
50     public static final String PSEUDO_PATH = "constructed";
51 
52     /**
53      * Is the given path eligible for getting a constructed value?
54      *
55      * @param xpath the given path
56      * @return true if eligible
57      */
pathIsEligible(String xpath)58     public static boolean pathIsEligible(String xpath) {
59         return xpath.startsWith(PATH_PREFIX) && xpath.contains(CODE_SEPARATOR);
60     }
61 
62     /**
63      * Is the given value bogus, and therefore eligible for getting replaced by a constructed value?
64      *
65      * @param value the given value
66      * @return true if bogus
67      */
valueIsBogus(String value)68     public static boolean valueIsBogus(String value) {
69         return (
70             value == null ||
71             value.contains(CODE_SEPARATOR) ||
72             RegexUtilities.PATTERN_3_OR_4_DIGITS.matcher(value).find()
73         );
74     }
75 
76     private final CLDRFile cldrFile;
77 
GlossonymConstructor(CLDRFile cldrFile)78     public GlossonymConstructor(CLDRFile cldrFile) {
79         this.cldrFile = cldrFile;
80         if (!cldrFile.isResolved()) {
81             throw new IllegalArgumentException("Unresolved CLDRFile in GlossonymConstructor constructor");
82         }
83     }
84 
85     /**
86      * Get the constructed value and fill in tracking information about where it was found
87      *
88      * @param xpath the path
89      * @param pathWhereFound if not null, to be filled in
90      * @param localeWhereFound if not null, to be filled in
91      * @return the constructed value, or null
92      */
getValueAndTrack(String xpath, Output<String> pathWhereFound, Output<String> localeWhereFound)93     public String getValueAndTrack(String xpath, Output<String> pathWhereFound, Output<String> localeWhereFound) {
94         final String constructedValue = getValue(xpath);
95         if (constructedValue != null) {
96             if (localeWhereFound != null) {
97                 localeWhereFound.value = cldrFile.getLocaleID();
98             }
99             if (pathWhereFound != null) {
100                 pathWhereFound.value = PSEUDO_PATH;
101             }
102             return constructedValue;
103         }
104         return null;
105     }
106 
107     /**
108      * Get the constructed value for the given path
109      *
110      * @param xpath the given path
111      * @return the constructed value, or null
112      */
getValue(String xpath)113     public String getValue(String xpath) {
114         if (pathIsEligible(xpath)) {
115             return reallyGetValue(xpath);
116         }
117         return null;
118     }
119 
reallyGetValue(String xpath)120     private synchronized String reallyGetValue(String xpath) {
121         final XPathParts parts = XPathParts.getFrozenInstance(xpath);
122         final String type = parts.getAttributeValue(-1, "type");
123         if (type.contains(CODE_SEPARATOR)) {
124             final String alt = parts.getAttributeValue(-1, "alt");
125             final CLDRFile.SimpleAltPicker altPicker = (alt == null) ? null : new CLDRFile.SimpleAltPicker(alt);
126             final String value = cldrFile.getName(type, true, altPicker);
127             if (!valueIsBogus(value)) {
128                 return value;
129             }
130         }
131         return null;
132     }
133 }
134