@protobase/ui 0.23.3 → 0.23.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/app.d.ts +4 -1
- package/dist/app/app.js +25 -19
- package/dist/app/charts/chart-groups.js +3 -2
- package/dist/app/charts/period-chart.js +3 -2
- package/dist/app/create/create-values.js +1 -1
- package/dist/app/custom-section.js +1 -1
- package/dist/app/displays/board-column.js +2 -1
- package/dist/app/displays/custom-display.js +1 -1
- package/dist/app/displays/display-frame.js +3 -2
- package/dist/app/displays/map-display.js +4 -3
- package/dist/app/embedded-list/cut-off-note.js +2 -1
- package/dist/app/hand-order/hand-sorted-list.js +2 -1
- package/dist/app/hand-order/use-hand-order.js +1 -1
- package/dist/app/import/import-check-step.js +3 -2
- package/dist/app/import/import-counts.js +2 -1
- package/dist/app/import/import-dialog.js +2 -1
- package/dist/app/import/import-result-step.js +2 -1
- package/dist/app/incoming-relations.js +1 -1
- package/dist/app/list-edit/use-list-edits.js +1 -1
- package/dist/app/list-page.js +1 -1
- package/dist/app/main.js +3 -1
- package/dist/app/map/records-map.js +4 -3
- package/dist/app/meta-gate-messages.js +16 -0
- package/dist/app/meta-gate.js +14 -5
- package/dist/app/nav-recent.js +1 -1
- package/dist/app/pages/blocks/link.js +1 -1
- package/dist/app/pages/blocks/progress.js +3 -2
- package/dist/app/pages/blocks/stat.js +2 -1
- package/dist/app/pages/render-node.js +1 -1
- package/dist/app/pages/use-layout-data.js +1 -1
- package/dist/app/record-preview.js +1 -1
- package/dist/app/record-row/record-row-body.js +2 -1
- package/dist/app/saved/saved-records.js +1 -1
- package/dist/app/search/messages.js +18 -0
- package/dist/app/search/search-model.js +6 -5
- package/dist/app/searches/saved-search-rows.js +1 -1
- package/dist/app/searches/saved-searches.js +1 -1
- package/dist/app/searches/update-search-dialog.js +1 -1
- package/dist/app/searches/use-save-search.js +1 -1
- package/dist/app-shell/bottom-bar.js +3 -2
- package/dist/app-shell/breadcrumb.js +2 -1
- package/dist/app-shell/drawer.js +2 -1
- package/dist/app-shell/global-search.js +5 -4
- package/dist/app-shell/messages.js +64 -0
- package/dist/app-shell/profile-menu.js +5 -4
- package/dist/app-shell/sidebar-group.js +6 -5
- package/dist/app-shell/sidebar.js +4 -3
- package/dist/app-shell/theme-switch.js +8 -7
- package/dist/app-shell/top-bar.js +5 -4
- package/dist/data/api-provider.d.ts +2 -0
- package/dist/data/focus-refresh.js +2 -0
- package/dist/data/live-refresh.js +29 -0
- package/dist/data/meta-data.d.ts +3 -0
- package/dist/data/use-live-updates.js +36 -0
- package/dist/data/use-meta.js +1 -0
- package/dist/data/use-record.js +1 -1
- package/dist/data/use-update-record.js +1 -1
- package/dist/format/date.js +42 -50
- package/dist/format/intl-cache.js +12 -0
- package/dist/format/messages.js +24 -0
- package/dist/format/money.js +9 -16
- package/dist/format/number-text.js +3 -2
- package/dist/format/number.js +7 -5
- package/dist/format/zone.js +3 -5
- package/dist/invitations/pending-invitation-row.js +2 -1
- package/dist/live/display-value.js +2 -1
- package/dist/locale/active-locale.js +24 -0
- package/dist/locale/app-locale.js +18 -0
- package/dist/locale/messages.js +12 -0
- package/dist/organizations/organizations-page.js +2 -1
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-Di4_EOe7.js +69 -0
- package/dist/shell/assets/export-worker-O1HF9R4j.js +2 -0
- package/dist/shell/assets/{index-BShZnsl_.js → index-DIcL_2pR.js} +2 -2
- package/dist/shell/assets/{maplibre-Z-0y-JM5.js → maplibre-B8VhXCMb.js} +2 -2
- package/dist/shell/assets/{markdown-content-C2__fEXf.js → markdown-content-CDcQeWQm.js} +1 -1
- package/dist/shell/assets/{record-map-sG110J_j.js → record-map-Bd0yjDXL.js} +1 -1
- package/dist/shell/assets/records-map-QR_MUceu.js +1 -0
- package/dist/shell/assets/{shared-protobase-ui-QAWUDrTS.js → shared-protobase-ui-CWBBcLfz.js} +1 -1
- package/dist/shell/index.html +3 -3
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/app-DDou93IP.js +0 -69
- package/dist/shell/assets/export-worker-C1djGgjD.js +0 -2
- package/dist/shell/assets/records-map-mv11CA2m.js +0 -1
package/dist/format/date.js
CHANGED
|
@@ -1,77 +1,69 @@
|
|
|
1
|
+
import { cachedFormat } from "./intl-cache.js";
|
|
2
|
+
import { text } from "./messages.js";
|
|
1
3
|
import { viewerZone } from "./zone.js";
|
|
2
4
|
//#region src/format/date.ts
|
|
3
|
-
const
|
|
5
|
+
const dateFormat = (name, options) => () => cachedFormat(`date:${name}`, (tag) => new Intl.DateTimeFormat(tag, {
|
|
6
|
+
...options,
|
|
7
|
+
timeZone: "UTC"
|
|
8
|
+
}));
|
|
9
|
+
const day = dateFormat("day", {
|
|
4
10
|
day: "numeric",
|
|
5
11
|
month: "short",
|
|
6
|
-
year: "numeric"
|
|
7
|
-
timeZone: "UTC"
|
|
12
|
+
year: "numeric"
|
|
8
13
|
});
|
|
9
|
-
const dayShort =
|
|
14
|
+
const dayShort = dateFormat("dayShort", {
|
|
10
15
|
day: "numeric",
|
|
11
|
-
month: "short"
|
|
12
|
-
timeZone: "UTC"
|
|
16
|
+
month: "short"
|
|
13
17
|
});
|
|
14
|
-
const month =
|
|
18
|
+
const month = dateFormat("month", {
|
|
15
19
|
month: "long",
|
|
16
|
-
year: "numeric"
|
|
17
|
-
timeZone: "UTC"
|
|
20
|
+
year: "numeric"
|
|
18
21
|
});
|
|
19
|
-
const weekday =
|
|
20
|
-
|
|
21
|
-
timeZone: "UTC"
|
|
22
|
-
});
|
|
23
|
-
const weekdayDate = new Intl.DateTimeFormat("en-GB", {
|
|
22
|
+
const weekday = dateFormat("weekday", { weekday: "short" });
|
|
23
|
+
const weekdayDate = dateFormat("weekdayDate", {
|
|
24
24
|
weekday: "long",
|
|
25
25
|
day: "numeric",
|
|
26
26
|
month: "short",
|
|
27
|
-
year: "numeric"
|
|
28
|
-
timeZone: "UTC"
|
|
27
|
+
year: "numeric"
|
|
29
28
|
});
|
|
30
|
-
const formatDate = (ms) => day.format(ms);
|
|
31
|
-
const formatDayShort = (ms) => dayShort.format(ms);
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
hour12: false,
|
|
47
|
-
timeZone: zone
|
|
48
|
-
})
|
|
49
|
-
};
|
|
50
|
-
zoned.set(zone, formats);
|
|
51
|
-
return formats;
|
|
52
|
-
};
|
|
29
|
+
const formatDate = (ms) => day().format(ms);
|
|
30
|
+
const formatDayShort = (ms) => dayShort().format(ms);
|
|
31
|
+
const zonedFormats = (zone) => cachedFormat(`zoned:${zone}`, (tag) => ({
|
|
32
|
+
day: new Intl.DateTimeFormat(tag, {
|
|
33
|
+
day: "numeric",
|
|
34
|
+
month: "short",
|
|
35
|
+
year: "numeric",
|
|
36
|
+
timeZone: zone
|
|
37
|
+
}),
|
|
38
|
+
time: new Intl.DateTimeFormat(tag, {
|
|
39
|
+
hour: "2-digit",
|
|
40
|
+
minute: "2-digit",
|
|
41
|
+
hour12: false,
|
|
42
|
+
timeZone: zone
|
|
43
|
+
})
|
|
44
|
+
}));
|
|
53
45
|
/** "6 Oct 2026, 16:32": an instant on the clock of `zone`, the viewer's unless given. */
|
|
54
46
|
const formatDateTime = (ms, zone = viewerZone()) => {
|
|
55
47
|
const formats = zonedFormats(zone);
|
|
56
48
|
return `${formats.day.format(ms)}, ${formats.time.format(ms)}`;
|
|
57
49
|
};
|
|
58
50
|
/** "October 2026". */
|
|
59
|
-
const formatMonth = (ms) => month.format(ms);
|
|
51
|
+
const formatMonth = (ms) => month().format(ms);
|
|
60
52
|
/** "Mon". */
|
|
61
|
-
const formatWeekday = (ms) => weekday.format(ms);
|
|
53
|
+
const formatWeekday = (ms) => weekday().format(ms);
|
|
62
54
|
/** "Monday, 12 Oct 2026". */
|
|
63
|
-
const formatWeekdayDate = (ms) => weekdayDate.format(ms);
|
|
55
|
+
const formatWeekdayDate = (ms) => weekdayDate().format(ms);
|
|
64
56
|
/** "12–18 Oct 2026", "28 Dec 2026 – 3 Jan 2027": the days from `from` to `to`, both included. */
|
|
65
|
-
const formatDayRange = (from, to) => day.formatRange(from, to);
|
|
57
|
+
const formatDayRange = (from, to) => day().formatRange(from, to);
|
|
66
58
|
/** "09:30": an instant's time on the clock of `zone`, the viewer's unless given. */
|
|
67
59
|
const formatTime = (ms, zone = viewerZone()) => zonedFormats(zone).time.format(ms);
|
|
68
60
|
const formatAgo = (seconds) => {
|
|
69
|
-
if (seconds < 60) return
|
|
70
|
-
if (seconds < 3600) return
|
|
71
|
-
if (seconds < 86400) return
|
|
72
|
-
return
|
|
61
|
+
if (seconds < 60) return text("secondsAgo", seconds);
|
|
62
|
+
if (seconds < 3600) return text("minutesAgo", Math.floor(seconds / 60));
|
|
63
|
+
if (seconds < 86400) return text("hoursAgo", Math.floor(seconds / 3600));
|
|
64
|
+
return text("daysAgo", Math.floor(seconds / 86400));
|
|
73
65
|
};
|
|
74
|
-
const relative = new Intl.RelativeTimeFormat(
|
|
66
|
+
const relative = () => cachedFormat("relative", (tag) => new Intl.RelativeTimeFormat(tag, { numeric: "auto" }));
|
|
75
67
|
const units = [
|
|
76
68
|
["year", 31536e3],
|
|
77
69
|
["month", 2592e3],
|
|
@@ -83,8 +75,8 @@ const units = [
|
|
|
83
75
|
const formatRelativeTime = (seconds) => {
|
|
84
76
|
const away = Math.abs(seconds);
|
|
85
77
|
const [unit, size] = units.find(([, size]) => away >= size) ?? ["second", 1];
|
|
86
|
-
if (unit === "second" && away < 45) return "
|
|
87
|
-
return relative.format(-Math.sign(seconds) * Math.floor(away / size), unit);
|
|
78
|
+
if (unit === "second" && away < 45) return text("justNow");
|
|
79
|
+
return relative().format(-Math.sign(seconds) * Math.floor(away / size), unit);
|
|
88
80
|
};
|
|
89
81
|
//#endregion
|
|
90
82
|
export { formatAgo, formatDate, formatDateTime, formatDayRange, formatDayShort, formatMonth, formatRelativeTime, formatTime, formatWeekday, formatWeekdayDate };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { formatTag } from "../locale/active-locale.js";
|
|
2
|
+
//#region src/format/intl-cache.ts
|
|
3
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4
|
+
/** One `Intl` formatter per language tag and `key`, made with `make` for the active locale's tag the first time. */
|
|
5
|
+
const cachedFormat = (key, make) => {
|
|
6
|
+
const tag = formatTag();
|
|
7
|
+
const id = `${tag}|${key}`;
|
|
8
|
+
if (!cache.has(id)) cache.set(id, make(tag));
|
|
9
|
+
return cache.get(id);
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { cachedFormat };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineMessages } from "../locale/messages.js";
|
|
2
|
+
//#region src/format/messages.ts
|
|
3
|
+
const text = defineMessages({
|
|
4
|
+
en: {
|
|
5
|
+
rows: (count) => `${count} rows`,
|
|
6
|
+
aboutRows: (count) => `about ${count} rows`,
|
|
7
|
+
secondsAgo: (count) => `${count} s ago`,
|
|
8
|
+
minutesAgo: (count) => `${count} min ago`,
|
|
9
|
+
hoursAgo: (count) => `${count} h ago`,
|
|
10
|
+
daysAgo: (count) => `${count} d ago`,
|
|
11
|
+
justNow: "just now"
|
|
12
|
+
},
|
|
13
|
+
nl: {
|
|
14
|
+
rows: (count) => `${count} rijen`,
|
|
15
|
+
aboutRows: (count) => `ongeveer ${count} rijen`,
|
|
16
|
+
secondsAgo: (count) => `${count} s geleden`,
|
|
17
|
+
minutesAgo: (count) => `${count} min geleden`,
|
|
18
|
+
hoursAgo: (count) => `${count} u geleden`,
|
|
19
|
+
daysAgo: (count) => `${count} d geleden`,
|
|
20
|
+
justNow: "zojuist"
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
//#endregion
|
|
24
|
+
export { text };
|
package/dist/format/money.js
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
|
+
import { cachedFormat } from "./intl-cache.js";
|
|
1
2
|
//#region src/format/money.ts
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
...decimals !== void 0 && {
|
|
11
|
-
minimumFractionDigits: decimals,
|
|
12
|
-
maximumFractionDigits: decimals
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
formatters.set(key, created);
|
|
16
|
-
return created;
|
|
17
|
-
};
|
|
3
|
+
const formatterFor = (currency, decimals) => cachedFormat(`money:${currency}:${decimals ?? ""}`, (tag) => new Intl.NumberFormat(tag, {
|
|
4
|
+
style: "currency",
|
|
5
|
+
currency,
|
|
6
|
+
...decimals !== void 0 && {
|
|
7
|
+
minimumFractionDigits: decimals,
|
|
8
|
+
maximumFractionDigits: decimals
|
|
9
|
+
}
|
|
10
|
+
}));
|
|
18
11
|
/** An amount in cents in the currency, with its usual decimals or `decimals` of them. */
|
|
19
12
|
const formatMoney = (cents, currency = "EUR", decimals) => formatterFor(currency, decimals).format(cents / 100);
|
|
20
13
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { formatTag } from "../locale/active-locale.js";
|
|
1
2
|
//#region src/format/number-text.ts
|
|
2
|
-
/** The decimal separator `locale` writes, the
|
|
3
|
-
const localeDecimal = (locale) => new Intl.NumberFormat(locale).formatToParts(1.5).find((part) => part.type === "decimal")?.value === "," ? "," : ".";
|
|
3
|
+
/** The decimal separator `locale` writes, the screens' unless given: `,` for nl-NL and de-DE, `.` for en-GB. */
|
|
4
|
+
const localeDecimal = (locale = formatTag()) => new Intl.NumberFormat(locale).formatToParts(1.5).find((part) => part.type === "decimal")?.value === "," ? "," : ".";
|
|
4
5
|
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
6
|
/**
|
|
6
7
|
* A number written as text, as a plain decimal (`-1234.5`): digits grouped by thousands with the other separator or
|
package/dist/format/number.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { cachedFormat } from "./intl-cache.js";
|
|
2
|
+
import { text } from "./messages.js";
|
|
1
3
|
//#region src/format/number.ts
|
|
2
|
-
const grouped = new Intl.NumberFormat(
|
|
3
|
-
const formatInt = (value) => grouped.format(value);
|
|
4
|
-
const formatSigned = (value) => value > 0 ? `+${grouped.format(value)}` : grouped.format(value).replace("-", "−");
|
|
4
|
+
const grouped = () => cachedFormat("grouped", (tag) => new Intl.NumberFormat(tag));
|
|
5
|
+
const formatInt = (value) => grouped().format(value);
|
|
6
|
+
const formatSigned = (value) => value > 0 ? `+${grouped().format(value)}` : grouped().format(value).replace("-", "−");
|
|
5
7
|
const formatPercent = (value) => `${value}%`;
|
|
6
8
|
const formatApproxRows = (count) => {
|
|
7
|
-
if (count < 1e4) return
|
|
9
|
+
if (count < 1e4) return text("rows", formatInt(count));
|
|
8
10
|
const magnitude = 10 ** (Math.floor(Math.log10(count)) - 3);
|
|
9
|
-
return
|
|
11
|
+
return text("aboutRows", formatInt(Math.round(count / magnitude) * magnitude));
|
|
10
12
|
};
|
|
11
13
|
//#endregion
|
|
12
14
|
export { formatApproxRows, formatInt, formatPercent, formatSigned };
|
package/dist/format/zone.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cachedFormat } from "./intl-cache.js";
|
|
1
2
|
//#region src/format/zone.ts
|
|
2
3
|
/** The viewer's IANA time zone, such as `Europe/Amsterdam`. */
|
|
3
4
|
const viewerZone = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -47,15 +48,12 @@ const instantAt = (wall, zone) => {
|
|
|
47
48
|
};
|
|
48
49
|
/** The instant `day` (`YYYY-MM-DD`) starts in `zone`: its local midnight. */
|
|
49
50
|
const startOfDayIn = (day, zone) => instantAt(Date.parse(`${day}T00:00:00Z`), zone);
|
|
50
|
-
const zoneNames = /* @__PURE__ */ new Map();
|
|
51
51
|
/** The zone a time is shown in, as its hover label says: "Europe/Amsterdam (GMT+2)", or "UTC". */
|
|
52
52
|
const zoneLabel = (ms, zone) => {
|
|
53
|
-
const
|
|
53
|
+
const name = cachedFormat(`zoneName:${zone}`, (tag) => new Intl.DateTimeFormat(tag, {
|
|
54
54
|
timeZone: zone,
|
|
55
55
|
timeZoneName: "shortOffset"
|
|
56
|
-
});
|
|
57
|
-
zoneNames.set(zone, known);
|
|
58
|
-
const name = known.formatToParts(ms).find((part) => part.type === "timeZoneName")?.value ?? zone;
|
|
56
|
+
})).formatToParts(ms).find((part) => part.type === "timeZoneName")?.value ?? zone;
|
|
59
57
|
return zone === "UTC" || zone === "Etc/UTC" ? "UTC" : `${zone} (${name})`;
|
|
60
58
|
};
|
|
61
59
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../locale/active-locale.js";
|
|
1
2
|
import { Button } from "../primitives/button.js";
|
|
2
3
|
import { SectionError } from "../account/account-section.js";
|
|
3
4
|
import { useAction } from "../organizations/use-action.js";
|
|
@@ -26,7 +27,7 @@ const PendingInvitationRow = ({ email, gives, expiresAt, onResend, onRevoke }) =
|
|
|
26
27
|
children: [
|
|
27
28
|
gives,
|
|
28
29
|
" · ",
|
|
29
|
-
expired ? "Expired" : `Until ${new Date(expiresAt).toLocaleDateString()}`
|
|
30
|
+
expired ? "Expired" : `Until ${new Date(expiresAt).toLocaleDateString(formatTag())}`
|
|
30
31
|
]
|
|
31
32
|
})]
|
|
32
33
|
}),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../locale/active-locale.js";
|
|
1
2
|
import { viewerZone, zoneLabel } from "../format/zone.js";
|
|
2
3
|
import { formatDate, formatDateTime, formatRelativeTime } from "../format/date.js";
|
|
3
4
|
import { fileShown } from "./file-values.js";
|
|
@@ -22,7 +23,7 @@ const displayValue = (field, value, hints = {}, zone = viewerZone(), now = Date.
|
|
|
22
23
|
case "decimal": {
|
|
23
24
|
const text = hints.decimals === void 0 ? String(value) : Number(value).toFixed(hints.decimals);
|
|
24
25
|
if (hints.format === "percent") return `${Number(value)}%`;
|
|
25
|
-
return affixed(Number(text).toLocaleString(
|
|
26
|
+
return affixed(Number(text).toLocaleString(formatTag(), {
|
|
26
27
|
minimumFractionDigits: hints.decimals ?? 0,
|
|
27
28
|
maximumFractionDigits: hints.decimals ?? 20
|
|
28
29
|
}), hints);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { pickLocale } from "@protobase/schema/internal";
|
|
2
|
+
//#region src/locale/active-locale.ts
|
|
3
|
+
let fallback = "en";
|
|
4
|
+
let app;
|
|
5
|
+
/** The language the screens are in now. */
|
|
6
|
+
const activeLocale = () => app ?? fallback;
|
|
7
|
+
/** The language the screens are in when the app sets none: the browser's, or the one the app was given. */
|
|
8
|
+
const setFallbackLocale = (locale) => {
|
|
9
|
+
fallback = locale;
|
|
10
|
+
};
|
|
11
|
+
/** The language the app sets for everyone, from its `/meta`; undefined when it sets none. */
|
|
12
|
+
const setAppLocale = (locale) => {
|
|
13
|
+
app = locale;
|
|
14
|
+
};
|
|
15
|
+
/** The browser's language when the screens come in it, else English. */
|
|
16
|
+
const browserLocale = (languages = globalThis.navigator?.languages ?? []) => pickLocale(languages);
|
|
17
|
+
const formatTags = {
|
|
18
|
+
en: "en-GB",
|
|
19
|
+
nl: "nl-NL"
|
|
20
|
+
};
|
|
21
|
+
/** The language tag `Intl` formats numbers and dates with, for the active locale. */
|
|
22
|
+
const formatTag = () => formatTags[activeLocale()];
|
|
23
|
+
//#endregion
|
|
24
|
+
export { activeLocale, browserLocale, formatTag, setAppLocale, setFallbackLocale };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { activeLocale, setAppLocale } from "./active-locale.js";
|
|
2
|
+
import { Fragment, useEffect } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/locale/app-locale.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Puts the screens below in the language the app sets for everyone, from its `/meta`, or in the fallback when it sets
|
|
7
|
+
* none; draws them anew when that changes, and tells the page which language it is in.
|
|
8
|
+
*/
|
|
9
|
+
const AppLocale = ({ locale, children }) => {
|
|
10
|
+
setAppLocale(locale);
|
|
11
|
+
const active = activeLocale();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
document.documentElement.lang = active;
|
|
14
|
+
}, [active]);
|
|
15
|
+
return /* @__PURE__ */ jsx(Fragment, { children }, active);
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { AppLocale };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { activeLocale } from "./active-locale.js";
|
|
2
|
+
//#region src/locale/messages.ts
|
|
3
|
+
/**
|
|
4
|
+
* An area's built-in texts in every language the screens come in, keyed by id: the lookup returns the one for the
|
|
5
|
+
* active locale, `text('search')` or `text('rows', 3)`. Dutch must translate every English text, which the types check.
|
|
6
|
+
*/
|
|
7
|
+
const defineMessages = (catalogue) => (id, ...values) => {
|
|
8
|
+
const message = catalogue[activeLocale()][id];
|
|
9
|
+
return typeof message === "function" ? message(...values) : message;
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { defineMessages };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../locale/active-locale.js";
|
|
1
2
|
import { Input } from "../primitives/input.js";
|
|
2
3
|
import { PageHeader } from "../app-shell/page-header.js";
|
|
3
4
|
import { useAuth } from "../auth/auth-provider.js";
|
|
@@ -85,7 +86,7 @@ const YourInvitations = () => {
|
|
|
85
86
|
invitation.appRoles.map((name) => roleLabel(roles, name)).join(", ") || "no app roles",
|
|
86
87
|
/* @__PURE__ */ jsxs("span", {
|
|
87
88
|
className: "block text-xs text-muted-foreground",
|
|
88
|
-
children: ["Until ", new Date(invitation.expiresAt).toLocaleDateString()]
|
|
89
|
+
children: ["Until ", new Date(invitation.expiresAt).toLocaleDateString(formatTag())]
|
|
89
90
|
})
|
|
90
91
|
]
|
|
91
92
|
}, invitation.id))
|
package/dist/package.js
CHANGED