diff --git a/gallery/src/data/traces/basic_trace.ts b/gallery/src/data/traces/basic_trace.ts
index 8fbd720e12..5113d6dd5f 100644
--- a/gallery/src/data/traces/basic_trace.ts
+++ b/gallery/src/data/traces/basic_trace.ts
@@ -17,6 +17,7 @@ export const basicTrace: DemoTrace = {
{
path: "trigger/0",
timestamp: "2021-03-25T04:36:51.223693+00:00",
+ changed_variables: {},
},
],
"condition/0": [
diff --git a/gallery/src/data/traces/motion-light-trace.ts b/gallery/src/data/traces/motion-light-trace.ts
index fa566e5556..0963a463ee 100644
--- a/gallery/src/data/traces/motion-light-trace.ts
+++ b/gallery/src/data/traces/motion-light-trace.ts
@@ -17,6 +17,7 @@ export const motionLightTrace: DemoTrace = {
{
path: "trigger/0",
timestamp: "2021-03-25T04:36:51.223693+00:00",
+ changed_variables: {},
},
],
"action/0": [
diff --git a/gallery/src/pages/automation/trace-timeline.ts b/gallery/src/pages/automation/trace-timeline.ts
index a9a0e1a9d5..4f5692b7da 100644
--- a/gallery/src/pages/automation/trace-timeline.ts
+++ b/gallery/src/pages/automation/trace-timeline.ts
@@ -55,6 +55,7 @@ export class DemoAutomationTraceTimeline extends LitElement {
super.firstUpdated(changedProps);
const hass = provideHass(this);
hass.updateTranslations(null, "en");
+ hass.updateTranslations("config", "en");
}
static get styles() {
diff --git a/gallery/src/pages/automation/trace.ts b/gallery/src/pages/automation/trace.ts
index 0092915510..4d346095f8 100644
--- a/gallery/src/pages/automation/trace.ts
+++ b/gallery/src/pages/automation/trace.ts
@@ -60,6 +60,7 @@ export class DemoAutomationTrace extends LitElement {
super.firstUpdated(changedProps);
const hass = provideHass(this);
hass.updateTranslations(null, "en");
+ hass.updateTranslations("config", "en");
}
static get styles() {
diff --git a/src/components/trace/hat-trace-timeline.ts b/src/components/trace/hat-trace-timeline.ts
index 2396c65879..78eb1ec8e1 100644
--- a/src/components/trace/hat-trace-timeline.ts
+++ b/src/components/trace/hat-trace-timeline.ts
@@ -153,7 +153,7 @@ class LogbookRenderer {
const parts: TemplateResult[] = [];
- let i;
+ let i: number;
for (
i = 0;
@@ -232,7 +232,7 @@ class ActionRenderer {
const value = this._getItem(index);
if (renderAllIterations) {
- let i;
+ let i: number = 0;
value.forEach((item) => {
i = this._renderIteration(index, item, actionType);
});
@@ -270,7 +270,12 @@ class ActionRenderer {
} catch (err: any) {
this._renderEntry(
path,
- `Unable to extract path ${path}. Download trace and report as bug`
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.path_error",
+ {
+ path: path,
+ }
+ )
);
return index + 1;
}
@@ -324,20 +329,22 @@ class ActionRenderer {
private _handleTrigger(index: number, triggerStep: TriggerTraceStep): number {
this._renderEntry(
triggerStep.path,
- `${
- triggerStep.changed_variables.trigger.alias
- ? `${triggerStep.changed_variables.trigger.alias} triggered`
- : "Triggered"
- } ${
- triggerStep.path === "trigger"
- ? "manually"
- : `by the ${this.trace.trigger}`
- } at
- ${formatDateTimeWithSeconds(
- new Date(triggerStep.timestamp),
- this.hass.locale,
- this.hass.config
- )}`,
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.triggered_by",
+ {
+ triggeredBy: triggerStep.changed_variables.trigger?.alias
+ ? "alias"
+ : "other",
+ alias: triggerStep.changed_variables.trigger?.alias,
+ triggeredPath: triggerStep.path === "trigger" ? "manual" : "trigger",
+ trigger: this.trace.trigger,
+ time: formatDateTimeWithSeconds(
+ new Date(triggerStep.timestamp),
+ this.hass.locale,
+ this.hass.config
+ ),
+ }
+ ),
mdiCircle
);
return index + 1;
@@ -367,12 +374,17 @@ class ActionRenderer {
this.keys[index]
) as ChooseAction;
const disabled = chooseConfig.enabled === false;
- const name = chooseConfig.alias || "Choose";
+ const name =
+ chooseConfig.alias ||
+ this.hass.localize("ui.panel.config.automation.trace.messages.choose");
if (defaultExecuted) {
this._renderEntry(
choosePath,
- `${name}: Default action executed`,
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.default_action_executed",
+ { name: name }
+ ),
undefined,
disabled
);
@@ -385,8 +397,17 @@ class ActionRenderer {
`${this.keys[index]}/choose/${chooseTrace.result.choice}`
) as ChooseActionChoice | undefined;
const choiceName = choiceConfig
- ? `${choiceConfig.alias || `Option ${choiceNumeric}`} executed`
- : `Error: ${chooseTrace.error}`;
+ ? `${
+ choiceConfig.alias ||
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.option_executed",
+ { option: choiceNumeric }
+ )
+ }`
+ : this.hass.localize(
+ "ui.panel.config.automation.trace.messages.error",
+ { error: chooseTrace.error }
+ );
this._renderEntry(
choosePath,
`${name}: ${choiceName}`,
@@ -396,13 +417,16 @@ class ActionRenderer {
} else {
this._renderEntry(
choosePath,
- `${name}: No action taken`,
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.no_action_executed",
+ { name: name }
+ ),
undefined,
disabled
);
}
- let i;
+ let i: number;
// Skip over conditions
for (i = index + 1; i < this.keys.length; i++) {
@@ -479,26 +503,38 @@ class ActionRenderer {
const ifTrace = this._getItem(index)[0] as IfActionTraceStep;
const ifConfig = this._getDataFromPath(this.keys[index]) as IfAction;
const disabled = ifConfig.enabled === false;
- const name = ifConfig.alias || "If";
+ const name =
+ ifConfig.alias ||
+ this.hass.localize("ui.panel.config.automation.trace.messages.if");
if (ifTrace.result?.choice) {
const choiceConfig = this._getDataFromPath(
`${this.keys[index]}/${ifTrace.result.choice}/`
) as any;
const choiceName = choiceConfig
- ? `${choiceConfig.alias || `${ifTrace.result.choice} action executed`}`
- : `Error: ${ifTrace.error}`;
+ ? choiceConfig.alias ||
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.action_executed",
+ { action: ifTrace.result.choice }
+ )
+ : this.hass.localize(
+ "ui.panel.config.automation.trace.messages.error",
+ { error: ifTrace.error }
+ );
this._renderEntry(ifPath, `${name}: ${choiceName}`, undefined, disabled);
} else {
this._renderEntry(
ifPath,
- `${name}: No action taken`,
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.no_action_executed",
+ { name: name }
+ ),
undefined,
disabled
);
}
- let i;
+ let i: number;
// Skip over conditions
for (i = index + 1; i < this.keys.length; i++) {
@@ -534,7 +570,11 @@ class ActionRenderer {
const disabled = parallelConfig.enabled === false;
- const name = parallelConfig.alias || "Execute in parallel";
+ const name =
+ parallelConfig.alias ||
+ this.hass.localize(
+ "ui.panel.config.automation.trace.messages.execute_in_parallel"
+ );
this._renderEntry(parallelPath, name, undefined, disabled);
@@ -564,7 +604,11 @@ class ActionRenderer {
this.entries.push(html`
${description}${disabled
- ? html` (disabled)`
+ ? html`
+ ${this.hass.localize(
+ "ui.panel.config.automation.trace.messages.disabled"
+ )}`
: ""}
`);
@@ -636,13 +680,12 @@ export class HaAutomationTracer extends LitElement {
this.hass.locale,
this.hass.config
);
- const renderRuntime = () => `(runtime:
- ${(
+ const renderRuntime = () =>
+ (
(new Date(this.trace!.timestamp.finish!).getTime() -
new Date(this.trace!.timestamp.start).getTime()) /
1000
- ).toFixed(2)}
- seconds)`;
+ ).toFixed(2);
let entry: {
description: TemplateResult | string;
@@ -652,57 +695,90 @@ export class HaAutomationTracer extends LitElement {
if (this.trace.state === "running") {
entry = {
- description: "Still running",
+ description: this.hass.localize(
+ "ui.panel.config.automation.trace.messages.still_running"
+ ),
icon: mdiProgressClock,
};
} else if (this.trace.state === "debugged") {
entry = {
- description: "Debugged",
+ description: this.hass.localize(
+ "ui.panel.config.automation.trace.messages.debugged"
+ ),
icon: mdiProgressWrench,
};
} else if (this.trace.script_execution === "finished") {
entry = {
- description: `Finished at ${renderFinishedAt()} ${renderRuntime()}`,
+ description: this.hass.localize(
+ "ui.panel.config.automation.trace.messages.finished",
+ {
+ time: renderFinishedAt(),
+ executiontime: renderRuntime(),
+ }
+ ),
icon: mdiCircle,
};
} else if (this.trace.script_execution === "aborted") {
entry = {
- description: `Aborted at ${renderFinishedAt()} ${renderRuntime()}`,
+ description: this.hass.localize(
+ "ui.panel.config.automation.trace.messages.aborted",
+ {
+ time: renderFinishedAt(),
+ executiontime: renderRuntime(),
+ }
+ ),
icon: mdiAlertCircle,
};
} else if (this.trace.script_execution === "cancelled") {
entry = {
- description: `Cancelled at ${renderFinishedAt()} ${renderRuntime()}`,
+ description: this.hass.localize(
+ "ui.panel.config.automation.trace.messages.cancelled",
+ {
+ time: renderFinishedAt(),
+ executiontime: renderRuntime(),
+ }
+ ),
icon: mdiAlertCircle,
};
} else {
- let reason: string;
+ let message:
+ | "stopped_failed_conditions"
+ | "stopped_failed_single"
+ | "stopped_failed_max_runs"
+ | "stopped_error"
+ | "stopped_unknown_reason";
let isError = false;
let extra: TemplateResult | undefined;
switch (this.trace.script_execution) {
case "failed_conditions":
- reason = "a condition failed";
+ message = "stopped_failed_conditions";
break;
case "failed_single":
- reason = "only a single execution is allowed";
+ message = "stopped_failed_single";
break;
case "failed_max_runs":
- reason = "maximum number of parallel runs reached";
+ message = "stopped_failed_max_runs";
break;
case "error":
- reason = "an error was encountered";
isError = true;
+ message = "stopped_error";
extra = html`
${this.trace.error!}`;
break;
default:
- reason = `of unknown reason "${this.trace.script_execution}"`;
isError = true;
+ message = "stopped_unknown_reason";
}
entry = {
- description: html`Stopped because ${reason} at ${renderFinishedAt()}
- ${renderRuntime()}${extra || ""}`,
+ description: html`${this.hass.localize(
+ `ui.panel.config.automation.trace.messages.${message}`,
+ {
+ time: renderFinishedAt(),
+ executiontime: renderRuntime(),
+ }
+ )}
+ ${extra || ""}`,
icon: mdiAlertCircle,
className: isError ? "error" : undefined,
};
diff --git a/src/translations/en.json b/src/translations/en.json
index c8c1b42c79..daa0884853 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -3195,6 +3195,29 @@
"no_logbook_entries": "No Logbook entries found for this step.",
"no_variables_changed": "No variables changed",
"unable_to_find_config": "Unable to find config"
+ },
+ "messages": {
+ "no_action_executed": "{name}: No action executed",
+ "default_action_executed": "{name}: Default action executed",
+ "action_executed": "{action} action executed",
+ "option_executed": "Option {option} executed",
+ "error": "Error: {error}",
+ "execute_in_parallel": "Execute in parallel",
+ "if": "If",
+ "choose": "Choose",
+ "still_running": "Still running",
+ "debugged": "Debugged",
+ "finished": "Finished at {time} (runtime: {executiontime} seconds)",
+ "aborted": "Aborted at {time} (runtime: {executiontime} seconds)",
+ "cancelled": "Cancelled at {time} (runtime: {executiontime} seconds)",
+ "stopped_failed_conditions": "Stopped because a condition failed at {time} (runtime: {executiontime} seconds)",
+ "stopped_failed_single": "Stopped because only a single execution is allowed at {time} (runtime: {executiontime} seconds)",
+ "stopped_failed_max_runs": "Stopped because maximum number of parallel runs reached at {time} (runtime: {executiontime} seconds)",
+ "stopped_error": "Stopped because an error was encountered at {time} (runtime: {executiontime} seconds)",
+ "stopped_unknown_reason": "Stopped because of unknown reason {reason} at {time} (runtime: {executiontime} seconds)",
+ "disabled": "(disabled)",
+ "triggered_by": "{triggeredBy, select, \n alias {{alias} triggered}\n other {Triggered} \n} {triggeredPath, select, \n trigger {by the {trigger}}\n other {manually} \n} at {time}",
+ "path_error": "Unable to extract path {path}. Download trace and report as bug."
}
}
},