diff --git a/src/mixins/lang.js b/src/mixins/lang.js index 9061e7d3d..0fff8cdc8 100644 --- a/src/mixins/lang.js +++ b/src/mixins/lang.js @@ -1,5 +1,5 @@ import { currentLocale } from "../i18n"; -import { setPageLocale } from "../util-frontend"; +import { setPageLocale, relativeTimeFormatter } from "../util-frontend"; const langModules = import.meta.glob("../lang/*.json"); export default { @@ -28,11 +28,13 @@ export default { * @returns {Promise} */ async changeLang(lang) { - let message = (await langModules["../lang/" + lang + ".json"]()).default; + let message = (await langModules["../lang/" + lang + ".json"]()) + .default; this.$i18n.setLocaleMessage(lang, message); this.$i18n.locale = lang; localStorage.locale = lang; setPageLocale(); - } - } + relativeTimeFormatter.updateLocale(lang); + }, + }, }; diff --git a/src/pages/Details.vue b/src/pages/Details.vue index 17d32365c..995d9f2e4 100644 --- a/src/pages/Details.vue +++ b/src/pages/Details.vue @@ -76,7 +76,7 @@
- {{ $t("checkEverySecond", [ monitor.interval ]) }} + {{ $t("checkEverySecond", [ monitor.interval ]) }} ({{ secondsToHumanReadableFormat(monitor.interval) }})
{{ status.text }} @@ -285,7 +285,7 @@ import Tag from "../components/Tag.vue"; import CertificateInfo from "../components/CertificateInfo.vue"; import { getMonitorRelativeURL } from "../util.ts"; import { URL } from "whatwg-url"; -import { getResBaseURL } from "../util-frontend"; +import { getResBaseURL, relativeTimeFormatter } from "../util-frontend"; import { highlight, languages } from "prismjs/components/prism-core"; import "prismjs/components/prism-clike"; import "prismjs/components/prism-javascript"; @@ -656,7 +656,12 @@ export default { .replace("https://example.com/api/push/key?status=up&msg=OK&ping=", this.pushURL); this.pushMonitor.code = code; }); + }, + + secondsToHumanReadableFormat(seconds) { + return relativeTimeFormatter.secondsToHumanReadableFormat(seconds); } + }, }; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 677210c45..50b0c08d0 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -577,6 +577,9 @@
+
+ {{ monitor.humanReadableInterval }} +
@@ -1120,7 +1123,7 @@ import RemoteBrowserDialog from "../components/RemoteBrowserDialog.vue"; import ProxyDialog from "../components/ProxyDialog.vue"; import TagsManager from "../components/TagsManager.vue"; import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND, sleep } from "../util.ts"; -import { hostNameRegexPattern } from "../util-frontend"; +import { hostNameRegexPattern, relativeTimeFormatter } from "../util-frontend"; import HiddenInput from "../components/HiddenInput.vue"; import EditMonitorConditions from "../components/EditMonitorConditions.vue"; import { version } from "../../package.json"; @@ -1137,6 +1140,7 @@ const monitorDefaults = { url: "https://", method: "GET", interval: 60, + humanReadableInterval: relativeTimeFormatter.secondsToHumanReadableFormat(60), retryInterval: 60, resendInterval: 0, maxretries: 0, @@ -1522,6 +1526,8 @@ message HealthCheckResponse { if (this.monitor.retryInterval === oldValue) { this.monitor.retryInterval = value; } + // Converting monitor.interval to human readable format. + this.monitor.humanReadableInterval = relativeTimeFormatter.secondsToHumanReadableFormat(value); }, "monitor.timeout"(value, oldValue) { diff --git a/src/util-frontend.js b/src/util-frontend.js index d9bf378e5..a3dc4c3ac 100644 --- a/src/util-frontend.js +++ b/src/util-frontend.js @@ -213,3 +213,78 @@ export function getToastErrorTimeout() { return errorTimeout; } + +class RelativeTimeFormatter { + /** + * Default locale and options for Relative Time Formatter + */ + constructor() { + this.options = { numeric: "auto" }; + this.instance = new Intl.RelativeTimeFormat(currentLocale(), this.options); + } + + /** + * Method to update the instance locale and options + * @param {string} locale Localization identifier (e.g., "en", "ar-sy") to update the instance with. + * @returns {void} No return value. + */ + updateLocale(locale) { + this.instance = new Intl.RelativeTimeFormat(locale, this.options); + } + + /** + * Method to convert seconds into Human readable format + * @param {number} seconds Receive value in seconds. + * @returns {string} String converted to Days Mins Seconds Format + */ + secondsToHumanReadableFormat(seconds) { + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + const minutes = Math.floor(((seconds % 86400) % 3600) / 60); + const secs = ((seconds % 86400) % 3600) % 60; + const parts = []; + /** + * Build the formatted string from parts + * 1. Get the relative time formatted parts from the instance. + * 2. Filter out the relevant parts literal (unit of time) or integer (value). + * 3. Map out the required values. + * @param {number} value Receives value in seconds. + * @param {string} unitOfTime Expected unit of time after conversion. + * @returns {void} + */ + const toFormattedPart = (value, unitOfTime) => { + const partsArray = this.instance.formatToParts(value, unitOfTime); + const filteredParts = partsArray + .filter( + (part, index) => + (part.type === "literal" || part.type === "integer") && + index > 0 + ) + .map((part) => part.value); + + const formattedString = filteredParts.join("").trim(); + parts.push(formattedString); + }; + + if (days > 0) { + toFormattedPart(days, "days"); + } + if (hours > 0) { + toFormattedPart(hours, "hour"); + } + if (minutes > 0) { + toFormattedPart(minutes, "minute"); + } + if (secs > 0) { + toFormattedPart(secs, "second"); + } + + if (parts.length > 0) { + return `${parts.join(" ")}`; + } + return this.instance.format(0, "second"); // Handle case for 0 seconds + } +} + +export const relativeTimeFormatter = new RelativeTimeFormatter(); +