1 package org.unicode.cldr.test; 2 3 import java.util.List; 4 5 import org.unicode.cldr.test.CheckCLDR.CheckStatus.Subtype; 6 import org.unicode.cldr.util.CLDRFile; 7 import org.unicode.cldr.util.XPathParts; 8 9 import com.ibm.icu.lang.UCharacter; 10 import com.ibm.icu.text.BreakIterator; 11 import com.ibm.icu.util.ULocale; 12 13 public class CheckCasing extends CheckCLDR { 14 public enum Case { 15 mixed, lowercase_words, titlecase_words, titlecase_firstword, verbatim; forString(String input)16 public static Case forString(String input) { 17 return valueOf(input.replace('-', '_')); 18 } 19 } 20 21 // remember to add this class to the list in CheckCLDR.getCheckAll 22 // to run just this test, on just locales starting with 'nl', use CheckCLDR with -fnl.* -t.*Currencies.* 23 24 ULocale uLocale = null; 25 BreakIterator breaker = null; 26 27 @Override setCldrFileToCheck(CLDRFile cldrFileToCheck, Options options, List<CheckStatus> possibleErrors)28 public CheckCLDR setCldrFileToCheck(CLDRFile cldrFileToCheck, Options options, 29 List<CheckStatus> possibleErrors) { 30 if (cldrFileToCheck == null) return this; 31 super.setCldrFileToCheck(cldrFileToCheck, options, possibleErrors); 32 uLocale = new ULocale(cldrFileToCheck.getLocaleID()); 33 breaker = BreakIterator.getWordInstance(uLocale); 34 return this; 35 } 36 37 // If you don't need any file initialization or postprocessing, you only need this one routine 38 @Override handleCheck(String path, String fullPath, String value, Options options, List<CheckStatus> result)39 public CheckCLDR handleCheck(String path, String fullPath, String value, Options options, 40 List<CheckStatus> result) { 41 // it helps performance to have a quick reject of most paths 42 if (fullPath == null) return this; // skip paths that we don't have 43 if (fullPath.indexOf("casing") < 0) return this; 44 45 // pick up the casing attributes from the full path 46 XPathParts parts = XPathParts.getFrozenInstance(fullPath); 47 48 Case caseTest = Case.mixed; 49 for (int i = 0; i < parts.size(); ++i) { 50 String casingValue = parts.getAttributeValue(i, "casing"); 51 if (casingValue == null) { 52 continue; 53 } 54 caseTest = Case.forString(casingValue); 55 if (caseTest == Case.verbatim) { 56 return this; // we're done 57 } 58 } 59 60 String newValue = value; 61 switch (caseTest) { 62 case lowercase_words: 63 newValue = UCharacter.toLowerCase(uLocale, value); 64 break; 65 case titlecase_words: 66 newValue = UCharacter.toTitleCase(uLocale, value, null); 67 break; 68 case titlecase_firstword: 69 newValue = TitleCaseFirst(uLocale, value); 70 break; 71 default: 72 break; 73 74 } 75 if (!newValue.equals(value)) { 76 // the following is how you signal an error or warning (or add a demo....) 77 result.add(new CheckStatus().setCause(this) 78 .setMainType(CheckStatus.errorType) 79 .setSubtype(Subtype.incorrectCasing) 80 // typically warningType or errorType 81 .setMessage("Casing incorrect: either should have casing=\"verbatim\" or be <{0}>", 82 new Object[] { newValue })); // the message; can be MessageFormat with arguments 83 } 84 return this; 85 } 86 87 // -f(bg|cs|da|el|et|is|it|lt|ro|ru|sl|uk) -t(.*casing.*) 88 TitleCaseFirst(ULocale locale, String value)89 private String TitleCaseFirst(ULocale locale, String value) { 90 if (value.length() == 0) { 91 return value; 92 } 93 breaker.setText(value); 94 breaker.first(); 95 int endOfFirstWord = breaker.next(); 96 return UCharacter.toTitleCase(uLocale, value.substring(0, endOfFirstWord), breaker) 97 + value.substring(endOfFirstWord); 98 } 99 100 }