1 package org.unicode.cldr.tool; 2 3 import com.google.common.base.Joiner; 4 import com.google.common.base.Splitter; 5 import com.google.common.collect.BiMap; 6 import com.google.common.collect.HashBiMap; 7 import com.google.common.collect.HashMultiset; 8 import com.google.common.collect.Multimap; 9 import com.google.common.collect.Multiset; 10 import java.io.IOException; 11 import java.util.Collection; 12 import java.util.Map; 13 import java.util.Map.Entry; 14 import java.util.Set; 15 import java.util.TreeSet; 16 import org.unicode.cldr.util.CldrUtility; 17 import org.unicode.cldr.util.Pair; 18 import org.unicode.cldr.util.Rational.FormatStyle; 19 import org.unicode.cldr.util.UnitConverter; 20 import org.unicode.cldr.util.UnitPreferences; 21 import org.unicode.cldr.util.UnitPreferences.UnitPreference; 22 23 public class ChartUnitPreferences extends Chart { 24 main(String[] args)25 public static void main(String[] args) { 26 new ChartUnitPreferences().writeChart(null); 27 } 28 29 @Override getDirectory()30 public String getDirectory() { 31 return FormattedFileWriter.CHART_TARGET_DIR; 32 } 33 34 @Override getTitle()35 public String getTitle() { 36 return "Unit Preferences"; 37 } 38 39 @Override getExplanation()40 public String getExplanation() { 41 return "<p>Unit Preferences provide a way to get the units that are appropriate for a region, and usage, and threshold amounts. " 42 + "The <a href='unit_conversions.html' target='unit_conversions'>Unit Conversions</a> are used to handle conversion of units needed to use the preferences." 43 + "This release adds additional structure for usage and threshold amount, allowing for more additions of regions, usages, thresholds, and units in future releases.</p>" 44 + "<ul>" 45 + "<li>The Base Unit shows the unit whose amount is to be compared to the ‘If ≥’ amount of the Result Unit." 46 + "<li>The unit identifiers are internal, and would be localized for display to users. See <a href='https://www.unicode.org/cldr/charts/latest/by_type/units.area.html#hectare' target='units.area.hectare'>Hectare</a>, for example." 47 + "<li>The Usage shows the type of usage; <i>default</i> is used as a fallback no more specific match is found." 48 + "<li>The Sample region represents a set of regions if it has a superscript. See the table at the bottom. 001 (World) is the default if no more specific region is found.</li>" 49 + "<li>The ‘If ≥’ column shows the thresholds: the first line for a given region where the input amount is greater or equal applies. " 50 + "For example, for 0.5km as input for [area, default, 001] would result in <i>hectare</i>.</li>" 51 + "<li>" 52 + ChartUnitConversions.RATIONAL_MSG 53 + "</li>\n" 54 + "<li>" 55 + ChartUnitConversions.QUANTITY_MSG 56 + "</li>" 57 + "<li>" 58 + ChartUnitConversions.SPEC_GENERAL_MSG 59 + ", and how to fall back if a given usage or region is not found.</li>\n" 60 + "</ul>" 61 + dataScrapeMessage( 62 "/tr35-general.html#Contents", 63 "common/testData/units/unitPreferencesTest.txt", 64 "common/supplemental/units.xml"); 65 } 66 67 @Override writeContents(FormattedFileWriter pw)68 public void writeContents(FormattedFileWriter pw) throws IOException { 69 // # Quantity; Usage; Region; Input (r); Input (d); Input Unit; Output (r); Output 70 // (d); Output Unit 71 72 TablePrinter tablePrinter = 73 new TablePrinter() 74 .addColumn( 75 "Base Unit", 76 "class='source'", 77 CldrUtility.getDoubleLinkMsg(), 78 "class='source'", 79 true) 80 .setBreakSpans(true) 81 .setRepeatHeader(true) 82 .addColumn( 83 "Usage", 84 "class='source'", 85 CldrUtility.getDoubleLinkMsg(), 86 "class='source'", 87 true) 88 .addColumn("Sample Region", "class='source'", null, "class='source'", true) 89 .addColumn("If ≥", "class='source'", null, "class='source'", true) 90 .setCellAttributes("class='target' style='text-align:right'") 91 .addColumn("Result Unit", "class='target'", null, "class='target'", true) 92 .addColumn("Skeleton", "class='target'", null, "class='target'", true) 93 .addColumn("Quantity", "class='target'", null, "class='target'", true); 94 95 UnitConverter converter = SDI.getUnitConverter(); 96 UnitPreferences prefs = SDI.getUnitPreferences(); 97 Samples samples = new Samples(); 98 99 for (Entry<String, Map<String, Multimap<Set<String>, UnitPreference>>> entry : 100 prefs.getData().entrySet()) { 101 String quantity = entry.getKey(); 102 String baseUnit = converter.getBaseUnitFromQuantity(quantity); 103 for (Entry<String, Multimap<Set<String>, UnitPreference>> entry2 : 104 entry.getValue().entrySet()) { 105 String usage = entry2.getKey(); 106 for (Entry<Set<String>, Collection<UnitPreference>> entry3 : 107 entry2.getValue().asMap().entrySet()) { 108 109 Set<String> regions = entry3.getKey(); 110 Pair<String, Integer> sampleRegion = samples.getSample(regions); 111 final String sampleRegionStr = sampleDisplay(sampleRegion); 112 113 for (UnitPreference pref : entry3.getValue()) { 114 tablePrinter 115 .addRow() 116 .addCell(baseUnit) 117 .addCell(usage) 118 .addCell(sampleRegionStr) 119 .addCell(pref.geq.toString(FormatStyle.html)) 120 .addCell( 121 Joiner.on(" & ") 122 .join(Splitter.on("-and-").split(pref.unit))) 123 .addCell(pref.skeleton) 124 .addCell(quantity) 125 .finishRow(); 126 } 127 } 128 } 129 } 130 pw.write(tablePrinter.toTable()); 131 pw.write("<br><h1>Region Sets</h1>\n"); 132 TablePrinter tablePrinter2 = 133 new TablePrinter() 134 .addColumn( 135 "Sample Region", 136 "class='source'", 137 CldrUtility.getDoubleLinkMsg(), 138 "class='source'", 139 true) 140 .addColumn( 141 "Region Set", 142 "class='target'", 143 CldrUtility.getDoubleLinkMsg(), 144 "class='source'", 145 true); 146 147 TreeSet<Pair<String, Integer>> sorted = new TreeSet<>(samples.setToSample.values()); 148 for (Pair<String, Integer> pair : sorted) { 149 tablePrinter2 150 .addRow() 151 .addCell(sampleDisplay(pair)) 152 .addCell(Joiner.on(", ").join(samples.setToSample.inverse().get(pair))) 153 .finishRow(); 154 } 155 pw.write(tablePrinter2.toTable()); 156 } 157 sampleDisplay(Pair<String, Integer> sampleRegion)158 private String sampleDisplay(Pair<String, Integer> sampleRegion) { 159 return sampleRegion.getFirst() 160 + (sampleRegion.getSecond() < 0 161 ? "" 162 : "<sup>" + sampleRegion.getSecond() + "</sup>"); 163 } 164 165 private static final class Samples { 166 BiMap<Set<String>, Pair<String, Integer>> setToSample = HashBiMap.create(); 167 Multiset<String> counters = HashMultiset.create(); 168 getSample(Set<String> regions)169 private Pair<String, Integer> getSample(Set<String> regions) { 170 if (regions.size() == 1) { 171 return new Pair<>(regions.iterator().next(), -1); 172 } 173 Pair<String, Integer> sample = setToSample.get(regions); 174 if (sample == null) { 175 String sampleBase = regions.iterator().next() + ", …"; 176 counters.add(sampleBase); 177 setToSample.put( 178 regions, sample = new Pair<>(sampleBase, counters.count(sampleBase))); 179 } 180 return sample; 181 } 182 } 183 } 184