Merge pull request #6411 from home-assistant/dev

This commit is contained in:
Bram Kragten 2020-07-16 18:38:27 +02:00 committed by GitHub
commit e8254f9aae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 333 additions and 116 deletions

View File

@ -108,7 +108,6 @@
"resize-observer-polyfill": "^1.5.1",
"roboto-fontface": "^0.10.0",
"superstruct": "^0.6.1",
"svg-gauge": "^1.0.6",
"unfetch": "^4.1.0",
"vue": "^2.6.11",
"vue2-daterange-picker": "^0.5.1",

View File

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20200715.1",
version="20200716.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",

View File

@ -9,7 +9,7 @@ import {
} from "lit-element";
@customElement("ha-card")
class HaCard extends LitElement {
export class HaCard extends LitElement {
@property() public header?: string;
@property({ type: Boolean, reflect: true }) public outlined = false;

130
src/components/ha-gauge.ts Normal file
View File

@ -0,0 +1,130 @@
import {
LitElement,
svg,
customElement,
css,
property,
internalProperty,
PropertyValues,
} from "lit-element";
import { styleMap } from "lit-html/directives/style-map";
import { afterNextRender } from "../common/util/render-status";
const getAngle = (value: number, min: number, max: number) => {
const percentage = getValueInPercentage(normalize(value, min, max), min, max);
return (percentage * 180) / 100;
};
const normalize = (value: number, min: number, max: number) => {
if (value > max) return max;
if (value < min) return min;
return value;
};
const getValueInPercentage = (value: number, min: number, max: number) => {
const newMax = max - min;
const newVal = value - min;
return (100 * newVal) / newMax;
};
@customElement("ha-gauge")
export class Gauge extends LitElement {
@property({ type: Number }) public min = 0;
@property({ type: Number }) public max = 100;
@property({ type: Number }) public value = 0;
@property() public label = "";
@internalProperty() private _angle = 0;
@internalProperty() private _updated = false;
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
// Wait for the first render for the initial animation to work
afterNextRender(() => {
this._updated = true;
this._angle = getAngle(this.value, this.min, this.max);
this._rescale_svg();
});
}
protected updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
if (!this._updated || !changedProperties.has("value")) {
return;
}
this._angle = getAngle(this.value, this.min, this.max);
this._rescale_svg();
}
protected render() {
return svg`
<svg viewBox="0 0 100 50" class="gauge">
<path
class="dial"
d="M 10 50 A 40 40 0 0 1 90 50"
></path>
<path
class="value"
style=${styleMap({ transform: `rotate(${this._angle}deg)` })}
d="M 90 50.001 A 40 40 0 0 1 10 50"
></path>
</svg>
<svg class="text">
<text class="value-text">
${this.value} ${this.label}
</text>
</svg>`;
}
private _rescale_svg() {
// Set the viewbox of the SVG containing the value to perfectly
// fit the text
// That way it will auto-scale correctly
const svgRoot = this.shadowRoot!.querySelector(".text")!;
const box = svgRoot.querySelector("text")!.getBBox()!;
svgRoot.setAttribute(
"viewBox",
`${box.x} ${box!.y} ${box.width} ${box.height}`
);
}
static get styles() {
return css`
:host {
position: relative;
}
.dial {
fill: none;
stroke: var(--primary-background-color);
stroke-width: 15;
}
.value {
fill: none;
stroke-width: 15;
stroke: var(--gauge-color);
transition: all 1000ms ease 0s;
transform-origin: 50% 100%;
}
.gauge {
display: block;
}
.text {
position: absolute;
max-height: 40%;
max-width: 55%;
left: 50%;
bottom: -6%;
transform: translate(-50%, 0%);
}
.value-text {
font-size: 50px;
fill: var(--primary-text-color);
text-anchor: middle;
}
`;
}
}

View File

@ -89,7 +89,7 @@ const mdiRenameMapping = {
"library-movie": "filmstrip-box-multiple",
"library-music": "music-box-multiple",
"library-music-outline": "music-box-multiple-outline",
"library-video": "play-box-mutiple",
"library-video": "play-box-multiple",
markdown: "language-markdown",
"markdown-outline": "language-markdown-outline",
"message-settings-variant": "message-cog",
@ -151,6 +151,8 @@ const mdiRenameMapping = {
"textbox-lock": "form-textbox-lock",
"textbox-password": "form-textbox-password",
"syllabary-katakana-half-width": "syllabary-katakana-halfwidth",
"visual-studio-code": "microsoft-visual-studio-code",
"visual-studio": "microsoft-visual-studio",
};
const mdiRemovedIcons = new Set([

View File

@ -1,5 +1,4 @@
import { HassEntity } from "home-assistant-js-websocket/dist/types";
import Gauge from "svg-gauge";
import {
css,
CSSResult,
@ -10,7 +9,6 @@ import {
internalProperty,
PropertyValues,
TemplateResult,
query,
} from "lit-element";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
@ -24,6 +22,8 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import type { GaugeCardConfig } from "./types";
import "../../../components/ha-gauge";
import { styleMap } from "lit-html/directives/style-map";
export const severityMap = {
red: "var(--label-badge-red)",
@ -68,10 +68,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
@internalProperty() private _config?: GaugeCardConfig;
@internalProperty() private _gauge?: any;
@query("#gauge") private _gaugeElement!: HTMLDivElement;
public getCardSize(): number {
return 2;
}
@ -84,7 +80,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
throw new Error("Invalid Entity");
}
this._config = { min: 0, max: 100, ...config };
this._initGauge();
}
protected render(): TemplateResult {
@ -118,7 +113,18 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
return html`
<ha-card @click=${this._handleClick} tabindex="0">
<div id="gauge"></div>
<ha-gauge
.min=${this._config.min!}
.max=${this._config.max!}
.value=${state}
.label=${this._config!.unit ||
this.hass?.states[this._config!.entity].attributes
.unit_of_measurement ||
""}
style=${styleMap({
"--gauge-color": this._computeSeverity(state),
})}
></ha-gauge>
<div class="name">
${this._config.name || computeStateName(stateObj)}
</div>
@ -130,13 +136,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
return hasConfigOrEntityChanged(this, changedProps);
}
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
if (!this._gauge) {
this._initGauge();
}
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (!this._config || !this.hass) {
@ -156,66 +155,38 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
) {
applyThemesOnElement(this, this.hass.themes, this._config.theme);
}
const oldState = oldHass?.states[this._config.entity];
const stateObj = this.hass.states[this._config.entity];
if (oldState?.state !== stateObj.state) {
this._gauge.setValueAnimated(stateObj.state, 1);
}
}
private _initGauge() {
if (!this._gaugeElement || !this._config || !this.hass) {
return;
private _computeSeverity(numberValue: number): string {
const sections = this._config!.severity;
if (!sections) {
return severityMap.normal;
}
if (this._gauge) {
this._gaugeElement.removeChild(this._gaugeElement.lastChild!);
this._gauge = undefined;
}
this._gauge = Gauge(this._gaugeElement, {
min: this._config.min,
max: this._config.max,
dialStartAngle: 180,
dialEndAngle: 0,
viewBox: "0 0 100 55",
label: (value) => `${Math.round(value)}
${
this._config!.unit ||
this.hass?.states[this._config!.entity].attributes
.unit_of_measurement ||
""
}`,
color: (value) => {
const sections = this._config!.severity;
if (!sections) {
return severityMap.normal;
}
const sectionsArray = Object.keys(sections);
const sortable = sectionsArray.map((severity) => [
severity,
sections[severity],
]);
const sectionsArray = Object.keys(sections);
const sortable = sectionsArray.map((severity) => [
severity,
sections[severity],
]);
for (const severity of sortable) {
if (severityMap[severity[0]] == null || isNaN(severity[1])) {
return severityMap.normal;
}
}
sortable.sort((a, b) => a[1] - b[1]);
if (value >= sortable[0][1] && value < sortable[1][1]) {
return severityMap[sortable[0][0]];
}
if (value >= sortable[1][1] && value < sortable[2][1]) {
return severityMap[sortable[1][0]];
}
if (value >= sortable[2][1]) {
return severityMap[sortable[2][0]];
}
for (const severity of sortable) {
if (severityMap[severity[0]] == null || isNaN(severity[1])) {
return severityMap.normal;
},
});
}
}
sortable.sort((a, b) => a[1] - b[1]);
if (numberValue >= sortable[0][1] && numberValue < sortable[1][1]) {
return severityMap[sortable[0][0]];
}
if (numberValue >= sortable[1][1] && numberValue < sortable[2][1]) {
return severityMap[sortable[1][0]];
}
if (numberValue >= sortable[2][1]) {
return severityMap[sortable[2][0]];
}
return severityMap.normal;
}
private _handleClick(): void {
@ -244,31 +215,20 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
outline: none;
background: var(--divider-color);
}
#gauge {
ha-gauge {
--gauge-color: var(--label-badge-blue);
width: 100%;
max-width: 300px;
}
.dial {
stroke: #ccc;
stroke-width: 15;
}
.value {
stroke-width: 15;
}
.value-text {
fill: var(--primary-text-color);
font-size: var(--gauge-value-font-size, 1.1em);
transform: translate(0, -5px);
font-family: inherit;
max-width: 250px;
}
.name {
text-align: center;
line-height: initial;
color: var(--primary-text-color);
width: 100%;
font-size: 15px;
}
margin-top: 8px;
}
`;
}

View File

@ -105,7 +105,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
.min=${stateObj.attributes.min_humidity}
.max=${stateObj.attributes.max_humidity}
.rtl=${rtlDirection === "rtl"}
.step="1"
step="1"
@value-changing=${this._dragEvent}
@value-changed=${this._setHumidity}
></round-slider>

View File

@ -12,6 +12,7 @@ import {
PropertyValues,
svg,
TemplateResult,
query,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { UNIT_F } from "../../../common/const";
@ -33,6 +34,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { ThermostatCardConfig } from "./types";
import type { HaCard } from "../../../components/ha-card";
const modeIcons: { [mode in HvacMode]: string } = {
auto: "hass:calendar-sync",
@ -77,6 +79,8 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
@internalProperty() private _setTemp?: number | number[];
@query("ha-card") private _card?: HaCard;
public getCardSize(): number {
return 5;
}
@ -290,18 +294,17 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
// That way it will auto-scale correctly
// This is not done to the SVG containing the current temperature, because
// it should not be centered on the text, but only on the value
if (this.shadowRoot && this.shadowRoot.querySelector("ha-card")) {
(this.shadowRoot.querySelector(
"ha-card"
) as LitElement).updateComplete.then(() => {
const svgRoot = this.shadowRoot!.querySelector("#set-values");
const box = svgRoot!.querySelector("g")!.getBBox();
svgRoot!.setAttribute(
const card = this._card;
if (card) {
card.updateComplete.then(() => {
const svgRoot = this.shadowRoot!.querySelector("#set-values")!;
const box = svgRoot.querySelector("g")!.getBBox()!;
svgRoot.setAttribute(
"viewBox",
`${box!.x} ${box!.y} ${box!.width} ${box!.height}`
`${box.x} ${box!.y} ${box.width} ${box.height}`
);
svgRoot!.setAttribute("width", `${box!.width}`);
svgRoot!.setAttribute("height", `${box!.height}`);
svgRoot.setAttribute("width", `${box.width}`);
svgRoot.setAttribute("height", `${box.height}`);
});
}
}

View File

@ -1,3 +1,4 @@
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import deepFreeze from "deep-freeze";
import {
css,

View File

@ -1,3 +1,4 @@
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import deepFreeze from "deep-freeze";
import {
css,

View File

@ -98,7 +98,7 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
no-label-float
auto-validate
.disabled=${UNAVAILABLE_STATES.includes(stateObj.state)}
.pattern="[0-9]+([\\.][0-9]+)?"
pattern="[0-9]+([\\.][0-9]+)?"
.step="${Number(stateObj.attributes.step)}"
.min="${Number(stateObj.attributes.min)}"
.max="${Number(stateObj.attributes.max)}"

View File

@ -9,7 +9,7 @@ import { Constructor } from "../types";
import { HassBaseEl } from "./hass-base-mixin";
import { HASSDomEvent } from "../common/dom/fire_event";
const DEBUG = true;
const DEBUG = false;
export const urlSyncMixin = <T extends Constructor<HassBaseEl>>(
superClass: T

View File

@ -70,9 +70,9 @@
"armed_custom_bypass": "Zabezpečeno",
"armed_home": "Zabezpečeno",
"armed_night": "Zabezpečeno",
"arming": "Aktivace",
"arming": "Zabezpečování",
"disarmed": "Nezabezpečeno",
"disarming": "Deaktivace",
"disarming": "Odbezpečování",
"pending": "Čeká",
"triggered": "Spuštěn"
},
@ -95,7 +95,7 @@
"alarm_control_panel": {
"armed": "Zabezpečeno",
"armed_away": "Režim nepřítomnost",
"armed_custom_bypass": "Aktivní uživatelským obejitím",
"armed_custom_bypass": "Zabezpečeno uživatelským obejitím",
"armed_home": "Režim domov",
"armed_night": "Noční režim",
"arming": "Zabezpečování",
@ -430,6 +430,8 @@
"activate": "Aktivovat"
},
"script": {
"cancel": "Zrušit",
"cancel_multiple": "Zrušit {number}",
"execute": "Vykonat"
},
"service": {
@ -525,6 +527,9 @@
"clear": "Vymazat",
"show_areas": "Zobrazit oblasti"
},
"data-table": {
"search": "Hledat"
},
"date-range-picker": {
"end_date": "Koncové datum",
"select": "Vybrat",
@ -938,6 +943,19 @@
"introduction": "Použijte automatizace k oživení svého domova",
"load_error_not_editable": "Lze upravovat pouze automatizace v automations.yaml.",
"load_error_unknown": "Chyba při načítání automatizace ({err_no}).",
"max": {
"parallel": "Maximální počet paralelních spuštění",
"queued": "Délka fronty"
},
"modes": {
"description": "Režim určuje, co se stane, když je automatizace spuštěna a zároveň stále ještě běží akce na základě předchozího spuštění. Další informace naleznete na {documentation_link}.",
"documentation": "Dokumentace automatizací",
"label": "Režim",
"parallel": "Paralelní (výchozí)",
"queued": "Fronta",
"restart": "Restart",
"single": "Jediný"
},
"move_down": "Posunout dolů",
"move_up": "Posunout nahoru",
"save": "Uložit",
@ -1356,6 +1374,7 @@
"confirm_text": "Entity lze odebrat pouze v případě, že integrace již entity neposkytuje.",
"confirm_title": "Chcete odstranit {number} entit?"
},
"search": "Hledat entitu",
"selected": "{number} vybraných",
"status": {
"disabled": "Zakázáno",
@ -1386,7 +1405,8 @@
"entity_id": "ID entity",
"name": "Název",
"type": "Typ"
}
},
"no_helpers": "Vypadá to, že ještě nemáte žádné pomocníky!"
},
"types": {
"input_boolean": "Přepnout",
@ -1490,7 +1510,8 @@
"note_about_integrations": "Ne všechny integrace lze prozatím konfigurovat prostřednictvím uživatelského rozhraní.",
"note_about_website_reference": "Další jsou k dispozici na ",
"rename_dialog": "Upravit název této položky nastavení",
"rename_input_label": "Název položky"
"rename_input_label": "Název položky",
"search": "Hledat integraci"
},
"introduction": "Zde je možné konfigurovat vaše komponenty a Home Assistant.\nZ uživatelského rozhraní sice zatím není možné konfigurovat vše, ale pracujeme na tom.",
"logs": {
@ -1643,6 +1664,7 @@
"introduction": "Zde lze nastavit entity, které nepatří k zařízení.",
"without_device": "Entity bez zařízení"
},
"icon": "Ikona",
"introduction": "Pomocí scén oživte svůj domov.",
"load_error_not_editable": "Lze upravovat pouze scény v souboru scenes.yaml.",
"load_error_unknown": "Chyba při načítání scény ({err_no}).",
@ -1676,9 +1698,26 @@
"delete_confirm": "Opravdu chcete tento skript smazat?",
"delete_script": "Smazat skript",
"header": "Skript: {name}",
"icon": "Ikona",
"id": "ID entity",
"id_already_exists": "Toto ID již existuje",
"id_already_exists_save_error": "Tento skript nelze uložit, protože ID není jedinečné, vyberte jiné ID nebo jej nechte prázdné a bude automaticky vygenerováno.",
"introduction": "K provedení posloupnosti akcí použijte skripty.",
"link_available_actions": "Další informace o dostupných akcích.",
"load_error_not_editable": "Upravovat lze pouze skripty uvnitř scripts.yaml.",
"max": {
"parallel": "Maximální počet paralelních spuštění",
"queued": "Délka fronty"
},
"modes": {
"description": "Režim určuje, co se stane, když je skript spuštěn a zároveň stále ještě běží na základě předchozího spuštění. Další informace naleznete na {documentation_link}.",
"documentation": "Dokumentace skriptů",
"label": "Režim",
"parallel": "Paralelní (výchozí)",
"queued": "Fronta",
"restart": "Restart",
"single": "Jediný (výchozí)"
},
"sequence": "Sekvence",
"sequence_sentence": "Posloupnost akcí tohoto skriptu."
},
@ -2194,6 +2233,7 @@
"name": "Název",
"no_theme": "Žádný motiv",
"refresh_interval": "Interval obnovení",
"search": "Hledat",
"secondary_info_attribute": "Sekundární informační atribut",
"show_icon": "Zobrazit ikonu?",
"show_name": "Zobrazit název?",
@ -2314,7 +2354,8 @@
"edit_lovelace": {
"edit_title": "Upravit titulek",
"explanation": "Tento název je zobrazen nad všemi vašimi zobrazeními v Lovelace.",
"header": "Název vašeho uživatelského rozhraní Lovelace"
"header": "Název vašeho uživatelského rozhraní Lovelace",
"title": "Název"
},
"edit_view": {
"add": "Přidat pohled",
@ -2503,6 +2544,7 @@
},
"trusted_networks": {
"abort": {
"not_allowed": "Váš počítač není povolen.",
"not_whitelisted": "Váš počítač není na seznamu povolených."
},
"step": {
@ -2678,6 +2720,10 @@
"not_used": "Nikdy nebylo použito",
"token_title": "Obnovovací token pro {clientId}"
},
"suspend": {
"description": "Měli bychom ukončit spojení se serverem, pokud není Home Assistant viditelný po dobu delší než 5 minut?",
"header": "Automaticky ukončovat spojení"
},
"themes": {
"dropdown_label": "Motiv",
"error_no_theme": "Žádné motivy nejsou k dispozici.",

View File

@ -951,10 +951,10 @@
"description": "The mode controls what happens when the automation is triggered while the actions are still running from a previous trigger. Check the {documentation_link} for more info.",
"documentation": "automation documentation",
"label": "Mode",
"parallel": "Parallel (default)",
"parallel": "Parallel",
"queued": "Queued",
"restart": "Restart",
"single": "Single"
"single": "Single (default)"
},
"move_down": "Move down",
"move_up": "Move up",

View File

@ -430,6 +430,8 @@
"activate": "Activar"
},
"script": {
"cancel": "Cancelar",
"cancel_multiple": "Cancelar {number}",
"execute": "Ejecutar"
},
"service": {
@ -941,6 +943,19 @@
"introduction": "Utiliza automatizaciones para darle vida a tu hogar.",
"load_error_not_editable": "Solo las automatizaciones en automations.yaml son editables.",
"load_error_unknown": "Error al cargar la automatización ({err_no}).",
"max": {
"parallel": "Número máximo de ejecuciones paralelas",
"queued": "Longitud de la cola"
},
"modes": {
"description": "El modo controla lo que sucede cuando se activa la automatización mientras las acciones aún se ejecutan desde una activación anterior. Consulta la {documentation_link} para obtener más información.",
"documentation": "documentación de automatización",
"label": "Modo",
"parallel": "Paralelo (predeterminado)",
"queued": "En cola",
"restart": "Reiniciar",
"single": "Único"
},
"move_down": "Mover hacia abajo",
"move_up": "Mover hacia arriba",
"save": "Guardar",
@ -1649,6 +1664,7 @@
"introduction": "Las entidades que no pertenecen a un dispositivo se pueden configurar aquí.",
"without_device": "Entidades sin dispositivo"
},
"icon": "Icono",
"introduction": "Usa escenas para dar vida a tu hogar.",
"load_error_not_editable": "Solo las escenas de scenes.yaml son editables.",
"load_error_unknown": "Error al cargar la escena ({err_no}).",
@ -1682,9 +1698,26 @@
"delete_confirm": "¿Seguro que quieres eliminar este script?",
"delete_script": "Eliminar script",
"header": "Script: {name}",
"icon": "Icono",
"id": "ID de la entidad",
"id_already_exists": "Este ID ya existe",
"id_already_exists_save_error": "No puedes guardar este script porque el ID no es único, elije otro ID o déjalo en blanco para generar uno automáticamente.",
"introduction": "Utiliza scripts para ejecutar una secuencia de acciones.",
"link_available_actions": "Saber más sobre las acciones disponibles.",
"load_error_not_editable": "Solo los scripts dentro de scripts.yaml son editables.",
"max": {
"parallel": "Número máximo de ejecuciones paralelas",
"queued": "Longitud de la cola"
},
"modes": {
"description": "El modo controla lo que sucede cuando se invoca el script mientras aún se ejecuta desde una o más invocaciones anteriores. Consulta la {documentation_link} para obtener más información.",
"documentation": "documentación de script",
"label": "Modo",
"parallel": "Paralelo",
"queued": "En cola",
"restart": "Reiniciar",
"single": "Único (predeterminado)"
},
"sequence": "Secuencia",
"sequence_sentence": "La secuencia de acciones de este script."
},
@ -2511,6 +2544,7 @@
},
"trusted_networks": {
"abort": {
"not_allowed": "Tu equipo no está permitido.",
"not_whitelisted": "Tu equipo no está en la lista de autorizados."
},
"step": {

View File

@ -430,6 +430,8 @@
"activate": "Activer"
},
"script": {
"cancel": "Annuler",
"cancel_multiple": "Annuler {number}",
"execute": "Exécuter"
},
"service": {
@ -941,6 +943,18 @@
"introduction": "Utilisez les automatisations pour donner vie à votre maison",
"load_error_not_editable": "Seules les automatisations dans automations.yaml sont modifiables.",
"load_error_unknown": "Erreur lors du chargement de l'automatisation ( {err_no} ).",
"max": {
"parallel": "Nombre maximal de parcours parallèles",
"queued": "Longueur de la file d'attente"
},
"modes": {
"description": "Le mode contrôle ce qui se passe lorsque lautomatisation est déclenchée alors que les actions sont toujours en cours dexécution à partir dun déclencheur précédent. Consultez le {documentation_link} pour plus dinformations.",
"documentation": "documentation d'automatisation",
"label": "Mode",
"parallel": "Parallèle (par défaut)",
"queued": "En attente",
"restart": "Redémarrer"
},
"move_down": "Déplacer vers le bas",
"move_up": "Déplacer vers le haut",
"save": "Sauvegarder",
@ -1649,6 +1663,7 @@
"introduction": "Les entités n'appartenant pas à un périphérique peuvent être définies ici.",
"without_device": "Entités sans appareil"
},
"icon": "Icône",
"introduction": "Utilisez des scènes pour donner vie à votre maison.",
"load_error_not_editable": "Seules les scènes de scenes.yaml sont modifiables.",
"load_error_unknown": "Erreur de chargement de la scène ({err_no})",
@ -1682,9 +1697,26 @@
"delete_confirm": "Êtes-vous sûr de vouloir supprimer ce script?",
"delete_script": "Supprimer le script",
"header": "Script: {name}",
"icon": "Icône",
"id": "ID de l'entité",
"id_already_exists": "Cet ID existe déjà",
"id_already_exists_save_error": "Vous ne pouvez pas enregistrer ce script car l'ID n'est pas unique, choisissez un autre ID ou laissez-le vide pour en générer automatiquement un.",
"introduction": "Utiliser des scripts pour exécuter une séquence d'actions.",
"link_available_actions": "En savoir plus sur les actions disponibles.",
"load_error_not_editable": "Seuls les scripts dans scripts.yaml sont modifiables.",
"max": {
"parallel": "Nombre maximal de parcours parallèles",
"queued": "Longueur de la file d'attente"
},
"modes": {
"description": "Le mode contrôle ce qui se passe lorsque le script est appelé alors quil est toujours en cours dexécution à partir dune ou plusieurs invocations précédentes. Consultez le {documentation_link} pour plus dinformations.",
"documentation": "documentation script",
"label": "Mode",
"parallel": "Parallèle",
"queued": "En attente",
"restart": "Redémarrer",
"single": "Unique (par défaut)"
},
"sequence": "Séquence",
"sequence_sentence": "La séquence d'actions de ce script."
},
@ -2511,6 +2543,7 @@
},
"trusted_networks": {
"abort": {
"not_allowed": "Votre ordinateur n'est pas autorisé.",
"not_whitelisted": "Votre ordinateur n'est pas en liste blanche."
},
"step": {

View File

@ -430,6 +430,8 @@
"activate": "Активировать"
},
"script": {
"cancel": "Отменить",
"cancel_multiple": "Отменить {number}",
"execute": "Выполнить"
},
"service": {
@ -1654,6 +1656,7 @@
"introduction": "Объекты, которые не связаны с каким-либо устройством, могут быть указаны здесь.",
"without_device": "Объекты без устройств"
},
"icon": "Значок",
"introduction": "Используйте сцены, чтобы оживить Ваш дом.",
"load_error_not_editable": "Доступны для редактирования только сцены из scenes.yaml.",
"load_error_unknown": "Ошибка загрузки сцены ({err_no}).",
@ -1687,6 +1690,9 @@
"delete_confirm": "Вы уверены, что хотите удалить этот сценарий?",
"delete_script": "Удалить сценарий",
"header": "Сценарий: {name}",
"icon": "Значок",
"id": "ID объекта",
"id_already_exists": "Этот ID уже существует",
"introduction": "Используйте сценарии для выполнения последовательности действий.",
"link_available_actions": "Узнайте больше о действиях",
"load_error_not_editable": "Доступны для редактирования только сценарии из scripts.yaml.",

View File

@ -430,6 +430,8 @@
"activate": "啟用"
},
"script": {
"cancel": "取消",
"cancel_multiple": "取消 {number}",
"execute": "執行"
},
"service": {
@ -1662,6 +1664,7 @@
"introduction": "不屬於設備的物件可以於此設置。",
"without_device": "無設備物件"
},
"icon": "圖示",
"introduction": "使用場景來讓你的智能家居更有魅力吧。",
"load_error_not_editable": "僅有於 scenes.yaml 檔案內的場景、方能進行編輯。",
"load_error_unknown": "載入場景錯誤({err_no})。",
@ -1695,6 +1698,10 @@
"delete_confirm": "確定要刪除此腳本?",
"delete_script": "刪除腳本",
"header": "腳本:{name}",
"icon": "圖示",
"id": "物件 ID",
"id_already_exists": "該 ID 已存在",
"id_already_exists_save_error": "由於該 ID 非獨一 ID因此無法儲存此腳本。請選擇其他 ID 或者保留空白以自動產生。",
"introduction": "使用腳本以執行一連串的動作。",
"link_available_actions": "詳細了解可使用動作",
"load_error_not_editable": "僅有於 scripts.yaml 檔案內的腳本,方能進行編輯。",

View File

@ -11305,11 +11305,6 @@ sver-compat@^1.5.0:
es6-iterator "^2.0.1"
es6-symbol "^3.1.1"
svg-gauge@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/svg-gauge/-/svg-gauge-1.0.6.tgz#1e84a366b1cce5b95dab3e33f41fdde867692d28"
integrity sha512-gRkznVhtS18eOM/GMPDXAvrLZOpqzNVDg4bFAPAEjiDKd1tZHFIe8Bwt3G6TFg/H+pFboetPPI+zoV+bOL26QQ==
symbol-observable@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"