Fix “today or yesterday” rendering for languages that do not put the weekday first
authorTim Düsterhus <duesterhus@woltlab.com>
Wed, 26 Apr 2023 09:54:31 +0000 (11:54 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Wed, 26 Apr 2023 10:02:31 +0000 (12:02 +0200)
The previous version was broken, because it just returned the name of the
weekday (`value`), but the time was missing entirely. The code was refactored
to move the “weekday first” check into refresh(), allowing languages that put
the weekday first to proceed as previously without any visual changes and other
languages to just use the absolute date + time. The diff likely looks larger
than it is for that reason.

Rendering was verified with de, en_US, en_GB, ar, he, el, ru, ja.

ts/WoltLabSuite/WebComponent/woltlab-core-date-time.ts
wcfsetup/install/files/js/WoltLabSuite/WebComponent.js

index 3c660bdf1cea3f8c0bbb1b376d517786196615c2..f35498fdfa51c6dd8c4bb852fec12f47c31c6dc4 100644 (file)
         } else if (difference < TimePeriod.OneHour) {
           const minutes = Math.trunc(difference / TimePeriod.OneMinute);
           value = DateFormatter.Minutes.format(minutes * -1, "minute");
-        } else if (date.getTime() > todayDayStart) {
-          value = this.#formatTodayOrYesterday(date, TodayOrYesterday.Today);
-        } else if (date.getTime() > yesterdayDayStart) {
-          value = this.#formatTodayOrYesterday(date, TodayOrYesterday.Yesterday);
         } else if (difference < TimePeriod.OneWeek) {
-          value = DateFormatter.DayOfWeekAndTime.format(date);
+          const dateParts = DateFormatter.DayOfWeekAndTime.formatToParts(date);
+          const weekdayFirst = dateParts[0].type === "weekday";
+
+          if (weekdayFirst) {
+            // If the weekday comes first, we can be reasonably sure that
+            // "Today" and "Yesterday" can be inserted correctly.
+            if (date.getTime() > todayDayStart) {
+              value = this.#formatTodayOrYesterday(dateParts, TodayOrYesterday.Today);
+            } else if (date.getTime() > yesterdayDayStart) {
+              value = this.#formatTodayOrYesterday(dateParts, TodayOrYesterday.Yesterday);
+            } else {
+              value = dateParts.map((part) => part.value).join("");
+            }
+          } else {
+            // If the weekday does not come first, use absolute dates + times.
+            value = DateFormatter.DateAndTime.format(date);
+          }
         } else {
           value = DateFormatter.Date.format(date);
         }
      * the “date” portion as a relative value such as “today” or
      * “tomorrow” _along_ with the time.
      *
-     * This workaround will generate the date using the day of week
+     * This workaround will take the date using the day of week
      * and the time, but replace the day of week with the relative
      * value.
      */
-    #formatTodayOrYesterday(date: Date, dayOffset: TodayOrYesterday): string {
-      // This will generate the localized value of “today” or “tomorrow”.
-      let value = DateFormatter.TodayOrYesterday.format(dayOffset, "day");
-
-      const dateParts = DateFormatter.DayOfWeekAndTime.formatToParts(date);
-      if (dateParts[0].type === "weekday") {
-        const datePartsWithoutDayOfWeek: string[] = dateParts.slice(1).map((part) => part.value);
-        datePartsWithoutDayOfWeek.unshift(value);
-        value = datePartsWithoutDayOfWeek.join("");
-      }
+    #formatTodayOrYesterday(dateParts: Intl.DateTimeFormatPart[], dayOffset: TodayOrYesterday): string {
+      const datePartsWithReplacedWeekday: string[] = dateParts.map((part) => {
+        if (part.type === "weekday") {
+          // This will return the localized value of “today” or “tomorrow”.
+          return DateFormatter.TodayOrYesterday.format(dayOffset, "day");
+        } else {
+          return part.value;
+        }
+      });
 
-      return value;
+      return datePartsWithReplacedWeekday.join("");
     }
   }
 
index 89e025a2c8c016ee8a5b648ba249c87ae2f1109c..27f958471783251d057fad6d609c9e5a0b4edbf7 100644 (file)
           } else if (difference < 3600 /* OneHour */) {
             const minutes = Math.trunc(difference / 60 /* OneMinute */);
             value = DateFormatter.Minutes.format(minutes * -1, "minute");
-          } else if (date.getTime() > todayDayStart) {
-            value = this.#formatTodayOrYesterday(date, 0 /* Today */);
-          } else if (date.getTime() > yesterdayDayStart) {
-            value = this.#formatTodayOrYesterday(date, -1 /* Yesterday */);
           } else if (difference < 604800 /* OneWeek */) {
-            value = DateFormatter.DayOfWeekAndTime.format(date);
+            const dateParts = DateFormatter.DayOfWeekAndTime.formatToParts(date);
+            const weekdayFirst = dateParts[0].type === "weekday";
+            if (weekdayFirst) {
+              if (date.getTime() > todayDayStart) {
+                value = this.#formatTodayOrYesterday(dateParts, 0 /* Today */);
+              } else if (date.getTime() > yesterdayDayStart) {
+                value = this.#formatTodayOrYesterday(dateParts, -1 /* Yesterday */);
+              } else {
+                value = dateParts.map((part) => part.value).join("");
+              }
+            } else {
+              value = DateFormatter.DateAndTime.format(date);
+            }
           } else {
             value = DateFormatter.Date.format(date);
           }
        * the “date” portion as a relative value such as “today” or
        * “tomorrow” _along_ with the time.
        *
-       * This workaround will generate the date using the day of week
+       * This workaround will take the date using the day of week
        * and the time, but replace the day of week with the relative
        * value.
        */
-      #formatTodayOrYesterday(date, dayOffset) {
-        let value = DateFormatter.TodayOrYesterday.format(dayOffset, "day");
-        const dateParts = DateFormatter.DayOfWeekAndTime.formatToParts(date);
-        if (dateParts[0].type === "weekday") {
-          const datePartsWithoutDayOfWeek = dateParts.slice(1).map((part) => part.value);
-          datePartsWithoutDayOfWeek.unshift(value);
-          value = datePartsWithoutDayOfWeek.join("");
-        }
-        return value;
+      #formatTodayOrYesterday(dateParts, dayOffset) {
+        const datePartsWithReplacedWeekday = dateParts.map((part) => {
+          if (part.type === "weekday") {
+            return DateFormatter.TodayOrYesterday.format(dayOffset, "day");
+          } else {
+            return part.value;
+          }
+        });
+        return datePartsWithReplacedWeekday.join("");
       }
     }
     window.customElements.define("woltlab-core-date-time", WoltlabCoreDateTimeElement);