Skip to content

Commit 3a66f8c

Browse files
committed
ICU-23172 part 1: Convert era names from array to map (#3588):
- handle era codes with non-0 start, holes
1 parent e45b3fe commit 3a66f8c

File tree

4 files changed

+82
-14
lines changed

4 files changed

+82
-14
lines changed

icu4c/source/i18n/dtfmtsym.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,8 +1782,50 @@ struct CalendarDataSink : public ResourceSink {
17821782
arraySizes.puti(path, dataArraySize, errorCode);
17831783
if (U_FAILURE(errorCode)) { return; }
17841784
} else if (value.getType() == URES_TABLE) {
1785-
// We are not on a leaf, recursively process the subtable.
1786-
processResource(path, key, value, errorCode);
1785+
// We might have an eras table that is replacing an eras leaf array
1786+
if (path.startsWith(u"eras", 4)) {
1787+
// path is one of eras/wide, eras/abbreviated, eras/narrow
1788+
ResourceTable rDataTable = value.getTable(errorCode);
1789+
int32_t dataTableSize = rDataTable.getSize();
1790+
UVector dataList(uprv_deleteUObject, uhash_compareUnicodeString, dataTableSize, errorCode);
1791+
if (U_FAILURE(errorCode)) { return; }
1792+
// Expand the UVector as necessary to have index from 0 up to the max
1793+
// eraCode, and fill in the slots for the eras defined in the resource data
1794+
// (filling in empty strings for other eras as we expand, since they would
1795+
// otherwise not get set to anything in particular such as null).
1796+
for (int32_t dataTableIndex = 0; dataTableIndex < dataTableSize; dataTableIndex++) {
1797+
rDataTable.getKeyAndValue(dataTableIndex, key, value);
1798+
int32_t listIndex = uprv_strtol(key, nullptr, 10);
1799+
if (listIndex + 1 > dataList.size()) {
1800+
dataList.ensureCapacity(listIndex + 1, errorCode); // needed only to minimize expansions
1801+
if (U_FAILURE(errorCode)) { return; }
1802+
// Fill in empty strings for all added slots (else they are undefined)
1803+
while (dataList.size() < listIndex + 1) {
1804+
LocalPointer<UnicodeString> emptyString(new UnicodeString(), errorCode);
1805+
dataList.adoptElement(emptyString.orphan(), errorCode);
1806+
}
1807+
}
1808+
// Now set the eraName that we just read
1809+
LocalPointer<UnicodeString> eraName((value.getType() == URES_STRING) ?
1810+
new UnicodeString(value.getUnicodeString(errorCode)) : new UnicodeString(), errorCode);
1811+
if (U_FAILURE(errorCode)) { return; }
1812+
dataList.setElementAt(eraName.orphan(), listIndex);
1813+
}
1814+
// Now convert to array running from era code 0 to the max era we have data for, fill
1815+
// in from the UVector
1816+
int32_t dataArraySize = dataList.size();
1817+
LocalArray<UnicodeString> dataArray(new UnicodeString[dataArraySize], errorCode);
1818+
// Fill out dataArray from dataList (dataList.toArray did not seem to work as expected)
1819+
for (int32_t dataArrayIndex = 0; dataArrayIndex < dataArraySize; dataArrayIndex++) {
1820+
dataArray[dataArrayIndex] = std::move(*(reinterpret_cast<UnicodeString *>(dataList.elementAt(dataArrayIndex))));
1821+
}
1822+
// Save array...
1823+
arrays.put(path, dataArray.orphan(), errorCode);
1824+
arraySizes.puti(path, dataArraySize, errorCode);
1825+
} else {
1826+
// We are not on a leaf, recursively process the subtable.
1827+
processResource(path, key, value, errorCode);
1828+
}
17871829
if (U_FAILURE(errorCode)) { return; }
17881830
}
17891831

icu4j/main/core/src/main/java/com/ibm/icu/text/DateFormatSymbols.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.IOException;
1313
import java.io.ObjectInputStream;
1414
import java.io.Serializable;
15+
import java.lang.Integer;
1516
import java.util.ArrayList;
1617
import java.util.HashMap;
1718
import java.util.HashSet;
@@ -1805,8 +1806,37 @@ protected void processResource(String path, UResource.Key key, UResource.Value v
18051806
String[] dataArray = value.getStringArray();
18061807
arrays.put(currentPath, dataArray);
18071808
} else if (value.getType() == ICUResourceBundle.TABLE) {
1808-
// We are not on a leaf, recursively process the subtable.
1809-
processResource(currentPath, key, value);
1809+
// We might have an eras table that is replacing an eras leaf array
1810+
if (currentPath.startsWith("eras")) {
1811+
// path is one of eras/wide, eras/abbreviated, eras/narrow
1812+
UResource.Table rDataTable = value.getTable();
1813+
int dataTableSize = rDataTable.getSize();
1814+
ArrayList<String> dataList = new ArrayList<>(dataTableSize);
1815+
// Expand the ArrayList as necessary to have index from 0 up to the max
1816+
// eraCode, and fill in the slots for the eras defined in the resource data
1817+
// (other slots get nulls).
1818+
for (int dataTableIndex = 0; dataTableIndex < dataTableSize; dataTableIndex++) {
1819+
rDataTable.getKeyAndValue(dataTableIndex, key, value);
1820+
int listIndex = Integer.parseInt(key.toString());
1821+
if (listIndex + 1 > dataList.size()) {
1822+
dataList.ensureCapacity(listIndex + 1); // needed only to minimize expansions
1823+
// Fill in empty strings for all added slots
1824+
while (dataList.size() < listIndex + 1) {
1825+
dataList.add("");
1826+
}
1827+
}
1828+
// Now set the eraName that we just read
1829+
String eraName = (value.getType() == ICUResourceBundle.STRING) ? value.getString() : "";
1830+
dataList.set(listIndex, eraName);
1831+
}
1832+
// Now convert to array
1833+
String[] dataArray = dataList.toArray(new String[dataList.size()]);
1834+
// Save the array
1835+
arrays.put(currentPath, dataArray);
1836+
} else {
1837+
// We are not on a leaf, recursively process the subtable.
1838+
processResource(currentPath, key, value);
1839+
}
18101840
}
18111841
}
18121842
}

tools/cldr/cldr-to-icu/src/main/java/org/unicode/icu/tool/cldrtoicu/IcuTextWriter.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ private boolean appendValues(
252252
private static final RbPath RB_SEQUENCE = RbPath.of("Sequence");
253253
private static final RbPath RB_RULES = RbPath.of("rules");
254254
private static final RbPath RB_LOCALE_SCRIPT = RbPath.of("LocaleScript");
255-
private static final RbPath RB_ERAS = RbPath.of("eras");
256255
private static final RbPath RB_NAMED = RbPath.of("named");
257256
private static final RbPath RB_CALENDAR_PREFERENCE_DATA = RbPath.of("calendarPreferenceData");
258257
private static final RbPath RB_METAZONE_INFO = RbPath.of("metazoneInfo");
@@ -270,9 +269,6 @@ private static boolean mustBeArray(boolean topValues, String name, RbPath rbPath
270269
&& rbPath.getSegment(1).startsWith("set");
271270
}
272271
return rbPath.equals(RB_LOCALE_SCRIPT)
273-
|| (rbPath.contains(RB_ERAS)
274-
&& !rbPath.getSegment(rbPath.length() - 1).endsWith(":alias")
275-
&& !rbPath.endsWith(RB_NAMED))
276272
|| rbPath.startsWith(RB_CALENDAR_PREFERENCE_DATA)
277273
|| rbPath.startsWith(RB_METAZONE_INFO);
278274
}

tools/cldr/cldr-to-icu/src/main/resources/ldml2icu_locale.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,13 @@
230230
//ldml/dates/calendars/calendar[@type="(%A)"]/dayPeriods/dayPeriodContext[@type="(%A)"]/dayPeriodWidth[@type="(%A)"]/dayPeriod[@type="(?!am|pm)(%A)"][@alt="(%A)"] ; /calendar/$1/dayPeriod/$2/$3/$4%$5
231231
//ldml/dates/calendars/calendar[@type="(%A)"]/dayPeriods/dayPeriodContext[@type="(%A)"]/dayPeriodWidth[@type="(%A)"]/dayPeriod[@type="(?!am|pm)(%A)"] ; /calendar/$1/dayPeriod/$2/$3/$4
232232

233-
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNarrow/era[@type="(%A)"][@alt="(%A)"] ; /calendar/$1/eras/narrow%$3
234-
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraAbbr/era[@type="(%A)"][@alt="(%A)"] ; /calendar/$1/eras/abbreviated%$3
235-
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNames/era[@type="(%A)"][@alt="(%A)"] ; /calendar/$1/eras/wide%$3
233+
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNarrow/era[@type="(%A)"][@alt="(%A)"] ; /calendar/$1/eras/narrow%$3/$2
234+
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraAbbr/era[@type="(%A)"][@alt="(%A)"] ; /calendar/$1/eras/abbreviated%$3/$2
235+
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNames/era[@type="(%A)"][@alt="(%A)"] ; /calendar/$1/eras/wide%$3/$2
236236

237-
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNarrow/era[@type="(%A)"] ; /calendar/$1/eras/narrow
238-
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraAbbr/era[@type="(%A)"] ; /calendar/$1/eras/abbreviated
239-
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNames/era[@type="(%A)"] ; /calendar/$1/eras/wide
237+
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNarrow/era[@type="(%A)"] ; /calendar/$1/eras/narrow/$2
238+
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraAbbr/era[@type="(%A)"] ; /calendar/$1/eras/abbreviated/$2
239+
//ldml/dates/calendars/calendar[@type="(%A)"]/eras/eraNames/era[@type="(%A)"] ; /calendar/$1/eras/wide/$2
240240

241241
# Leap year names go after other month names.
242242
# "yeartype" is an #IMPLIED attribute in the DTD and it should implicitly default to "standard".

0 commit comments

Comments
 (0)