Add basic date & time formatters using navigator language (#404)

Adjacent to #400 — while this isn't yet a proper localization pass, at
least dates & times will now use the user's browser language/locale
settings. When used in Browsertrix, this should ensure dates are
formatted more consistently, at least when the user has a locale with a
language matching one of the supported languages in Browsertrix set in
their browser settings.

Also adds tabular numerals in a few places (e.g. lists of dates/times).
This commit is contained in:
Emma Segal-Grossman
2025-03-04 13:52:06 -05:00
committed by GitHub
parent 51c7eef4cd
commit 64dc599532
7 changed files with 62 additions and 26 deletions
+4 -1
View File
@@ -12,6 +12,7 @@ import { tsToDate } from "./pageutils";
import prettyBytes from "pretty-bytes"; import prettyBytes from "pretty-bytes";
import { property } from "lit/decorators.js"; import { property } from "lit/decorators.js";
import type { ItemType } from "./types"; import type { ItemType } from "./types";
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
// =========================================================================== // ===========================================================================
export class RWPEmbedReceipt extends LitElement { export class RWPEmbedReceipt extends LitElement {
@@ -184,7 +185,9 @@ export class RWPEmbedReceipt extends LitElement {
? `https://crt.sh/?q=${certFingerprint}` ? `https://crt.sh/?q=${certFingerprint}`
: ""; : "";
const dateStr = tsToDate(this.ts).toLocaleString(); const dateStr = this.ts
? dateTimeFormatter.format(tsToDate(this.ts) as Date)
: "";
return html` return html`
<div class="dropdown mb-4 ${this.active ? "is-active" : ""}"> <div class="dropdown mb-4 ${this.active ? "is-active" : ""}">
+4 -1
View File
@@ -7,6 +7,7 @@ import prettyBytes from "pretty-bytes";
import type { ItemType } from "./types"; import type { ItemType } from "./types";
import "./components/labeled-field"; import "./components/labeled-field";
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
// =========================================================================== // ===========================================================================
class ItemInfo extends LitElement { class ItemInfo extends LitElement {
@@ -111,7 +112,9 @@ class ItemInfo extends LitElement {
</wr-labeled-field>` </wr-labeled-field>`
: nothing} : nothing}
<wr-labeled-field label="Date Loaded" class="column is-2"> <wr-labeled-field label="Date Loaded" class="column is-2">
${item!.ctime ? new Date(item!.ctime).toLocaleString() : nothing} ${item!.ctime
? dateTimeFormatter.format(new Date(item!.ctime))
: nothing}
</wr-labeled-field> </wr-labeled-field>
<wr-labeled-field label="Total Size" class="column is-2"> <wr-labeled-field label="Total Size" class="column is-2">
${prettyBytes(Number(item!.totalSize || item!.size || 0))} ${prettyBytes(Number(item!.totalSize || item!.size || 0))}
+15 -3
View File
@@ -55,6 +55,7 @@ import type { Replay } from "./replay";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import "./item-info"; import "./item-info";
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
const RWP_SCHEME = "search://"; const RWP_SCHEME = "search://";
@@ -756,6 +757,7 @@ class Item extends LitElement {
align-items: center; align-items: center;
transition: background-color var(--sl-transition-fast); transition: background-color var(--sl-transition-fast);
color: var(--sl-color-neutral-600); color: var(--sl-color-neutral-600);
font-variant-numeric: tabular-nums;
} }
.timestamp-dropdown-btn:hover { .timestamp-dropdown-btn:hover {
@@ -782,6 +784,10 @@ class Item extends LitElement {
transform: translateY(0.075em); transform: translateY(0.075em);
} }
.timestamp-menu-item {
font-variant-numeric: tabular-nums;
}
.timestamp-menu-item[aria-selected="true"]::part(label) { .timestamp-menu-item[aria-selected="true"]::part(label) {
color: var(--sl-color-blue-600); color: var(--sl-color-blue-600);
} }
@@ -1245,7 +1251,9 @@ class Item extends LitElement {
protected renderToolbarRight() { protected renderToolbarRight() {
const isReplay = !!this.tabData.url; const isReplay = !!this.tabData.url;
const dateStr = tsToDate(this.ts).toLocaleString(); const dateStr = this.ts
? dateTimeFormatter.format(tsToDate(this.ts) as Date)
: "";
return html` <div return html` <div
class="dropdown is-right ${this.menuActive ? "is-active" : ""}" class="dropdown is-right ${this.menuActive ? "is-active" : ""}"
@@ -1419,7 +1427,9 @@ class Item extends LitElement {
// Filter out invalid dates // Filter out invalid dates
try { try {
const date = getDateFromTS(+ts); const date = getDateFromTS(+ts);
const dateStr = tsToDate(date).toLocaleString(); const dateStr = date
? dateTimeFormatter.format(tsToDate(date) as Date)
: "";
timestampStrs.push({ timestampStrs.push({
date, date,
label: dateStr, label: dateStr,
@@ -1428,7 +1438,9 @@ class Item extends LitElement {
/* empty */ /* empty */
} }
}); });
const currDateStr = tsToDate(this.ts).toLocaleString(); const currDateStr = this.ts
? dateTimeFormatter.format(tsToDate(this.ts) as Date)
: "";
return html`<div id="datetime" class="control is-hidden-mobile"> return html`<div id="datetime" class="control is-hidden-mobile">
${timestampStrs.length > 1 ${timestampStrs.length > 1
? html` ? html`
+12 -19
View File
@@ -9,6 +9,11 @@ import { getPageDateTS, getReplayLink } from "./pageutils";
import { wrapCss } from "./misc"; import { wrapCss } from "./misc";
import type { URLResource } from "./types"; import type { URLResource } from "./types";
import {
dateFormatter,
dateTimeFormatter,
timeFormatter,
} from "./utils/dateTimeFormatter";
// =========================================================================== // ===========================================================================
class PageEntry extends LitElement { class PageEntry extends LitElement {
@@ -154,6 +159,10 @@ class PageEntry extends LitElement {
.media-content a { .media-content a {
display: block; display: block;
} }
.col-date {
font-variant-numeric: tabular-nums;
}
`); `);
} }
@@ -218,20 +227,8 @@ class PageEntry extends LitElement {
` `
: ""} : ""}
<div class="column col-date is-2"> <div class="column col-date is-2">
<div> <div>${date ? dateFormatter.format(date) : ""}</div>
${ <div>${date ? timeFormatter.format(date) : ""}</div>
// TODO: Fix this the next time the file is edited.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
date ? date.toLocaleDateString() : ""
}
</div>
<div>
${
// TODO: Fix this the next time the file is edited.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
date ? date.toLocaleTimeString() : ""
}
</div>
</div> </div>
<div class="column"> <div class="column">
<div class="media"> <div class="media">
@@ -259,11 +256,7 @@ class PageEntry extends LitElement {
>${this.thumbnailValid ? this.renderFavicon() : ""} >${this.thumbnailValid ? this.renderFavicon() : ""}
</p> </p>
<p class="has-text-grey-dark text is-inline-date"> <p class="has-text-grey-dark text is-inline-date">
${ ${date ? dateTimeFormatter.format(date) : ""}
// TODO: Fix this the next time the file is edited.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
date ? date.toLocaleString() : ""
}
</p> </p>
</a> </a>
${this.textSnippet ${this.textSnippet
+2 -1
View File
@@ -10,6 +10,7 @@ import { getTS, getReplayLink } from "./pageutils";
import Split from "split.js"; import Split from "split.js";
import { type ItemType } from "./types"; import { type ItemType } from "./types";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
// =========================================================================== // ===========================================================================
@customElement("wr-coll-story") @customElement("wr-coll-story")
@@ -364,7 +365,7 @@ class Story extends LitElement {
<p class="is-size-6 has-text-weight-bold has-text-link">${p.title}</p> <p class="is-size-6 has-text-weight-bold has-text-link">${p.title}</p>
<p class="has-text-dark">${p.url}</p> <p class="has-text-dark">${p.url}</p>
</a> </a>
<p>${date.toLocaleString()}</p> <p>${dateTimeFormatter.format(date)}</p>
<p>${p.desc}</p> <p>${p.desc}</p>
</div> </div>
<hr /> <hr />
+2 -1
View File
@@ -8,6 +8,7 @@ import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
import "keyword-mark-element/lib/keyword-mark.js"; import "keyword-mark-element/lib/keyword-mark.js";
import { type ItemType } from "./types"; import { type ItemType } from "./types";
import { type URLResource } from "./types"; import { type URLResource } from "./types";
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
// =========================================================================== // ===========================================================================
/** /**
@@ -544,7 +545,7 @@ class URLResources extends LitElement {
</td> </td>
<td class="column col-ts is-2"> <td class="column col-ts is-2">
<p class="minihead is-hidden-tablet">Date</p> <p class="minihead is-hidden-tablet">Date</p>
${new Date(result.date).toLocaleString()} ${dateTimeFormatter.format(new Date(result.date))}
</td> </td>
<td class="column col-mime is-3"> <td class="column col-mime is-3">
<p class="minihead is-hidden-tablet">Media Type</p> <p class="minihead is-hidden-tablet">Media Type</p>
+23
View File
@@ -0,0 +1,23 @@
export const dateTimeFormatter = new Intl.DateTimeFormat(
[...navigator.languages],
{
month: "2-digit",
day: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
},
);
export const dateFormatter = new Intl.DateTimeFormat([...navigator.languages], {
month: "2-digit",
day: "2-digit",
year: "numeric",
});
export const timeFormatter = new Intl.DateTimeFormat([...navigator.languages], {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});