Add support for entity translation key (#14482)

This commit is contained in:
Paul Bottein 2022-12-01 12:53:44 +01:00 committed by GitHub
parent dff7f653b1
commit dfc461ce05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 150 additions and 47 deletions

View File

@ -307,7 +307,8 @@ export class DemoEntityState extends LitElement {
html`${computeStateDisplay(
hass.localize,
entry.stateObj,
hass.locale
hass.locale,
hass.entities
)}`,
},
device_class: {

View File

@ -1,10 +1,12 @@
import { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { EntityRegistryEntry } from "../../data/entity_registry";
import { FrontendLocaleData } from "../../data/translation";
import {
updateIsInstallingFromAttributes,
UPDATE_SUPPORT_PROGRESS,
} from "../../data/update";
import { HomeAssistant } from "../../types";
import { formatDuration, UNIT_TO_SECOND_CONVERT } from "../datetime/duration";
import { formatDate } from "../datetime/format_date";
import { formatDateTime } from "../datetime/format_date_time";
@ -23,11 +25,13 @@ export const computeStateDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
entities: HomeAssistant["entities"],
state?: string
): string =>
computeStateDisplayFromEntityAttributes(
localize,
locale,
entities,
stateObj.entity_id,
stateObj.attributes,
state !== undefined ? state : stateObj.state
@ -36,6 +40,7 @@ export const computeStateDisplay = (
export const computeStateDisplayFromEntityAttributes = (
localize: LocalizeFunc,
locale: FrontendLocaleData,
entities: HomeAssistant["entities"],
entityId: string,
attributes: any,
state: string
@ -194,7 +199,13 @@ export const computeStateDisplayFromEntityAttributes = (
: localize("ui.card.update.up_to_date");
}
const entity = entities[entityId] as EntityRegistryEntry | undefined;
return (
(entity?.translation_key &&
localize(
`component.${entity.platform}.entity.${domain}.${entity.translation_key}.state.${state}`
)) ||
// Return device class translation
(attributes.device_class &&
localize(

View File

@ -55,6 +55,7 @@ class HaEntityStatePicker extends LitElement {
this.hass.localize,
state,
this.hass.locale,
this.hass.entities,
key
)
: formatAttributeValue(this.hass, key),

View File

@ -158,7 +158,8 @@ export class HaStateLabelBadge extends LitElement {
: computeStateDisplay(
this.hass!.localize,
entityState,
this.hass!.locale
this.hass!.locale,
this.hass!.entities
);
}
}

View File

@ -85,7 +85,12 @@ class HaWaterHeaterState extends LocalizeMixin(PolymerElement) {
}
_localizeState(stateObj) {
return computeStateDisplay(this.hass.localize, stateObj, this.hass.locale);
return computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.entities
);
}
}
customElements.define("ha-water_heater-state", HaWaterHeaterState);

View File

@ -21,6 +21,7 @@ export interface EntityRegistryEntry {
has_entity_name: boolean;
original_name?: string;
unique_id: string;
translation_key?: string;
}
export interface ExtEntityRegistryEntry extends EntityRegistryEntry {

View File

@ -184,6 +184,7 @@ const equalState = (obj1: LineChartState, obj2: LineChartState) =>
const processTimelineEntity = (
localize: LocalizeFunc,
language: FrontendLocaleData,
entities: HomeAssistant["entities"],
entityId: string,
states: EntityHistoryState[],
current_state: HassEntity | undefined
@ -198,6 +199,7 @@ const processTimelineEntity = (
state_localize: computeStateDisplayFromEntityAttributes(
localize,
language,
entities,
entityId,
state.a || first.a,
state.s
@ -344,6 +346,7 @@ export const computeHistory = (
processTimelineEntity(
localize,
hass.locale,
hass.entities,
entityId,
stateInfo,
currentState

View File

@ -435,7 +435,13 @@ export const localizeStateMessage = (
`${LOGBOOK_LOCALIZE_PATH}.changed_to_state`,
"state",
stateObj
? computeStateDisplay(localize, stateObj, hass.locale, state)
? computeStateDisplay(
localize,
stateObj,
hass.locale,
hass.entities,
state
)
: state
);
};

View File

@ -90,7 +90,12 @@ export const computeDisplayTimer = (
}
if (stateObj.state === "idle" || timeRemaining === 0) {
return computeStateDisplay(hass.localize, stateObj, hass.locale);
return computeStateDisplay(
hass.localize,
stateObj,
hass.locale,
hass.entities
);
}
let display = secondsToDuration(timeRemaining || 0);
@ -99,7 +104,8 @@ export const computeDisplayTimer = (
display = `${display} (${computeStateDisplay(
hass.localize,
stateObj,
hass.locale
hass.locale,
hass.entities
)})`;
}

View File

@ -44,6 +44,7 @@ declare global {
export type TranslationCategory =
| "title"
| "state"
| "entity"
| "config"
| "config_panel"
| "options"

View File

@ -37,7 +37,8 @@ export class HuiConfiguratorNotificationItem extends LitElement {
>${computeStateDisplay(
this.hass.localize,
this.notification,
this.hass.locale
this.hass.locale,
this.hass.entities
)}</mwc-button
>
</notification-item-template>

View File

@ -307,7 +307,9 @@ export const provideHass = (
true
);
},
areas: {},
devices: {},
entities: {},
...overrideData,
};

View File

@ -137,6 +137,8 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
super.hassConnected();
// @ts-ignore
this._loadHassTranslations(this.hass!.language, "state");
// @ts-ignore
this._loadHassTranslations(this.hass!.language, "entity");
document.addEventListener(
"visibilitychange",

View File

@ -205,7 +205,8 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
${computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}
</span>`
: ""}

View File

@ -167,7 +167,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
: computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}</span
>${showUnit
? html`

View File

@ -335,7 +335,8 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
: computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass!.locale
this.hass!.locale,
this.hass!.entities
)}
</div>
`

View File

@ -160,7 +160,8 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
${computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}
</div>
`

View File

@ -121,7 +121,8 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
const entityState = computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
);
let footer: TemplateResult | string = "";

View File

@ -255,7 +255,8 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
title=${`${computeStateName(stateObj)} : ${computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass!.locale
this.hass!.locale,
this.hass!.entities
)}`}
>
<ha-state-icon
@ -277,7 +278,8 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
: computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass!.locale
this.hass!.locale,
this.hass!.entities
)}
</div>
`}

View File

@ -201,7 +201,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
return computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass!.locale
this.hass!.locale,
this.hass!.entities
);
}

View File

@ -221,7 +221,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
${computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}
</div>
<div class="name" .title=${name}>${name}</div>

View File

@ -83,7 +83,12 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
)}
>
${this._config.prefix}${!this._config.attribute
? computeStateDisplay(this.hass.localize, stateObj, this.hass.locale)
? computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.entities
)
: stateObj.attributes[this._config.attribute]}${this._config.suffix}
</div>
`;

View File

@ -69,7 +69,8 @@ class HuiGroupEntityRow extends LitElement implements LovelaceRow {
${computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}
</div>
`}

View File

@ -100,6 +100,7 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.entities,
stateObj.state
)}
</span>

View File

@ -193,7 +193,12 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
.hass=${this.hass}
.config=${this._config}
.secondaryText=${mediaDescription ||
computeStateDisplay(this.hass.localize, stateObj, this.hass.locale)}
computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.entities
)}
>
<div class="controls">
${supportsFeature(stateObj, SUPPORT_TURN_ON) &&

View File

@ -104,6 +104,7 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.entities,
stateObj.state
)}
</span>

View File

@ -83,7 +83,8 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
: computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}
</div>
</hui-generic-entity-row>

View File

@ -49,7 +49,12 @@ class HuiSimpleEntityRow extends LitElement implements LovelaceRow {
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
${computeStateDisplay(this.hass!.localize, stateObj, this.hass.locale)}
${computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass.locale,
this.hass.entities
)}
</hui-generic-entity-row>
`;
}

View File

@ -64,7 +64,8 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
${computeStateDisplay(
this.hass!.localize,
stateObj,
this.hass!.locale
this.hass!.locale,
this.hass!.entities
)}
</div>
`}

View File

@ -120,7 +120,8 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
? computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)
: html`
${formatNumber(

View File

@ -58,7 +58,12 @@ class StateCardConfigurator extends LocalizeMixin(PolymerElement) {
}
_localizeState(stateObj) {
return computeStateDisplay(this.hass.localize, stateObj, this.hass.locale);
return computeStateDisplay(
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.entities
);
}
}
customElements.define("state-card-configurator", StateCardConfigurator);

View File

@ -52,7 +52,8 @@ export class StateCardDisplay extends LitElement {
: computeStateDisplay(
this.hass!.localize,
this.stateObj,
this.hass.locale
this.hass.locale,
this.hass.entities
)}
</div>
</div>

View File

@ -165,6 +165,7 @@ class StateCardInputNumber extends mixinBehaviors(
this.hass.localize,
newVal,
this.hass.locale,
this.hass.entities,
newVal.state
),
mode: String(newVal.attributes.mode),

View File

@ -85,7 +85,12 @@ class StateCardMediaPlayer extends LocalizeMixin(PolymerElement) {
computePrimaryText(localize, playerObj) {
return (
playerObj.primaryTitle ||
computeStateDisplay(localize, playerObj.stateObj, this.hass.locale)
computeStateDisplay(
localize,
playerObj.stateObj,
this.hass.locale,
this.hass.entities
)
);
}
}

View File

@ -234,7 +234,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
category: Parameters<typeof getHassTranslations>[2],
integration?: Parameters<typeof getHassTranslations>[3],
configFlow?: Parameters<typeof getHassTranslations>[4],
force = false
force = true
): Promise<LocalizeFunc> {
if (
__BACKWARDS_COMPAT__ &&

View File

@ -31,7 +31,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"component.binary_sensor.state._.off"
);
});
@ -45,7 +45,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"component.binary_sensor.state.moisture.off"
);
});
@ -65,7 +65,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(altLocalize, stateObj, localeData),
computeStateDisplay(altLocalize, stateObj, localeData, {}),
"component.binary_sensor.state.invalid_device_class.off"
);
});
@ -79,7 +79,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"123 m"
);
});
@ -93,7 +93,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"1,234.5 m"
);
});
@ -107,7 +107,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"1,234.5"
);
});
@ -127,7 +127,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(altLocalize, stateObj, localeData),
computeStateDisplay(altLocalize, stateObj, localeData, {}),
"state.default.unknown"
);
});
@ -147,7 +147,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(altLocalize, stateObj, localeData),
computeStateDisplay(altLocalize, stateObj, localeData, {}),
"state.default.unavailable"
);
});
@ -165,7 +165,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
computeStateDisplay(altLocalize, stateObj, localeData),
computeStateDisplay(altLocalize, stateObj, localeData, {}),
"component.sensor.state._.custom_state"
);
});
@ -187,14 +187,14 @@ describe("computeStateDisplay", () => {
};
it("Uses am/pm time format", () => {
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"November 18, 2017 at 11:12 PM"
);
});
it("Uses 24h time format", () => {
localeData.time_format = TimeFormat.twenty_four;
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"November 18, 2017 at 23:12"
);
});
@ -216,7 +216,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"November 18, 2017"
);
});
@ -239,14 +239,14 @@ describe("computeStateDisplay", () => {
it("Uses am/pm time format", () => {
localeData.time_format = TimeFormat.am_pm;
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"11:12 PM"
);
});
it("Uses 24h time format", () => {
localeData.time_format = TimeFormat.twenty_four;
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData),
computeStateDisplay(localize, stateObj, localeData, {}),
"23:12"
);
});
@ -273,6 +273,7 @@ describe("computeStateDisplay", () => {
localize,
stateObj,
localeData,
{},
"2021-07-04 15:40:03"
),
"July 4, 2021 at 3:40 PM"
@ -285,6 +286,7 @@ describe("computeStateDisplay", () => {
localize,
stateObj,
localeData,
{},
"2021-07-04 15:40:03"
),
"July 4, 2021 at 15:40"
@ -308,7 +310,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData, "2021-07-04"),
computeStateDisplay(localize, stateObj, localeData, {}, "2021-07-04"),
"July 4, 2021"
);
});
@ -331,14 +333,14 @@ describe("computeStateDisplay", () => {
it("Uses am/pm time format", () => {
localeData.time_format = TimeFormat.am_pm;
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData, "17:05:07"),
computeStateDisplay(localize, stateObj, localeData, {}, "17:05:07"),
"5:05 PM"
);
});
it("Uses 24h time format", () => {
localeData.time_format = TimeFormat.twenty_four;
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData, "17:05:07"),
computeStateDisplay(localize, stateObj, localeData, {}, "17:05:07"),
"17:05"
);
});
@ -357,7 +359,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
computeStateDisplay(altLocalize, stateObj, localeData),
computeStateDisplay(altLocalize, stateObj, localeData, {}),
"state.default.unavailable"
);
});
@ -372,8 +374,26 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
computeStateDisplay(altLocalize, stateObj, localeData),
computeStateDisplay(altLocalize, stateObj, localeData, {}),
"My Custom State"
);
});
it("Localizes using translation key", () => {
const stateObj: any = {
entity_id: "sensor.test",
state: "custom_state",
attributes: {},
};
const entities: any = {
"sensor.test": {
translation_key: "custom_translation",
platform: "custom_integration",
},
};
assert.strictEqual(
computeStateDisplay(localize, stateObj, localeData, entities),
"component.custom_integration.entity.sensor.custom_translation.state.custom_state"
);
});
});