xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/tool/ChartUnitConversions.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
1 package org.unicode.cldr.tool;
2 
3 import com.google.common.base.Joiner;
4 import com.ibm.icu.impl.Row;
5 import com.ibm.icu.impl.Row.R4;
6 import java.io.IOException;
7 import java.io.PrintWriter;
8 import java.util.EnumSet;
9 import java.util.Map.Entry;
10 import java.util.Set;
11 import java.util.TreeSet;
12 import org.unicode.cldr.util.CldrUtility;
13 import org.unicode.cldr.util.Rational;
14 import org.unicode.cldr.util.Rational.FormatStyle;
15 import org.unicode.cldr.util.UnitConverter;
16 import org.unicode.cldr.util.UnitConverter.TargetInfo;
17 import org.unicode.cldr.util.UnitConverter.UnitId;
18 import org.unicode.cldr.util.UnitConverter.UnitSystem;
19 
20 public class ChartUnitConversions extends Chart {
21 
22     public static final String QUANTITY_MSG =
23             "The units are grouped and ordered by Quantity (which are based on the NIST quantities, see "
24                     + "<a href='https://www.nist.gov/pml/special-publication-811' target='nist811'>NIST 811</a>). Note that the quantities are informative.";
25     public static final String RATIONAL_MSG =
26             "Each numeric value is an exact rational. (Radians are an exception since the value of π is irrational; a rational approximation is used.)"
27                     + "The format is a terminating decimal where possible; "
28                     + "otherwise a repeating decimal if possible (where ˙ marks the start of the <a href='https://en.wikipedia.org/wiki/Repeating_decimal' target='wiki'>reptend</a>); "
29                     + "otherwise a <a href='https://en.wikipedia.org/wiki/Rational_number' target='wiki'>rational number</a> (of the form <i>numerator/denominator</i>)."
30                     + "";
31     public static final String SPEC_GENERAL_MSG =
32             "The "
33                     + ldmlSpecLink("/tr35-general.html#Contents")
34                     + " should be consulted for more details, such as how to handle complex units (such as foot-per-minute) by converting the elements";
35 
main(String[] args)36     public static void main(String[] args) {
37         new ChartUnitConversions().writeChart(null);
38     }
39 
40     @Override
getDirectory()41     public String getDirectory() {
42         return FormattedFileWriter.CHART_TARGET_DIR;
43     }
44 
45     @Override
getTitle()46     public String getTitle() {
47         return "Unit Conversions";
48     }
49 
50     @Override
getExplanation()51     public String getExplanation() {
52         return "<p>Unit Conversions provide conversions for units, such as meter ⟹ foot, "
53                 + "so that a source units can be converted into what is needed for localized "
54                 + "<a href='unit_preferences.html' target='unit_preferences'>Unit Preferences</a>. "
55                 + "There are many possible units, and additional units and conversions will be added in future releases.</p>"
56                 + "<ul>"
57                 + "<li>Each Source Unit is converted to the Target Unit by multiplying it by the Factor and adding the Offset (if any).</li>"
58                 + "<li>The unit identifiers are internal, and are to 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. "
59                 + "<li>"
60                 + RATIONAL_MSG
61                 + "</li>"
62                 + "<li>The Systems column indicates which systems the units are used in. For now, they just show the two ‘inch-pound’ systems.</li>"
63                 + "<li>"
64                 + QUANTITY_MSG
65                 + "</li>"
66                 + "<li>"
67                 + SPEC_GENERAL_MSG
68                 + ".</li>"
69                 + "</ul>"
70                 + dataScrapeMessage(
71                         "/tr35-general.html#Contents",
72                         "common/testData/units/unitsTest.txt",
73                         "common/supplemental/units.xml");
74     }
75 
76     @Override
writeContents(FormattedFileWriter pw)77     public void writeContents(FormattedFileWriter pw) throws IOException {
78         //  <convertUnit source='ounce' baseUnit='kilogram' factor='lb_to_kg/16' systems="ussystem
79         // uksystem"/>
80         //  <convertUnit source='fahrenheit' baseUnit='kelvin' factor='5/9' offset='2298.35/9'
81         // systems="ussystem uksystem"/>
82 
83         TablePrinter tablePrinter =
84                 new TablePrinter()
85                         .addColumn("SortKey", "class='source'", null, "class='source'", true)
86                         .setHidden(true)
87                         .setSortPriority(0)
88                         .addColumn(
89                                 "Quantity",
90                                 "class='source'",
91                                 CldrUtility.getDoubleLinkMsg(),
92                                 "class='source'",
93                                 true)
94                         .setRepeatHeader(true)
95                         .setBreakSpans(true)
96                         .addColumn("Target", "class='source'", null, "class='source'", true)
97                         .addColumn("Systems", "class='source'", null, "class='source'", true)
98                         .addColumn(
99                                 "Source Unit",
100                                 "class='source'",
101                                 CldrUtility.getDoubleLinkMsg(),
102                                 "class='source'",
103                                 true)
104                         .addColumn("Approx. Factor", "class='target'", null, "class='target'", true)
105                         .setCellAttributes("class='target' style='text-align:right'")
106                         .addColumn("Exact* Factor", "class='target'", null, "class='target'", true)
107                         .setCellAttributes("class='target' style='text-align:right'")
108                         .addColumn("Offset", "class='target'", null, "class='target'", true)
109                         .setCellAttributes("class='target' style='text-align:right'");
110 
111         UnitConverter converter = SDI.getUnitConverter();
112         converter.getSourceToSystems();
113 
114         Set<R4<UnitId, UnitSystem, Rational, String>> all = new TreeSet<>();
115 
116         for (Entry<String, TargetInfo> entry : converter.getInternalConversionData().entrySet()) {
117             String sourceUnit = entry.getKey();
118             String quantity = converter.getQuantityFromUnit(sourceUnit, false);
119             TargetInfo targetInfo = entry.getValue();
120 
121             final EnumSet<UnitSystem> systems =
122                     EnumSet.copyOf(converter.getSystemsEnum(sourceUnit));
123 
124             // to sort the right items together items together, put together a sort key
125             UnitSystem sortingSystem = systems.iterator().next();
126             switch (sortingSystem) {
127                 case si:
128                 case si_acceptable:
129                     sortingSystem = UnitSystem.metric;
130                     break;
131                 case uksystem:
132                     sortingSystem = UnitSystem.ussystem;
133                     break;
134                 default:
135             }
136             UnitId targetUnitId = converter.createUnitId(targetInfo.target);
137             R4<UnitId, UnitSystem, Rational, String> sortKey =
138                     Row.of(targetUnitId, sortingSystem, targetInfo.unitInfo.factor, sourceUnit);
139             all.add(sortKey);
140 
141             // get some formatted strings
142             // TODO: handle specials here, CLDR-16329 additional PR or follow-on ticket
143 
144             final String repeatingFactor =
145                     targetInfo.unitInfo.factor.toString(FormatStyle.repeating);
146             final String basicFactor = targetInfo.unitInfo.factor.toString(FormatStyle.approx);
147             final String repeatingOffset =
148                     targetInfo.unitInfo.offset.equals(Rational.ZERO)
149                             ? ""
150                             : targetInfo.unitInfo.offset.toString(FormatStyle.repeating);
151 
152             String targetDisplay = targetInfo.target;
153             String normalized = converter.getStandardUnit(targetInfo.target);
154             if (!targetDisplay.equals(normalized)) {
155                 targetDisplay = normalized + " = " + targetDisplay;
156             }
157 
158             // now make a row
159 
160             tablePrinter
161                     .addRow()
162                     .addCell(sortKey)
163                     .addCell(quantity)
164                     .addCell(targetDisplay)
165                     .addCell(Joiner.on(", ").join(systems))
166                     .addCell(sourceUnit)
167                     .addCell(basicFactor)
168                     .addCell(repeatingFactor)
169                     .addCell(repeatingOffset)
170                     .finishRow();
171         }
172         pw.write(tablePrinter.toTable());
173         PrintWriter pw2 = new PrintWriter(System.out);
174         tablePrinter.toTsv(pw2);
175         pw2.flush();
176         pw2.close();
177         //        for (R4<UnitId, UnitSystem, Rational, String> sk : all) {
178         //            System.out.println(String.format("%s\t%s\t%s\t%s", sk.get0(), sk.get1(),
179         // sk.get2(), sk.get3()));
180         //        }
181     }
182 }
183