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