Skip to content

Commit

Permalink
CLDR-16933 Allow names for noon, midnight to match adjacent non-fixed…
Browse files Browse the repository at this point in the history
… dayPeriods; add tests & spec note (#3857)
  • Loading branch information
pedberg-icu authored Jul 9, 2024
1 parent 5bb8280 commit 229b635
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 5 deletions.
4 changes: 3 additions & 1 deletion docs/ldml/tr35-dates.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,9 @@ The former `am`/`pm` elements have been deprecated, and replaced by the more fle

These behave like months, days, and so on in terms of having context and width. Each locale has an associated dayPeriodRuleSet in the supplemental data, rules that specify when the day periods start and end for that locale. Each type in the rules needs to have a translation in a dayPeriod (but if translation data is missing for a particular variable dayPeriod in the locale’s language and script, formatting should fall back to using the am/pm values). For more information, see _[Day Period Rules](#Day_Period_Rules)_.

The dayPeriod names should be distinct within each of the context/width combinations, including narrow; as with era names, there is less disambiguating information for them, and they are more likely to be used in a format that requires parsing. In some unambiguous cases, it is acceptable for certain overlapping dayPeriods to be the same, such as the names for "am" and "morning", or the names for "pm" and "afternoon".
The dayPeriod names should be distinct within each of the context/width combinations, including narrow; as with era names, there is less disambiguating information for them, and they are more likely to be used in a format that requires parsing. In some unambiguous cases, it is acceptable for certain overlapping dayPeriods to be the same, such as the names for `am` and `morning`, or the names for `pm` and `afternoon`.

If dayPeriods are specified for `noon` and `midnight`, they can often be formatted without also specifying the numeric time, e.g. "May 6, noon" instead of "May 6, 12:00 noon" or "May 6, 12:00 PM". To prevent parse issues, this should only be done if the names for `noon` and `midnight` are not also used for any other day periods, such as for `morning2` or `night1`.

Example:

Expand Down
6 changes: 4 additions & 2 deletions docs/ldml/tr35.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
|Version|46 (draft)|
|-------|----------|
|Editors|Mark Davis (<a href="mailto:[email protected]">[email protected]</a>) and <a href="tr35.md#Acknowledgments">other CLDR committee members</a>|
|Date|2024-04-22|
|Date|2024-07-08|
|This Version|<a href="https://www.unicode.org/reports/tr35/tr35-73/tr35.html">https://www.unicode.org/reports/tr35/tr35-73/tr35.html</a>|
|Previous Version|<a href="https://www.unicode.org/reports/tr35/tr35-72/tr35.html">https://www.unicode.org/reports/tr35/tr35-72/tr35.html</a>|
|Latest Version|<a href="https://www.unicode.org/reports/tr35/">https://www.unicode.org/reports/tr35/</a>|
Expand Down Expand Up @@ -4095,7 +4095,9 @@ Other contributors to CLDR are listed on the [CLDR Project Page](https://www.uni

**Differences from LDML Version 45**

(in progress)
* Part 4: [Dates](tr35-dates.md#Contents)
* In [Element dayPeriods](tr35-dates.md#dayPeriods), added a note on special formatting usable with
dayPeriods `noon` and `midnight`.

**Differences from LDML Version 44.1**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,9 @@ && isTooMuchWiderThan(value, abbrValue)
final boolean isDayPeriod = path.contains("dayPeriod");
if (isDayPeriod) {
XPathParts parts = XPathParts.getFrozenInstance(fullPath);
type = Type.fromString(parts.getAttributeValue(5, "type"));
type =
Type.fromString(
parts.getAttributeValue(5, "type")); // format, stand-alone
dayPeriod = DayPeriod.valueOf(parts.getAttributeValue(-1, "type"));
}

Expand Down Expand Up @@ -577,7 +579,10 @@ && isTooMuchWiderThan(value, abbrValue)
}
if (isDayPeriod) {
// ldml/dates/calendars/calendar[@type="gregorian"]/dayPeriods/dayPeriodContext[@type="format"]/dayPeriodWidth[@type="wide"]/dayPeriod[@type="am"]
Type itemType = Type.fromString(itemParts.getAttributeValue(5, "type"));
Type itemType =
Type.fromString(
itemParts.getAttributeValue(
5, "type")); // format, stand-alone
DayPeriod itemDayPeriod =
DayPeriod.valueOf(itemParts.getAttributeValue(-1, "type"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,42 @@ public boolean collisionIsError(
}
}

// Fix for CLDR-16933, for format types only
// Let midnight match a non-fixed period that starts at, ends at, or contains midnight (both
// versions);
// Let noon match a non-fixed period that starts at, ends at, or contains noon (or just
// before noon);
if (type1 == Type.format && type2 == Type.format) {
if (dayPeriod1 == DayPeriod.midnight && !dayPeriod2.isFixed()) {
for (Span s : dayPeriodsToSpans.get(dayPeriod2)) {
if (s.contains(MIDNIGHT) || s.contains(DAY_LIMIT)) {
return false;
}
}
}
if (dayPeriod2 == DayPeriod.midnight && !dayPeriod1.isFixed()) {
for (Span s : dayPeriodsToSpans.get(dayPeriod1)) {
if (s.contains(MIDNIGHT) || s.contains(DAY_LIMIT)) {
return false;
}
}
}
if (dayPeriod1 == DayPeriod.noon && !dayPeriod2.isFixed()) {
for (Span s : dayPeriodsToSpans.get(dayPeriod2)) {
if (s.contains(NOON) || s.contains(NOON - 1)) {
return false;
}
}
}
if (dayPeriod2 == DayPeriod.noon && !dayPeriod1.isFixed()) {
for (Span s : dayPeriodsToSpans.get(dayPeriod1)) {
if (s.contains(NOON) || s.contains(NOON - 1)) {
return false;
}
}
}
}

// we use the more lenient if they are mixed types
if (type2 == Type.format) {
type1 = Type.format;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,48 @@ public void TestDotPixel14031() {
checkDisplayCollisions("de", pathValuePairs, factory);
}

public void checkDayPeriodCollisions() {
// CLDR-16933 (uk, ...)
// Let midnight match a non-fixed period that starts at, ends at, or contains midnight (both
// versions);
// Let noon match a non-fixed period that starts at, ends at, or contains noon (or just
// before noon);
Map<String, String> ukPathValuePairs =
ImmutableMap.of(
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"midnight\"]",
"ночі",
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"night1\"]",
"ночі",
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"noon\"]",
"дня",
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"afternoon1\"]",
"дня");
TestFactory ukFactory = makeFakeCldrFile("uk", ukPathValuePairs);
checkDisplayCollisions("uk", ukPathValuePairs, ukFactory);

// CLDR-17132 (fr, ...)
// Let night1 have the same name as morning1/am if night1 starts at 00:00
Map<String, String> frPathValuePairs =
ImmutableMap.of(
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"morning1\"]",
"matin",
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"night1\"]",
"matin");
TestFactory frFactory = makeFakeCldrFile("fr", frPathValuePairs);
checkDisplayCollisions("fr", frPathValuePairs, frFactory);

// CLDR-17139 (fil, ...)
// Let night1 have the same name as evening1 if night1 ends at 24:00
Map<String, String> filPathValuePairs =
ImmutableMap.of(
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"evening1\"]",
"ng gabi",
"ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\"format\"]/dayPeriodWidth[@type=\"abbreviated\"]/dayPeriod[@type=\"night1\"]",
"ng gabi");
TestFactory filFactory = makeFakeCldrFile("fil", filPathValuePairs);
checkDisplayCollisions("fil", filPathValuePairs, filFactory);
}

public void checkDisplayCollisions(
String locale, Map<String, String> pathValuePairs, TestFactory factory) {
CheckDisplayCollisions cdc = new CheckDisplayCollisions(factory);
Expand Down

0 comments on commit 229b635

Please sign in to comment.