blob: 24f83ff1790a9219b4a9df9c438428f73428cf92 [file] [log] [blame]
package org.unicode.cldr.util;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.unicode.cldr.test.CheckCLDR.CheckStatus.Subtype;
import org.unicode.cldr.util.RegexLookup.Merger;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.ibm.icu.text.Transform;
public class PatternPlaceholders {
public enum PlaceholderStatus {
DISALLOWED("No placeholders allowed."),//
REQUIRED("Specific number of placeholders allowed."),//
LOCALE_DEPENDENT("Some placeholders may be omitted in certain locales"),//
MULTIPLE("May have multiple instances of the same placeholder, eg “{0} cats and {0} dogs”."),//
OPTIONAL("Any specific placeholder is optional (and non-numeric); there must be at least one.")//
;
private final String message;
private PlaceholderStatus(String message) {
this.message = message;
}
@Override
public String toString() {
return name() + ": " + message;
}
}
public static final ImmutableSet<Subtype> PLACEHOLDER_SUBTYPES = ImmutableSet.of(
Subtype.gapsInPlaceholderNumbers,
Subtype.duplicatePlaceholders,
Subtype.missingPlaceholders,
Subtype.extraPlaceholders);
private static class PlaceholderData {
PlaceholderStatus status = PlaceholderStatus.REQUIRED;
Map<String, PlaceholderInfo> data = new LinkedHashMap<>();
public void add(String id, String name, String example) {
PlaceholderInfo row = new PlaceholderInfo(name, example);
data.put(id, row);
}
}
public static class PlaceholderInfo {
public String name;
public String example;
private PlaceholderInfo(String name, String example) {
this.name = name;
this.example = example;
}
@Override
public String toString() {
return "{" + name + "}, e.g. “" + example + "”";
}
}
private static final class MyMerger implements Merger<PlaceholderData> {
@Override
public PlaceholderData merge(PlaceholderData a, PlaceholderData into) {
// check unique
for (String key : a.data.keySet()) {
if (into.data.containsKey(key)) {
throw new IllegalArgumentException("Duplicate placeholder: " + key);
}
}
into.data.putAll(a.data);
if (into.status != a.status) {
throw new IllegalArgumentException("Different optional status");
}
return into;
}
}
private static final class MapTransform implements Transform<String, PlaceholderData> {
@Override
public PlaceholderData transform(String source) {
PlaceholderData result = new PlaceholderData();
try {
String[] parts = source.split("\\s*;\\s+");
for (String part : parts) {
switch (part) {
case "locale":
result.status = PlaceholderStatus.LOCALE_DEPENDENT;
continue;
case "multiple":
result.status = PlaceholderStatus.MULTIPLE;
continue;
case "optional":
result.status = PlaceholderStatus.OPTIONAL;
continue;
default:
int equalsPos = part.indexOf('=');
String id = part.substring(0, equalsPos).trim();
String name = part.substring(equalsPos + 1).trim();
int spacePos = name.indexOf(' ');
String example;
if (spacePos >= 0) {
example = name.substring(spacePos + 1).trim();
name = name.substring(0, spacePos).trim();
} else {
example = "";
}
// TODO Some normalization of personName namePattern placeholder ids.
// Hack for now, later do something maybe using PersonNameFormatter.ModifiedField
id = id.replace("-allCaps", "");
id = id.replace("-initialCap", "");
id = id.replace("-initial", "");
id = id.replace("-monogram", "");
PlaceholderInfo old = result.data.get(id);
if (old != null) {
throw new IllegalArgumentException("Key occurs twice: " + id + "=" + old + "!=" + name);
}
result.add(id, name, example);
}
}
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse " + source, e);
}
return result;
}
}
private final RegexLookup<PlaceholderData> patternPlaceholders;
private PatternPlaceholders() {
patternPlaceholders = RegexLookup.of(new MapTransform())
.setValueMerger(new MyMerger())
.loadFromFile(PatternPlaceholders.class, "data/Placeholders.txt");
}
static final private class PatternPlaceholdersHelper {
static final PatternPlaceholders SINGLETON = new PatternPlaceholders();
}
public static PatternPlaceholders getInstance() {
return PatternPlaceholdersHelper.SINGLETON;
}
public Map<String, PlaceholderInfo> get(String path) {
// TODO change the original map to be unmodifiable, to avoid this step. Need to add a "finalize" to the lookup.
final PlaceholderData map = patternPlaceholders.get(path);
return map == null ? ImmutableMap.of() : Collections.unmodifiableMap(map.data);
}
public PlaceholderStatus getStatus(String path) {
// TODO change the original map to be unmodifiable, to avoid this step. Need to add a "finalize" to the lookup.
final PlaceholderData map = patternPlaceholders.get(path);
return map == null ? PlaceholderStatus.DISALLOWED : map.status;
}
}