diff --git a/src/common/datetime/format_duration.ts b/src/common/datetime/format_duration.ts index c530a20d4aba..9279a8b0ce47 100644 --- a/src/common/datetime/format_duration.ts +++ b/src/common/datetime/format_duration.ts @@ -1,5 +1,6 @@ import type { HaDurationData } from "../../components/ha-duration-input"; import type { FrontendLocaleData } from "../../data/translation"; +import { formatListWithAnds } from "../string/format-list"; const leftPad = (num: number) => (num < 10 ? `0${num}` : num); @@ -42,3 +43,62 @@ export const formatDuration = ( } return null; }; + +export const formatDurationLong = ( + locale: FrontendLocaleData, + duration: HaDurationData +) => { + const d = duration.days || 0; + const h = duration.hours || 0; + const m = duration.minutes || 0; + const s = duration.seconds || 0; + const ms = duration.milliseconds || 0; + + const parts: string[] = []; + if (d > 0) { + parts.push( + Intl.NumberFormat(locale.language, { + style: "unit", + unit: "day", + unitDisplay: "long", + }).format(d) + ); + } + if (h > 0) { + parts.push( + Intl.NumberFormat(locale.language, { + style: "unit", + unit: "hour", + unitDisplay: "long", + }).format(h) + ); + } + if (m > 0) { + parts.push( + Intl.NumberFormat(locale.language, { + style: "unit", + unit: "minute", + unitDisplay: "long", + }).format(m) + ); + } + if (s > 0) { + parts.push( + Intl.NumberFormat(locale.language, { + style: "unit", + unit: "second", + unitDisplay: "long", + }).format(s) + ); + } + if (ms > 0) { + parts.push( + Intl.NumberFormat(locale.language, { + style: "unit", + unit: "millisecond", + unitDisplay: "long", + }).format(ms) + ); + } + return formatListWithAnds(locale, parts); +}; diff --git a/src/data/automation_i18n.ts b/src/data/automation_i18n.ts index 5f8b9eb95c0c..2651f71246e9 100644 --- a/src/data/automation_i18n.ts +++ b/src/data/automation_i18n.ts @@ -1,6 +1,9 @@ import type { HassConfig } from "home-assistant-js-websocket"; import { ensureArray } from "../common/array/ensure-array"; -import { formatDuration } from "../common/datetime/format_duration"; +import { + formatDuration, + formatDurationLong, +} from "../common/datetime/format_duration"; import { formatTime, formatTimeWithSeconds, @@ -720,6 +723,38 @@ const tryDescribeTrigger = ( }`; } + // Calendar Trigger + if (trigger.trigger === "calendar") { + const calendarEntity = hass.states[trigger.entity_id] + ? computeStateName(hass.states[trigger.entity_id]) + : trigger.entity_id; + + let offsetChoice = trigger.offset.startsWith("-") ? "before" : "after"; + let offset: string | string[] = trigger.offset.startsWith("-") + ? trigger.offset.substring(1).split(":") + : trigger.offset.split(":"); + const duration = { + hours: offset.length > 0 ? +offset[0] : 0, + minutes: offset.length > 1 ? +offset[1] : 0, + seconds: offset.length > 2 ? +offset[2] : 0, + }; + offset = formatDurationLong(hass.locale, duration); + if (offset === "") { + offsetChoice = "other"; + } + + return hass.localize( + `${triggerTranslationBaseKey}.calendar.description.full`, + { + eventChoice: trigger.event, + offsetChoice: offsetChoice, + offset: offset, + hasCalendar: trigger.entity_id ? "true" : "false", + calendar: calendarEntity, + } + ); + } + return ( hass.localize( `ui.panel.config.automation.editor.triggers.type.${trigger.trigger}.label` diff --git a/src/translations/en.json b/src/translations/en.json index 7b7a7c72daf8..cda8a005c5d9 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2995,7 +2995,8 @@ "before": "Before", "after": "After", "description": { - "picker": "When a calendar event starts or ends." + "picker": "When a calendar event starts or ends.", + "full": "When{offsetChoice, select, \n before { it's {offset} before}\n after { it's {offset} after}\n other {}\n} a calendar event{eventChoice, select, \n start { starts}\n end { ends}\n other { starts or ends}\n}{hasCalendar, select, \n true { in {calendar}}\n other {}\n}" } }, "device": {