From 1e6e945a079934efcf1c49360934529744c582af Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 4 Jun 2021 02:52:56 +0000 Subject: [PATCH 01/73] Translation update --- translations/frontend/bg.json | 5 +++++ translations/frontend/ca.json | 8 +++++--- translations/frontend/en.json | 2 ++ translations/frontend/it.json | 6 +++++- translations/frontend/ko.json | 6 ++++-- translations/frontend/nl.json | 3 ++- translations/frontend/ru.json | 6 ++++-- translations/frontend/zh-Hans.json | 2 +- 8 files changed, 28 insertions(+), 10 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index 203efdef19..a368df0a53 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -351,6 +351,9 @@ "create_blocked_not_running": "Създаването на снапшот в момента не е възможно, тъй като системата е в състояние {state}.", "create_snapshot": "Създаване на снапшот", "created": "Създаден", + "delete_selected": "Изтриване на избраните снапшоти", + "delete_snapshot_confirm": "Изтрий", + "delete_snapshot_title": "Изтриване на снапшот", "description": "Снапшотите ви позволяват лесно да архивирате и възстановявате всички данни от вашия екземпляр на Home Assistant.", "enter_password": "Моля, въведете парола.", "folder": { @@ -369,6 +372,7 @@ "password_protected": "защитен с парола", "password_protection": "Защита с парола", "security": "Сигурност", + "selected": "{number} избрани", "type": "Тип", "upload_snapshot": "Качване на снапшот" }, @@ -874,6 +878,7 @@ "config_entry_system_options": { "enable_new_entities_description": "Ако е изключено, новооткритите обекти за {integration} няма да бъдат автоматично добавяни в Home Assistant", "enable_new_entities_label": "Активирай новодобавените обекти.", + "restart_home_assistant": "Трябва да рестартирате Home Assistant, за да влязат в сила промените.", "title": "Системни опции за {integration}", "update": "Актуализация" }, diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index 54c8a184ff..276ddb644f 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -284,7 +284,7 @@ "refresh": "Actualitza", "release_notes": "Notes de la versió", "reload": "Torna a carregar", - "reset_defaults": "Restableix als valors per defecte", + "reset_defaults": "Restableix els valors per defecte", "reset_options": "Opcions de reinici", "restart": "Reinicia", "restart_name": "Reinicia {name}", @@ -368,6 +368,8 @@ "error": "S'ha produït un error desconegut", "error_addon_no_ingress": "El complement sol·licitat no admet ingress", "error_addon_not_found": "No s'ha trobat el complement", + "error_addon_not_installed": "El complement sol·licitat no està instal·lat. Instal·la'l primer", + "error_addon_not_started": "El complement sol·licitat no s'està executant. Inicia'l primer", "faq_link": "Preguntes freqüents de My Home Assistant", "not_supported": "La instància de Home Assistant no admet aquesta redirecció. Consulta {link} per veure les redireccions compatibles i en quina versió es van introduir." }, @@ -3714,7 +3716,7 @@ }, "page-authorize": { "abort_intro": "S'ha avortat l'inici de sessió", - "authorizing_client": "Esteu a punt de permetre l'accés a la vostra instància de Home Assistant al client {clientId}.", + "authorizing_client": "Estàs a punt de concedir al client {clientId} l'accés a la teva instància de Home Assistant.", "form": { "error": "Error: {error}", "next": "Següent", @@ -3808,7 +3810,7 @@ "working": "Si us plau, espereu" }, "initializing": "S'està inicialitzant", - "logging_in_to_with": "S'escriuen els registes amb **{authProviderName}** a **{locationName}**.", + "logging_in_to_with": "Iniciant sessió a **{locationName}** amb **{authProviderName}**.", "logging_in_with": "Iniciant sessió amb **{authProviderName}**.", "pick_auth_provider": "O bé inicieu sessió amb" }, diff --git a/translations/frontend/en.json b/translations/frontend/en.json index b9dc7ff55e..b2ff6ed221 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -368,6 +368,8 @@ "error": "An unknown error occurred", "error_addon_no_ingress": "The requested add-on does not support ingress", "error_addon_not_found": "Add-on not found", + "error_addon_not_installed": "The requested add-on is not installed. Please install it first", + "error_addon_not_started": "The requested add-on are not running. Please start it first", "faq_link": "My Home Assistant FAQ", "not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced." }, diff --git a/translations/frontend/it.json b/translations/frontend/it.json index 1815c2307b..96779a9caf 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -368,6 +368,8 @@ "error": "Si è verificato un errore sconosciuto", "error_addon_no_ingress": "Il componente aggiuntivo richiesto non supporta l'ingresso", "error_addon_not_found": "Componente aggiuntivo non trovato", + "error_addon_not_installed": "Il componente aggiuntivo richiesto non è installato. Si prega di installarlo prima di proseguire", + "error_addon_not_started": "Il componente aggiuntivo non è in esecuzione. Si prega di avviarlo prima di proseguire", "faq_link": "My Home Assistant FAQ", "not_supported": "Questo reindirizzamento non è supportato dall'istanza di Home Assistant. Controlla il {link} per i reindirizzamenti supportati e la versione in cui sono stati introdotti." }, @@ -2076,7 +2078,8 @@ "scripts": "Script", "unknown_error": "Errore sconosciuto", "unnamed_device": "Dispositivo senza nome", - "update": "Aggiorna" + "update": "Aggiorna", + "update_device_error": "Aggiornamento del dispositivo non riuscito" }, "entities": { "caption": "Entità", @@ -2209,6 +2212,7 @@ "depends_on_cloud": "Dipende dal cloud", "device_unavailable": "Dispositivo non disponibile", "devices": "{count} {count, plural, \none {dispositivo}\nother {dispositivi}\n}", + "disable_error": "Abilitazione o disabilitazione dell'integrazione non riuscita", "disable_restart_confirm": "Riavvia Home Assistant per terminare la disabilitazione di questa integrazione", "disable": { "disable_confirm": "Sei sicuro di voler disabilitare questa voce di configurazione? I suoi dispositivi ed entità saranno disabilitati.", diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index 061c61763b..c028a51af8 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -387,7 +387,7 @@ "created": "생성됨", "delete_selected": "선택한 스냅샷 삭제", "delete_snapshot_confirm": "삭제", - "delete_snapshot_text": "{number} {number, plural,\n one{개의 스냅샷}\n other{개의 스냅샷}\n}를 삭제하시겠습니까?", + "delete_snapshot_text": "{number} {number, plural,\n one{개의 스냅샷}\n other{개의 스냅샷}\n} 삭제하시겠습니까?", "delete_snapshot_title": "스냅샷 삭제", "description": "스냅숏을 사용하면 Home Assistant 인스턴스의 모든 데이터를 쉽게 백업하고 복원할 수 있습니다.", "enter_password": "비밀번호를 입력해주세요.", @@ -2076,7 +2076,8 @@ "scripts": "스크립트", "unknown_error": "알 수 없는 오류", "unnamed_device": "이름이 없는 기기", - "update": "업데이트" + "update": "업데이트", + "update_device_error": "장치 업데이트 실패" }, "entities": { "caption": "구성요소", @@ -2209,6 +2210,7 @@ "depends_on_cloud": "클라우드 서비스", "device_unavailable": "기기 사용불가", "devices": "{count} {count, plural,\none{개의 기기}\nother{개의 기기}\n}", + "disable_error": "통합구성요소 활성화 혹은 비활성화 실패", "disable_restart_confirm": "이 통합 구성요소를 비활성화하려면 Home Assistant를 다시 시작해주세요", "disable": { "disable_confirm": "이 구성 항목을 비활성화하시겠습니까? 해당 기기 및 구성요소가 비활성화됩니다.", diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 606fda0db6..f9460cbeec 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -2076,7 +2076,8 @@ "scripts": "Scripts", "unknown_error": "Onbekende fout", "unnamed_device": "Naamloos apparaat", - "update": "Bijwerken" + "update": "Bijwerken", + "update_device_error": "Updaten van het apparaat mislukt" }, "entities": { "caption": "Entiteiten", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 0be73ee056..b6bd827b75 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -368,6 +368,8 @@ "error": "Произошла неизвестная ошибка", "error_addon_no_ingress": "Дополнение не поддерживает ingress.", "error_addon_not_found": "Дополнение не найдено.", + "error_addon_not_installed": "Запрошенное дополнение не установлено. Сначала нужно установить его.", + "error_addon_not_started": "Запрашиваемое дополнение не запущено. Сначала нужно запустить его.", "faq_link": "часто задаваемыми вопросами по My Home Assistant", "not_supported": "Это перенаправление не поддерживается Вашим Home Assistant. Ознакомьтесь с {link}, чтобы узнать поддерживаемые перенаправления и версии, в которых они были добавлены." }, @@ -408,9 +410,9 @@ "password_protected": "защищено паролем", "password_protection": "Защита паролем", "security": "Безопасность", - "select_type": "Выберите что нужно восстановить", + "select_type": "Выберите что нужно восстановить из этого снимка файловой системы", "selected": "Выбрано: {number}", - "type": "Тип снимка", + "type": "Выберите что должен включать в себя снимок файловой системы", "upload_snapshot": "Загрузить снимок на сервер" }, "store": { diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index b40625b2f7..5a64668803 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -1806,7 +1806,7 @@ } }, "alexa": { - "banner": "由于您在 configuration.yaml 中配置了实体过滤器,无法通过此 UI 修改要开放的实体。", + "banner": "无法通过此 UI 修改要开放的实体,因为您在 configuration.yaml 中配置了实体过滤器。", "dont_expose_entity": "使实体不可发现", "expose": "向Alexa发送你的位置", "expose_entity": "使实体可发现", From a45b8ca8e71d34ebab288d887adaf99d246e6299 Mon Sep 17 00:00:00 2001 From: Will Adler Date: Fri, 4 Jun 2021 02:57:03 -0400 Subject: [PATCH 02/73] Add period to end of sentence (#9361) --- src/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/en.json b/src/translations/en.json index 6d41d8e276..22cb216393 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1155,7 +1155,7 @@ "section": { "validation": { "heading": "Configuration validation", - "introduction": "Validate your configuration if you recently made some changes to your configuration and want to make sure that it is all valid", + "introduction": "Validate your configuration if you recently made some changes to your configuration and want to make sure that it is all valid.", "check_config": "Check configuration", "valid": "Configuration valid!", "invalid": "Configuration invalid" From 635a027a8e4412ad73833d50cf7112f46b614003 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 5 Jun 2021 02:40:15 +0000 Subject: [PATCH 03/73] Translation update --- translations/frontend/bg.json | 2 +- translations/frontend/ca.json | 2 +- translations/frontend/cs.json | 16 +++++++++++++--- translations/frontend/de.json | 22 +++++++++++++++++++++- translations/frontend/en.json | 2 +- translations/frontend/es-419.json | 6 +++++- translations/frontend/es.json | 4 +++- translations/frontend/et.json | 6 ++++-- translations/frontend/ko.json | 2 ++ translations/frontend/nb.json | 4 +++- translations/frontend/nl.json | 2 ++ translations/frontend/pl.json | 12 ++++++++++-- translations/frontend/ru.json | 2 +- translations/frontend/zh-Hans.json | 4 +++- translations/frontend/zh-Hant.json | 4 +++- 15 files changed, 73 insertions(+), 17 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index a368df0a53..26a266478d 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -2098,7 +2098,7 @@ "confirm_delete_ignore_title": "Да се спре ли игнорирането на {name}?", "confirm_ignore": "Наистина ли не искате да настроите тази интеграция? Можете да отмените това, като кликнете върху „Показване на игнорирани интеграции“ в менюто горе вдясно.", "hide_ignored": "Скриване на игнорираните интеграции", - "ignore": "Игнорирайте", + "ignore": "Игнориране", "ignored": "Игнорирана", "show_ignored": "Показване на игнорираните интеграции", "stop_ignore": "Спрете да игнорирате" diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index 276ddb644f..09b15bcbb9 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -2721,7 +2721,7 @@ "validation": { "check_config": "Comprova la configuració", "heading": "Validació de la configuració", - "introduction": "Valida la configuració si recentment has fet algun canvi a la configuració i vols assegurar-te de que sigui vàlida.", + "introduction": "Valida la configuració si recentment n'has fet algun canvi i vols assegurar-te de que sigui vàlida.", "invalid": "Configuració invàlida", "valid": "Configuració vàlida!" } diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index e65cdf03ff..2197c06ff2 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -368,6 +368,8 @@ "error": "Nastala neznámá chyba", "error_addon_no_ingress": "Požadovaný doplněk nepodporuje ingress", "error_addon_not_found": "Doplněk nebyl nalezen", + "error_addon_not_installed": "Požadovaný doplněk není nainstalován. Nejprve jej prosím nainstalujte", + "error_addon_not_started": "Požadovaný doplněk není spuštěn. Nejprve jej prosím spusťte", "faq_link": "Časté dotazy týkající se My Home Assistant", "not_supported": "Toto přesměrování není vaší instancí Home Assistant podporováno. Zkontrolujte {link} pro podporovaná přesměrování a verzi, ve které byla zavedena." }, @@ -929,8 +931,11 @@ }, "dialogs": { "config_entry_system_options": { - "enable_new_entities_description": "Pokud je zakázáno, nově objevené entity pro {integration} nebudou automaticky přidány do Home Assistant.", + "enable_new_entities_description": "Pokud se mají automaticky přidat nově objevená zařízení integrace {integration}.", "enable_new_entities_label": "Povolit nově přidané entity.", + "enable_polling_description": "Má-li Home Assistant automaticky zjišťovat aktualizace entit integrace {integration}.", + "enable_polling_label": "Povolit dotazování na aktualizace.", + "restart_home_assistant": "Aby se změny projevily, je třeba restartovat Home Assistant.", "title": "Upravit nastavení pro {integration}", "update": "Aktualizovat" }, @@ -2073,7 +2078,8 @@ "scripts": "Skripty", "unknown_error": "Neznámá chyba", "unnamed_device": "Nepojmenované zařízení", - "update": "Aktualizovat" + "update": "Aktualizovat", + "update_device_error": "Aktualizace zařízení se nezdařila" }, "entities": { "caption": "Entity", @@ -2206,6 +2212,7 @@ "depends_on_cloud": "Závisí na cloudu", "device_unavailable": "Zařízení není dostupné", "devices": "{count} {count, plural,\n one {zařízení}\n other {zařízení}\n}", + "disable_error": "Povolení nebo zakázání integrace se nezdařilo", "disable_restart_confirm": "Restartujte Home Assistant pro dokončení odstranění této integrace", "disable": { "disable_confirm": "Opravdu chcete zakázat tuto položku konfigurace? Její zařízení a entity budou zakázány.", @@ -2217,6 +2224,7 @@ }, "disabled_cause": "Zakázáno {cause}" }, + "disabled_polling": "Automatické dotazování na aktualizovaná data je zakázáno", "documentation": "Dokumentace", "enable_restart_confirm": "Restartujte Home Assistant pro dokončení přidání této integrace", "entities": "{count} {count, plural,\n one {entita}\n other {entit}\n}", @@ -2713,7 +2721,7 @@ "validation": { "check_config": "Zkontrolujte konfiguraci", "heading": "Ověření konfigurace", - "introduction": "Pokud jste nedávno provedli změny konfigurace a chcete se ujistit, že je vše v pořádku, můžete zde konfiguraci ověřit", + "introduction": "Pokud jste nedávno provedli nějaké změny v konfiguraci a chcete se ujistit, že jsou všechny platné, proveďte ověření konfigurace.", "invalid": "Konfigurace není v pořádku!", "valid": "Konfigurace je v pořádku!" } @@ -2928,6 +2936,7 @@ "follow_device_instructions": "Podle pokynů dodaných se zařízením aktivujte párování na zařízení.", "inclusion_failed": "Uzel nelze přidat. Další informace najdete v protokolech.", "inclusion_finished": "Uzel byl přidán.", + "interview_failed": "Komunikace se zařízením se nezdařila. V logách mohou být k dispozici další informace.", "introduction": "Tento průvodce vás provede přidáním uzlu do vaší sítě Z-Wave.", "secure_inclusion_warning": "Zabezpečená zařízení vyžadují větší šířku pásma; příliš mnoho zabezpečených zařízení může zpomalit vaši síť Z-Wave. Bezpečné začlenění doporučujeme používat pouze u zařízení, která to vyžadují, jako jsou zámky nebo otvírače garážových vrat.", "start_inclusion": "Zahájit začlenění", @@ -3157,6 +3166,7 @@ "copy_id": "Zkopírovat ID do schránky", "current_entities": "Současné entity", "description1": "Nastavte stav zařízení v Home Assistant.", + "description2": "Pokud entita patří k zařízení, neprobíhá s tímto zařízením žádná skutečná komunikace.", "entity": "Entita", "filter_attributes": "Filtrovat atributy", "filter_entities": "Filtrovat entity", diff --git a/translations/frontend/de.json b/translations/frontend/de.json index 32294da3bd..abb367366c 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -368,6 +368,8 @@ "error": "Ein unbekannter Fehler ist aufgetreten.", "error_addon_no_ingress": "Das angeforderte Add-on unterstützt keinen Ingress", "error_addon_not_found": "Add-on nicht gefunden", + "error_addon_not_installed": "Das angeforderte Add-on ist nicht installiert. Bitte installiere es zuerst", + "error_addon_not_started": "Das angeforderte Add-on läuft nicht. Bitte starte es zuerst", "faq_link": "Häufig gestellten Fragen zu Home Assistant", "not_supported": "Diese Weiterleitung wird von deiner Home Assistant-Instanz nicht unterstützt. Überprüfe den {link} auf die unterstützten Weiterleitungen und die Version, in der sie eingeführt wurden." }, @@ -385,8 +387,13 @@ "create_blocked_not_running": "Das Erstellen eines Snapshots ist derzeit nicht möglich, da sich das System im Zustand {state} befindet.", "create_snapshot": "Datensicherung erstellen", "created": "Erstellt", + "delete_selected": "Ausgewählten Snapshot löschen", + "delete_snapshot_confirm": "löschen", + "delete_snapshot_text": "Möchtest du {number} {number, plural,\n one {den Snapshot}\n other {die Snapshots}\n} löschen?", + "delete_snapshot_title": "Snapshot löschen", "description": "Datensicherungen ermöglichen dir das leichte Speichern und Wiederherstellen von allen Daten aus Home Assistant.", "enter_password": "Bitte Passwort eingeben.", + "failed_to_delete": "Löschen fehlgeschlagen", "folder": { "addons/local": "Lokale Add-ons", "homeassistant": "Home Assistant-Konfiguration", @@ -403,6 +410,8 @@ "password_protected": "Passwort geschützt", "password_protection": "Passwortschutz", "security": "Sicherheit", + "select_type": "Wähle aus, was wiederhergestellt werden soll", + "selected": "{number} ausgewählt", "type": "Typ", "upload_snapshot": "Datensicherung hochladen" }, @@ -720,6 +729,9 @@ "no_match": "Keine übereinstimmende Bereiche gefunden", "show_areas": "Bereiche anzeigen" }, + "attributes": { + "expansion_header": "Attribute" + }, "blueprint-picker": { "add_user": "Benutzer hinzufügen", "remove_user": "Benutzer entfernen", @@ -921,6 +933,9 @@ "config_entry_system_options": { "enable_new_entities_description": "Wenn deaktiviert werden neu erkannte Entitäten für {integration} nicht automatisch zu Home Assistant hinzugefügt.", "enable_new_entities_label": "Neu hinzugefügte Entitäten aktivieren.", + "enable_polling_description": "Ob Home Assistant automatisch {integration} Entitäten nach Updates abfragen soll.", + "enable_polling_label": "Aktiviere Polling für Updates.", + "restart_home_assistant": "Du musst Home Assistant neu starten, damit deine Änderungen wirksam werden.", "title": "Einstellungen für {integration}", "update": "Aktualisieren" }, @@ -1719,6 +1734,7 @@ "title": "Alexa" }, "connected": "Verbunden", + "connecting": "Verbinde...", "connection_status": "Cloud-Verbindungsstatus", "fetching_subscription": "Abo wird abgerufen ...", "google": { @@ -2062,7 +2078,8 @@ "scripts": "Skripte", "unknown_error": "Unbekannter Fehler", "unnamed_device": "Unbenanntes Gerät", - "update": "Aktualisieren" + "update": "Aktualisieren", + "update_device_error": "Aktualisieren des Geräts fehlgeschlagen" }, "entities": { "caption": "Entitäten", @@ -2195,6 +2212,7 @@ "depends_on_cloud": "Abhängig von der Cloud", "device_unavailable": "Gerät nicht verfügbar", "devices": "{count} {count, plural,\n one {Gerät}\n other {Geräte}\n}", + "disable_error": "Aktivieren oder Deaktivieren der Integration fehlgeschlagen", "disable_restart_confirm": "Home Assistant neu starten, um das Deaktivieren dieser Integration abzuschließen", "disable": { "disable_confirm": "Möchtest du diesen Konfigurationseintrag wirklich deaktivieren? Die Geräte und Entitäten werden deaktiviert.", @@ -2206,6 +2224,7 @@ }, "disabled_cause": "Deaktiviert durch {cause}." }, + "disabled_polling": "Automatisches Abfragen nach aktualisierten Daten deaktiviert", "documentation": "Dokumentation", "enable_restart_confirm": "Home Assistant neu starten, um das Aktivieren dieser Integration abzuschließen", "entities": "{count} {count, plural,\none {Entität}\nother {Entitäten}\n}", @@ -2959,6 +2978,7 @@ }, "logs": { "log_level": "Protokollstufe", + "log_level_changed": "Log Level geändert auf: {level}", "subscribed_to_logs": "Abonniert Z-Wave JS-Protokollnachrichten ...", "title": "Z-Wave JS Protokolle" }, diff --git a/translations/frontend/en.json b/translations/frontend/en.json index b2ff6ed221..00c78cbeeb 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -2721,7 +2721,7 @@ "validation": { "check_config": "Check configuration", "heading": "Configuration validation", - "introduction": "Validate your configuration if you recently made some changes to your configuration and want to make sure that it is all valid", + "introduction": "Validate your configuration if you recently made some changes to your configuration and want to make sure that it is all valid.", "invalid": "Configuration invalid", "valid": "Configuration valid!" } diff --git a/translations/frontend/es-419.json b/translations/frontend/es-419.json index 7745b01ec5..6df6c79aaf 100644 --- a/translations/frontend/es-419.json +++ b/translations/frontend/es-419.json @@ -367,6 +367,8 @@ "my": { "error": "Ha ocurrido un error desconocido", "error_addon_not_found": "Complemento no encontrado", + "error_addon_not_installed": "El complemento solicitado no está instalado. Por favor instálelo primero", + "error_addon_not_started": "El complemento solicitado no se están ejecutando. Por favor inícielo antes.", "faq_link": "Mis preguntas frecuentes de Home Assistant", "not_supported": "Esta redirección no está soportada por su instancia de Home Assistant. Consulte las redirecciones soportadas y la versión en la que fueron introducidas en {link}." }, @@ -2031,7 +2033,8 @@ "scripts": "Scripts", "unknown_error": "Error desconocido", "unnamed_device": "Dispositivo sin nombre", - "update": "Actualizar" + "update": "Actualizar", + "update_device_error": "Error al actualizar el dispositivo" }, "entities": { "caption": "Entidades", @@ -2163,6 +2166,7 @@ "depends_on_cloud": "Depende de la nube", "device_unavailable": "Dispositivo no disponible", "devices": "{count} {count, plural,\n one {dispositivo}\n other {dispositivos}\n}", + "disable_error": "Ha fallado la habilitación o deshabilitación de la integración", "disable_restart_confirm": "Reinicie Home Assistant para terminar de deshabilitar esta integración", "disable": { "disable_confirm": "¿Está seguro de que desea deshabilitar esta entrada de configuración? Sus dispositivos y entidades serán deshabilitados.", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index 002eb09069..9b28f1c447 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -368,6 +368,8 @@ "error": "Se ha producido un error desconocido", "error_addon_no_ingress": "El complemento solicitado no admite la entrada", "error_addon_not_found": "Complemento no encontrado", + "error_addon_not_installed": "El complemento solicitado no está instalado. Por favor instálalo primero", + "error_addon_not_started": "El complemento solicitado no se está ejecutando. Por favor, inícialo primero", "faq_link": "Preguntas frecuentes sobre mi Home Assistant", "not_supported": "Esta redirección no es compatible con tu instancia de Home Assistant. Consulta el {link} para conocer las redirecciones admitidas y la versión en la que se introdujeron." }, @@ -2719,7 +2721,7 @@ "validation": { "check_config": "Verificar configuración", "heading": "Validación de la configuración", - "introduction": "Valida tu configuración si has realizado cambios recientemente y quieres asegurarte de que son correctos", + "introduction": "Valida tu configuración si has realizado cambios recientemente en ella y quieres asegurarte de que son correctos", "invalid": "Configuración no válida", "valid": "¡Configuración valida!" } diff --git a/translations/frontend/et.json b/translations/frontend/et.json index c017a16e88..18ce2c5330 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -368,6 +368,8 @@ "error": "Viga", "error_addon_no_ingress": "Valitud lisandmoodul ei toeta ingressi", "error_addon_not_found": "Lisandmoodulit ei leitud", + "error_addon_not_installed": "Soovitud lisandmoodul pole pigaldatud. Alustamiseks paigalda see", + "error_addon_not_started": "Soovitud lisandmoodul ei tööta. Alustamiseks käivita see", "faq_link": "KKK viide", "not_supported": "pole toetatud" }, @@ -929,7 +931,7 @@ }, "dialogs": { "config_entry_system_options": { - "enable_new_entities_description": "Kas lisada äsja avastatud sidumise {integration} olemed automaatselt Home Assistant'i.", + "enable_new_entities_description": "Kas lisada äsja avastatud sidumise {integration} olemeid automaatselt Home Assistant'i.", "enable_new_entities_label": "Luba äsja lisatud olemid.", "enable_polling_description": "Kas Home Assistant peaks automaatselt küsitlema {integration} üksusi uuenduste saamiseks.", "enable_polling_label": "Luba värskenduste jaoks küsitlus.", @@ -2719,7 +2721,7 @@ "validation": { "check_config": "Kontrolli seadeid", "heading": "Seadete kontrollimine", - "introduction": "Kontrolli oma seadeid kui oled neis hiljuti muutusi teinud ja tahad veenduda, et kõik on korrektne", + "introduction": "Kontrolli oma seadeid kui oled neis hiljuti muutusi teinud ja tahad veenduda, et kõik on korrektne.", "invalid": "Konfiguratsioon on vigane", "valid": "Konfiguratsioon on korrektne!" } diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index c028a51af8..8165ff6aed 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -368,6 +368,8 @@ "error": "알 수 없는 오류가 발생했습니다", "error_addon_no_ingress": "해당 애드온은 인그레스를 지원하지 않습니다.", "error_addon_not_found": "애드온을 찾을 수 없습니다", + "error_addon_not_installed": "해당 애드온은 설치되어있지 않습니다. 애드온을 설치해주세요.", + "error_addon_not_started": "해당 애드온은 실행중이지 않습니다. 애드온을 실행해주세요.", "faq_link": "내 Home Assistant 자주 묻는 질문", "not_supported": "이 리디렉션은 Home Assistant 인스턴스에서 지원되지 않습니다. {link}에서 지원되는 리디렉션과 리디렉션이 도입된 버전을 확인해주세요." }, diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index db4682fb93..db2b6757ab 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -368,6 +368,8 @@ "error": "En ukjent feil har oppstått", "error_addon_no_ingress": "Det etterspurte tillegget støtter ikke inngang", "error_addon_not_found": "Tillegget ble ikke funnet", + "error_addon_not_installed": "Det forespurte tillegget er ikke installert. Vennligst installer den først", + "error_addon_not_started": "Det valgte tillegget kjører ikke. Vennligst start den først", "faq_link": "Vanlige spørsmål om Min Home Assistant", "not_supported": "Denne viderekoblingen støttes ikke av Home Assistant-forekomsten. Se på {link} for viderekoblinger som støttes, og hvilken versjon de ble introdusert." }, @@ -2719,7 +2721,7 @@ "validation": { "check_config": "Sjekk konfigurasjonen", "heading": "Validering av konfigurasjon", - "introduction": "Valider konfigurasjonen hvis du nylig har gjort endringer i konfigurasjonen og vil forsikre deg om at den er gyldig", + "introduction": "Bekreft konfigurasjonen hvis du nylig har gjort noen endringer i konfigurasjonen og vil være sikker på at den er gyldig.", "invalid": "Ugyldig konfigurasjon", "valid": "Gyldig konfigurasjon" } diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index f9460cbeec..d3e4bd25c9 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -368,6 +368,8 @@ "error": "Er is een onbekende fout opgetreden", "error_addon_no_ingress": "De gevraagde add-on ondersteunt geen ingress", "error_addon_not_found": "Invoegtoepassing niet gevonden", + "error_addon_not_installed": "De gevraagde add-on is niet geïnstalleerd. Gelieve deze eerst te installeren", + "error_addon_not_started": "De gevraagde add-on is niet actief. Start deze a.u.b. eerst", "faq_link": "My Home Assistant FAQ", "not_supported": "Deze redirect wordt niet ondersteund door uw Home Assistant instantie. Controleer de {link} voor de ondersteunde redirects en de versie waarin ze zijn geïntroduceerd." }, diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index c2c22c3b6e..73cf60fb11 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -368,6 +368,8 @@ "error": "Wystąpił nieznany błąd", "error_addon_no_ingress": "Żądany dodatek nie obsługuje osadzania", "error_addon_not_found": "Nie znaleziono dodatku", + "error_addon_not_installed": "Żądany dodatek nie jest zainstalowany. Najpierw go zainstaluj.", + "error_addon_not_started": "Żądany dodatek nie jest uruchomiony. Proszę najpierw go uruchomić.", "faq_link": "Mój Home Assistant - często zadawane pytania", "not_supported": "To przekierowanie nie jest obsługiwane przez Twoją instancję Home Assistanta. Sprawdź {link} aby znaleźć obsługiwane przekierowania i wersję, w której zostały wprowadzone." }, @@ -929,8 +931,11 @@ }, "dialogs": { "config_entry_system_options": { - "enable_new_entities_description": "Jeśli wyłączone, nowo wykryte encje integracji {integration} nie będą automatycznie dodawane do Home Assistanta.", + "enable_new_entities_description": "Jeśli nowo odkryte urządzenia dla integracji {integration} powinny zostać dodane automatycznie.", "enable_new_entities_label": "Włącz dodawanie nowych encji.", + "enable_polling_description": "Czy Home Assistant powinien automatycznie odpytywać encje {integration} w poszukiwaniu aktualizacji.", + "enable_polling_label": "Włącz odpytywanie o aktualizacje.", + "restart_home_assistant": "Aby zmiany zostały wprowadzone, musisz ponownie uruchomić Home Assistanta.", "title": "Opcje systemowe dla {integration}", "update": "Aktualizuj" }, @@ -2073,7 +2078,8 @@ "scripts": "Skrypty", "unknown_error": "Nieznany błąd", "unnamed_device": "Nienazwane urządzenie", - "update": "Aktualizuj" + "update": "Aktualizuj", + "update_device_error": "Aktualizacja urządzenia nie powiodła się" }, "entities": { "caption": "Rejestr encji", @@ -2206,6 +2212,7 @@ "depends_on_cloud": "Zależny od chmury", "device_unavailable": "Urządzenie niedostępne", "devices": "{count} {count, plural,\n one {urządzenie}\n few {urządzenia}\n many {urządzeń}\n other {urządzeń}\n}", + "disable_error": "Nie udało się włączyć lub wyłączyć integracji", "disable_restart_confirm": "Zrestartuj Home Assistanta, aby zakończyć wyłączanie tej integracji", "disable": { "disable_confirm": "Czy na pewno chcesz wyłączyć ten wpis w konfiguracji? Jego urządzenia i instancje zostaną wyłączone.", @@ -2217,6 +2224,7 @@ }, "disabled_cause": "Wyłączone przez {cause}." }, + "disabled_polling": "Automatyczne odpytywanie o zaktualizowane dane jest wyłączone", "documentation": "Dokumentacja", "enable_restart_confirm": "Uruchom ponownie Home Assistanta, aby dokończyć uruchamianie tej integracji", "entities": "{count} {count, plural,\n one {encja}\n few {encje}\n many {encji}\n other {encji}\n}", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index b6bd827b75..37753f8016 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -2721,7 +2721,7 @@ "validation": { "check_config": "Начать проверку", "heading": "Проверка конфигурации", - "introduction": "Проверьте файлы конфигурации, если Вы внесли в них изменения.", + "introduction": "Выполните проверку конфигурации, если в неё были внесены изменения и Вы хотите убедиться в её работоспособности.", "invalid": "Ошибка в конфигурации", "valid": "Конфигурация выполнена верно" } diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index 5a64668803..55f5ee6d20 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -368,6 +368,8 @@ "error": "发生未知错误", "error_addon_no_ingress": "请求的加载项不支持 ingress", "error_addon_not_found": "未找到加载项", + "error_addon_not_installed": "请求的加载项尚未安装,请先安装", + "error_addon_not_started": "请求的加载项未运行,请先运行", "faq_link": "我的 Home Assistant 常见问题", "not_supported": "您的 Home Assistant 不支持此重定向。请查阅{link}以获取受支持的重定向及其引入的版本。" }, @@ -2719,7 +2721,7 @@ "validation": { "check_config": "检查配置", "heading": "配置检查", - "introduction": "此处可以帮助您检验最新修改的配置文件有效性", + "introduction": "此处可以帮助您检验最新修改的配置文件的有效性。", "invalid": "配置无效", "valid": "配置有效!" } diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index 3290d42a9c..81805be4b7 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -368,6 +368,8 @@ "error": "發生未知錯誤", "error_addon_no_ingress": "所要求的附加元件不支援 ingress", "error_addon_not_found": "找不到附加元件", + "error_addon_not_installed": "所要求的附加元件未安裝,請先進行安裝。", + "error_addon_not_started": "所要求的附加元件未執行,請先進行啟動。", "faq_link": "Home Assistant 常見問答集", "not_supported": "Home Assistant 不支援此重新導向。點選 {link} 獲取支援之重新導向與版本。" }, @@ -2719,7 +2721,7 @@ "validation": { "check_config": "檢查設定內容", "heading": "設定驗證", - "introduction": "如果您對設定進行了一些更改、並且想確保設定有無錯誤,可以選擇驗證設定內容。", + "introduction": "如果您對設定進行了部分更改、並且想確保設定有無錯誤,可以選擇驗證設定內容。", "invalid": "設定無效", "valid": "設定檔內容檢查正確" } From c2792a28ba01e8c1cfa0d2bfd781328bab2f8db4 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sat, 5 Jun 2021 12:52:27 +0200 Subject: [PATCH 04/73] Move attributes down in more info person and timer (#9368) --- src/dialogs/more-info/controls/more-info-person.ts | 10 +++++----- src/dialogs/more-info/controls/more-info-timer.ts | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/dialogs/more-info/controls/more-info-person.ts b/src/dialogs/more-info/controls/more-info-person.ts index 328b73dc97..ea7858de78 100644 --- a/src/dialogs/more-info/controls/more-info-person.ts +++ b/src/dialogs/more-info/controls/more-info-person.ts @@ -23,11 +23,6 @@ class MoreInfoPerson extends LitElement { } return html` - ${this.stateObj.attributes.latitude && this.stateObj.attributes.longitude ? html` ` : ""} + `; } diff --git a/src/dialogs/more-info/controls/more-info-timer.ts b/src/dialogs/more-info/controls/more-info-timer.ts index daf2e8e97f..e3ab452ea7 100644 --- a/src/dialogs/more-info/controls/more-info-timer.ts +++ b/src/dialogs/more-info/controls/more-info-timer.ts @@ -17,11 +17,6 @@ class MoreInfoTimer extends LitElement { } return html` -
${this.stateObj.state === "idle" || this.stateObj.state === "paused" ? html` @@ -57,6 +52,11 @@ class MoreInfoTimer extends LitElement { ` : ""}
+ `; } From 299c863f49940d2ef734e4b4f042719a4b5a264e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 23:52:13 +0200 Subject: [PATCH 05/73] Bump ws from 6.2.1 to 6.2.2 (#9372) --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index af5d0f949e..8fd9b8db50 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4041,9 +4041,9 @@ async-each@^1.0.0, async-each@^1.0.1: integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg== async-limiter@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== async-settle@^1.0.0: version "1.0.0" @@ -13503,9 +13503,9 @@ write@1.0.3: mkdirp "^0.5.1" ws@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== dependencies: async-limiter "~1.0.0" From 2e9aafc377df005022a798619e1e4f49a0a42b88 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 6 Jun 2021 00:49:09 +0000 Subject: [PATCH 06/73] Translation update --- translations/frontend/bg.json | 2 +- translations/frontend/he.json | 1522 ++++++++++++++++++++++++--------- translations/frontend/it.json | 2 +- translations/frontend/ru.json | 4 +- 4 files changed, 1140 insertions(+), 390 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index 26a266478d..55c754025b 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -498,7 +498,7 @@ "heating": "{name} отопление", "high": "високо", "low": "ниско", - "on_off": "Вкл. / Изкл", + "on_off": "Вкл. / Изкл.", "operation": "Режим", "preset_mode": "Предварително зададени настройки", "swing_mode": "Режим на люлеене", diff --git a/translations/frontend/he.json b/translations/frontend/he.json index 9d635a92e9..a50118c73d 100644 --- a/translations/frontend/he.json +++ b/translations/frontend/he.json @@ -1,7 +1,7 @@ { "config_entry": { "disabled_by": { - "config_entry": "ערך תצורה", + "config_entry": "תצורת כניסה", "device": "מכשיר", "integration": "אינטגרציה", "user": "משתמש" @@ -15,16 +15,16 @@ }, "panel": { "calendar": "לוח שנה", - "config": "הגדרות", + "config": "תצורה", "developer_tools": "כלים למפתחים", "history": "היסטוריה", - "logbook": "יומן אירועים", + "logbook": "יומן רישום", "mailbox": "תיבת דואר", "map": "מפה", "media_browser": "סייר המדיה", "profile": "פרופיל", "shopping_list": "רשימת קניות", - "states": "ראשי" + "states": "סקירה כללית" }, "state_attributes": { "climate": { @@ -68,11 +68,11 @@ }, "state_badge": { "alarm_control_panel": { - "armed": "מופעל", - "armed_away": "מופעל", - "armed_custom_bypass": "מופעל", - "armed_home": "מופעל", - "armed_night": "מופעל", + "armed": "דרוך", + "armed_away": "דרוך", + "armed_custom_bypass": "דרוך", + "armed_home": "דרוך", + "armed_night": "דרוך", "arming": "דורך", "disarmed": "לא דרוך", "disarming": "מבטל", @@ -80,18 +80,18 @@ "triggered": "מופעל" }, "default": { - "entity_not_found": "ישות לא נמצאה", + "entity_not_found": "הישות לא נמצאה", "error": "שגיאה", "unavailable": "לא זמין", "unknown": "לא ידוע" }, "device_tracker": { "home": "בבית", - "not_home": "לא נמצא" + "not_home": "לא בבית" }, "person": { "home": "בבית", - "not_home": "לא נמצא" + "not_home": "לא בבית" } }, "state": { @@ -104,44 +104,219 @@ }, "supervisor": { "addon": { + "configuration": { + "audio": { + "default": "ברירת מחדל", + "header": "שמע", + "input": "קלט", + "output": "פלט" + }, + "network": { + "container": "מכולה", + "disabled": "מושבת", + "header": "רשת", + "host": "מארח" + }, + "no_configuration": "הרחבה זו אינה חושפת תצורה עבורך כדי להתעסק עם...", + "options": { + "edit_in_ui": "ערוך בממשק המשתמש", + "edit_in_yaml": "עריכה ב-YAML", + "header": "אפשרויות", + "invalid_yaml": "YAML לא חוקי", + "show_unused_optional": "הצג אפשרויות תצורה אופציונליות שאינן בשימוש" + } + }, "dashboard": { "action_error": { "get_changelog": "קבלת יומן שינויים של התוסף נכשלה", + "go_to_config": "הפעלת ההרחבה נכשלה - אימות התצורה נכשל!", + "install": "התקנת הרחבה נכשלה", + "restart": "הפעלה מחדש של הרחבה נכשלה", + "start": "הפעלת ההרחבה נכשלה", + "start_invalid_config": "עבור לתצורה", + "stop": "הפסקת ההרחבה נכשלה", + "uninstall": "הסרת התקנת ההרחבה נכשלה", "validate_config": "אימות תצורת התוסף נכשל" }, + "capability": { + "apparmor": { + "description": "AppArmor ('שריון יישומים') הוא מודול אבטחה של ליבת לינוקס המגביל יכולות הרחבות כגון גישה לרשת, גישה לשקע גולמי והרשאה לקרוא, לכתוב או לבצע קבצים ספציפיים.\n\nעורכי הרחבות יכולים לספק את פרופילי האבטחה שלהם, ממוטבים עבור ההרחבה או לבקש להפוך אותה ללא זמינה. אם AppArmor מושבת, זה יעלה את סיכוני האבטחה ולכן, יש השפעה שלילית על ניקוד האבטחה של ההרחבה.", + "title": "AppArmor" + }, + "auth_api": { + "description": "הרחבה יכולה לאמת משתמשים מול Home Assistant, דבר המאפשר להרחבות להעניק למשתמשים את האפשרות להיכנס ליישומים הפועלים בתוך הרחבות, באמצעות שם המשתמש/הסיסמה של Home Assistant שלהם. תג זה מציין אם מחבר ההרחבה מבקש יכולת זו.", + "title": "אימות Home Assistant" + }, + "docker_api": { + "description": "מחבר ההרחבה ביקש שההרחבה תהיה בעלת גישת ניהול למופע Docker הפועל במערכת שלך. מצב זה מעניק להרחבה גישה ושליטה מלאה למערכת Home Assistant כולה, מה שמוסיף סיכוני אבטחה ועלול לגרום נזק למערכת בעת שימוש לרעה. לכן, תכונה זו משפיעה לרעה על תוצאת אבטחת ההרחבה.\n\nרמת גישה זו אינה מוענקת באופן אוטומטי ועליך להיות מאושרת על ידיך. כדי לעשות זאת, עליך להשבית את מצב ההגנה בהרחבה באופן ידני. הפוך את מצב ההגנה ללא זמין רק אם ידוע לך, עליך לתת אמון במקור של הרחבה זו.", + "title": "גישה מלאה ל-docker" + }, + "full_access": { + "description": "הרחבה זו מקבלת גישה מלאה לחומרת המערכת שלך, לפי בקשת מחבר ההרחבה. הגישה דומה למצב מורשה ב-Docker. מאחר שתכונה זו פותחת סיכוני אבטחה אפשריים, תכונה זו משפיעה לרעה על תוצאת אבטחת ההרחבה.\n\nרמת גישה זו אינה מוענקת באופן אוטומטי ועליך להיות מאושרת על ידיך. כדי לעשות זאת, עליך להשבית את מצב ההגנה בהרחבה באופן ידני. הפוך את מצב ההגנה ללא זמין רק אם ידוע לך, עליך לתת אמון במקור של הרחבה זו.", + "title": "גישה מלאה לחומרה" + }, + "hassio_api": { + "description": "ההרחבה ניתנה גישה ל-API של המפקח, לבקשת מחבר ההרחבה. כברירת מחדל, ההרחבה יכולה לגשת למידע גירסה כללי של המערכת שלך. כאשר ההרחבה מבקשת גישה ברמת 'מנהל' או 'מנהל' ל-API, היא תקבל גישה לשליטה בחלקים מרובים של מערכת Home Assistant שלך. הרשאה זו מצוינת על ידי תג זה ותשפיע לרעה על תוצאת האבטחה של ההרחבה.", + "title": "גישת API למפקח" + }, + "homeassistant_api": { + "description": "הרחבה זו מותרת לגשת למופע Home Assistant הפועל שלך ישירות באמצעות ה-API של Home Assistant. מצב זה מטפל באימות גם עבור ההרחבה, המאפשר להרחבה לקיים אינטראקציה עם Home Assistant ללא צורך באסימוני אימות נוספים.", + "title": "גישה ל-API של Assistant Home" + }, + "host_network": { + "description": "הרחבות פועלות בדרך כלל בשכבת רשת מבודדת משלהן, המונעת מהן גישה לרשת של מערכת ההפעלה המארחת. במקרים מסוימים, בידוד רשת זה יכול להגביל הרחבות במתן השירותים שלהם ולכן, מחבר ההרחבה יכול להסיר את הבידוד, מה שמעניק להרחבה גישה מלאה ליכולות הרשת של המחשב המארח. פעולה זו מעניקה להרחבה יכולות רשת נוספות אך מורידה את האבטחה, ומכאן, דירוג האבטחה של ההרחבה יופחת כאשר אפשרות זו תשמש את ההרחבה.", + "title": "רשת מארח" + }, + "host_pid": { + "description": "בדרך כלל, התהליכים שההרחבה מפעילה מבודדים מכל תהליכי המערכת האחרים. מחבר ההרחבה ביקש מההרחבה לקבל גישה לתהליכי המערכת הפועלים במופע המערכת המארחת, ולאפשר להרחבה להוליד תהליכים גם במערכת המארחת. מצב זה מעניק להרחבה גישה ושליטה מלאה למערכת Home Assistant כולה, מה שמוסיף סיכוני אבטחה ועלול לגרום נזק למערכת בעת שימוש לרעה. לכן, תכונה זו משפיעה לרעה על תוצאת אבטחת ההרחבה.\n\nרמת גישה זו אינה מוענקת באופן אוטומטי ועליך להיות מאושרת על-ידיך. כדי לעשות זאת, עליך להשבית את מצב ההגנה בהרחבה באופן ידני. הפוך את מצב ההגנה ללא זמין רק אם ידוע לך, עליך לתת אמון במקור של הרחבה זו.", + "title": "מרחב שמות של תהליכי מארח" + }, + "ingress": { + "description": "תוסף זה משתמש ב-Ingress כדי להטמיע את הממשק שלו בצורה מאובטחת ב-Home Assistant.", + "title": "חדירה" + }, + "label": { + "apparmor": "apparmor", + "auth": "אימות", + "docker": "docker", + "hardware": "חומרה", + "hass": "hass", + "hassio": "hassio", + "host": "מארח", + "host_pid": "pid של מארח", + "ingress": "חדירה", + "rating": "דירוג", + "stage": "שלב" + }, + "rating": { + "description": "Home Assistant מספק דירוג אבטחה לכל אחת מההרחבות, המציין את הסיכונים הכרוכים בשימוש בהרחבה זו. ככל שההרחבה דורשת גישה רבה יותר למערכת שלך, כך הציון נמוך יותר, ובכך מעלה את סיכוני האבטחה האפשריים.\n\nציון הוא בסולם מ 1 עד 6. כאשר 1 הוא הציון הנמוך ביותר (נחשב לסיכון הגבוה ביותר וחסר ביטחון) וציון של 6 הוא הציון הגבוה ביותר (נחשב לסיכון הבטוח והנמוך ביותר).", + "title": "דירוג אבטחה של הרחבה" + }, + "role": { + "admin": "מנהל מערכת", + "backup": "גיבוי", + "default": "ברירת מחדל", + "homeassistant": "homeassistant", + "manager": "מנהל" + }, + "stage": { + "description": "הרחבות יכולות להיות אחד משלושה שלבים:\n\n{icon_stable} **יציב**: אלו הרחבות המוכנות לשימוש במערכת מתפקדת.\n\n{icon_experimental} **נסיוני**: אלו עשויים להכיל באגים, וייתכן שהם לא גמורים.\n\n{icon_deprecated} **הוצא משימוש**: הרחבות אלו כבר לא יקבלו עדכונים.", + "title": "שלב הרחבה" + } + }, + "changelog": "יומן שינויים", + "cpu_usage": "שימוש ב-CPU של הרחבה", + "hostname": "שם מארח", + "install": "התקנה", + "new_update_available": "{name} {version} זמין", + "not_available_arch": "הרחבה זו אינה תואמת למעבד ההתקן או למערכת ההפעלה שהתקנת בהתקן שלך.", "not_available_version": "אתה מפעיל את Home Assistant {core_version_installed} , כדי לעדכן לגרסה זו של התוסף אתה זקוק לפחות לגרסה {core_version_needed} של Home Assistant", + "open_web_ui": "פתח ממשק משתמש אינטרנטי", + "option": { + "auto_update": { + "description": "עדכן אוטומטית את ההרחבה כאשר גירסה חדשה זמינה", + "title": "עדכון אוטומטי" + }, + "boot": { + "description": "הפעלת ההרחבה במהלך אתחול מערכת", + "title": "הפעל באתחול" + }, + "ingress_panel": { + "description": "הוסף הרחבה זו לסרגל הצד", + "title": "הצג בסרגל הצד" + }, + "protected": { + "description": "חסימת גישה מוגברת למערכת מההרחבה", + "title": "מצב הגנה" + }, + "watchdog": { + "description": "פעולה זו תפעיל את ההרחבה אם היא תקרוס", + "title": "כלב שמירה" + } + }, + "protection_mode": { + "content": "מצב הגנה על הרחבה זו מושבת! פעולה זו מעניקה להרחבה גישה מלאה למערכת כולה, מה שמוסיף סיכוני אבטחה ועלול לגרום נזק למערכת בעת שימוש שגוי. הפוך את מצב ההגנה ללא זמין רק אם אתה יודע מה אתה עושה, עליך לתת אמון במקור של הרחבה זו.", + "enable": "אפשר מצב הגנה", + "title": "אזהרה: מצב ההגנה מושבת!" + }, + "ram_usage": "שימוש ב-RAM של הרחבה", + "rebuild": "בנייה מחדש", + "restart": "הפעלה מחדש", + "start": "התחל", + "stop": "עצור", + "uninstall": "הסרת התקנה", "visit_addon_page": "בקר בדף {name} לפרטים נוספים" }, "documentation": { "get_documentation": "קבלת תיעוד התוסף נכשלה, {error}" }, + "failed_to_reset": "איפוס תצורת ההרחבה נכשל, {error}", + "failed_to_save": "שמירת תצורת ההרחבה נכשלה, {error}", "logs": { "get_logs": "קבלת יומני התוסף נכשלה, {error}" + }, + "panel": { + "configuration": "תצורה", + "documentation": "תיעוד", + "info": "מידע", + "log": "יומן" + }, + "state": { + "installed": "ההרחבה מותקנת", + "not_available": "הרחבה אינה זמינה במערכת שלך", + "not_installed": "ההרחבה אינה מותקנת" } }, "common": { - "cancel": "בטל", + "cancel": "ביטול", "close": "סגור", "description": "תיאור", "error": { - "unknown": "בעיה לא ידועה" + "unknown": "בעיה לא ידועה", + "update_failed": "העדכון נכשל" }, "failed_to_restart_name": "אתחול {name} נכשל.", "failed_to_update_name": "עדכון {name} נכשל.", "learn_more": "למד עוד", "new_version_available": "גרסה חדשה זמינה", + "newest_version": "הגרסה החדשה ביותר", "no": "לא", "refresh": "רענן", + "release_notes": "הערות שיחרור", "reload": "טען מחדש", "reset_defaults": "אפס לברירות מחדל", + "reset_options": "אפשרויות איפוס", + "restart": "הפעלה מחדש", + "restart_name": "הפעל מחדש את {name}", + "running_version": "אתה מריץ כעת גרסה {version}", "save": "שמור", + "show_more": "הראה מידע נוסף על כך", + "update": "עדכן", + "update_available": "{count, plural,\n one {עדכון}\n other {{count} עדכונים}\n} בהמתנה", + "version": "גירסה", "yes": "כן" }, "confirm": { + "reset_options": { + "text": "האם אתה בטוח שברצונך לאפס את כל האפשרויות שלך?", + "title": "אפשרויות איפוס" + }, + "restart": { + "text": "האם אתה בטוח שברצונך להפעיל מחדש את {name}?", + "title": "הפעל מחדש את {name}" + }, "update": { + "text": "האם אתה בטוח שברצונך לעדכן את {name} לגרסה {version}?", "title": "עדכן את {name}" } }, + "dashboard": { + "addon_new_version": "גירסה חדשה זמינה", + "addon_running": "ההרחבה פועלת", + "addon_stopped": "ההרחבה הופסקה", + "addons": "הרחבות מותקנות", + "no_addons": "עדיין לא מותקנות הרחבות. גשו לחנות ההרחבה כדי להתחיל!" + }, "dialog": { "network": { "connected_to": "מחובר אל {ssid}", @@ -169,8 +344,8 @@ "password": "סיסמה", "registry": "מאגר", "remove": "הסר", - "title_add": "הוסף מאגר Container", - "title_manage": "ניהול מאגרי Container", + "title_add": "הוסף רישום מכולה חדשה", + "title_manage": "ניהול מאגרי מכולות", "username": "שם משתמש" }, "repositories": { @@ -179,8 +354,8 @@ "title": "נהל את מאגרי ההרחבות" }, "restart_addon": { - "confirm_text": "אתחל את התוסף", - "text": "האם ברצונך לאתחל את התוסף עם השינויים שלך?" + "confirm_text": "הפעל מחדש את ההרחבה", + "text": "האם ברצונך להפעיל מחדש את ההרחבה עם השינויים שביצעת?" }, "update": { "create_snapshot": "צור נקודת גיבוי עבור {name} לפני העדכון", @@ -190,9 +365,19 @@ } }, "my": { - "error": "שגיאה לא ידועה התרחשה", + "error": "אירעה שגיאה לא ידועה", + "error_addon_no_ingress": "ההרחבה המבוקשת אינו תומכת בכניסה", "error_addon_not_found": "התוסף לא נמצא", - "faq_link": "שאלות ותשובות של Home Assistant" + "error_addon_not_installed": "התוסף המבוקש אינו מותקן. אנא התקן אותו תחילה", + "error_addon_not_started": "התוסף המבוקש אינו פועל. אנא הפעל אותו תחילה", + "faq_link": "שאלות נפוצות על Home Assistant שלי", + "not_supported": "הפניה זו אינה נתמכת על ידי מופע ה-Home Assistant שלך. בדוק ב-{link} את ההפניות הנתמכות ואת הגרסה שהוצגה." + }, + "panel": { + "dashboard": "לוח בקרה", + "snapshots": "גיבויים", + "store": "חנות הרחבות", + "system": "מערכת" }, "snapshot": { "addons": "תוספים", @@ -201,8 +386,14 @@ "create": "צור", "create_blocked_not_running": "יצירת גיבוי אינה אפשרית כרגע מכיוון שהמערכת במצב {state} .", "create_snapshot": "צור גיבוי", + "created": "נוצר", + "delete_selected": "מחק גיבויים שנבחרו", + "delete_snapshot_confirm": "מחיקה", + "delete_snapshot_text": "האם אתה רוצה למחוק {number} {number, plural,\n one {גיבוי}\n other {גיבויים}\n}?", + "delete_snapshot_title": "מחק גיבוי", "description": "גיבויים מאפשרים לך לגבות ולשחזר בקלות את כל הנתונים של Home Assistant.", "enter_password": "נא הזן סיסמה.", + "failed_to_delete": "המחיקה נכשלה", "folder": { "addons/local": "תוספות מקומיות", "homeassistant": "תצורת Home Assistant", @@ -212,24 +403,32 @@ }, "folders": "תיקיות", "full_snapshot": "גיבוי מלא", - "name": "שם", + "name": "שם נקודת גיבוי", "no_snapshots": "אין לך גיבויים כרגע.", "partial_snapshot": "גיבוי חלקי", "password": "סיסמה", "password_protected": "מוגן באמצעות סיסמה", "password_protection": "הגנה באמצעות סיסמה", "security": "אבטחה", - "type": "סוּג", + "select_type": "בחר מה לשחזר", + "selected": "{number} נבחרו", + "type": "סוג נקודת גיבוי", "upload_snapshot": "טען גיבוי" }, + "store": { + "missing_addons": "חסרות הרחבות? אפשר מצב מתקדם בדף פרופיל המשתמש שלך", + "no_results_found": "לא נמצאו תוצאות ב-{repository}.", + "registries": "רישומים", + "repositories": "מאגרים" + }, "system": { "core": { - "cpu_usage": "שימו ליבה ב CPU", - "ram_usage": "שימוש ליבה ב RAM" + "cpu_usage": "שימוש ליבה ב-CPU", + "ram_usage": "שימוש ליבה ב-RAM" }, "host": { "change": "שינוי", - "change_hostname": "שנה שם מכונה", + "change_hostname": "שנה שם המארח", "confirm_reboot": "האם אתה בטוח שאתה מעוניין לאתחל שרת מארח?", "confirm_shutdown": "האם אתה בטוח שאתה מעוניין לכבות שרת מארח?", "deployment": "פריסה", @@ -237,14 +436,14 @@ "emmc_lifetime_used": "eMMC Lifetime בשימוש", "failed_to_get_hardware_list": "קבלת רשימת החומרה נכשלה", "failed_to_import_from_usb": "ייבוא מ- USB נכשל", - "failed_to_reboot": "אתחול המכונה נכשל", - "failed_to_set_hostname": "הגדרת שם המכונה נכשלה", - "failed_to_shutdown": "כיבוי המכונה נכשל", + "failed_to_reboot": "אתחול המארח נכשל", + "failed_to_set_hostname": "הגדרת שם המארח נכשלה", + "failed_to_shutdown": "כיבוי המארח נכשל", "hardware": "חומרה", - "hostname": "שם מכונה", - "import_from_usb": "יבא מרכיב USB", + "hostname": "שם מארח", + "import_from_usb": "ייבא מ-USB", "ip_address": "כתובת IP", - "new_hostname": "אנא הזן שם מכונה חדש:", + "new_hostname": "אנא הזן שם מארח חדש:", "operating_system": "מערכת הפעלה", "reboot_host": "אתחל שרת", "shutdown_host": "כבה שרת מארח", @@ -256,37 +455,38 @@ }, "supervisor": { "beta_backup": "ודא שיש לך גיבויים של הנתונים לפני הפעלת תכונה זו.", - "beta_join_confirm": "האם אתה רוצה להצטרף לערוץ הבטא?", + "beta_join_confirm": "האם אתה רוצה להצטרף לערוץ הביטא?", "beta_release_items": "זה כולל גרסאות בטא עבור:", "beta_warning": "גרסאות בטא מיועדות לבודקים ומאמצים מוקדמים ויכולות להכיל שינויי קוד לא יציבים", - "channel": "עָרוּץ", - "cpu_usage": "שימוש ב- CPU של ה Supervisor", - "failed_to_reload": "הטעינה מחדש של ה Supervisor נכשלה", - "failed_to_set_option": "הגדרת אפשרות ה Supervisor נכשלה", - "failed_to_update": "עדכון ה Supervisor נכשל", - "join_beta_action": "הצטרף לערוץ בטא", - "join_beta_description": "קבל עדכוני בטא עבור Home Assistant, Supervisor ומערכת ההפעלה", - "leave_beta_action": "עזוב את ערוץ הבטא", - "leave_beta_description": "קבל עדכונים יציבים עבור Home Assistant, Supervisor ומערכת ההפעלה", - "ram_usage": "שימוש ב- RAM של ה Supervisor", - "reload_supervisor": "טען מחדש את ה Supervisor", + "channel": "ערוץ", + "cpu_usage": "שימוש ב-CPU של מפקח", + "failed_to_reload": "טעינה מחדש של המפקח נכשלה", + "failed_to_set_option": "הגדרת אפשרות המפקח נכשלה", + "failed_to_update": "עדכון המפקח נכשל", + "join_beta_action": "הצטרף לערוץ ביטא", + "join_beta_description": "קבל עדכוני ביטא עבור Home Assistant, מפקח ומערכת ההפעלה", + "leave_beta_action": "עזוב את ערוץ הביטא", + "leave_beta_description": "קבל עדכונים יציבים עבור Home Assistant, מפקח ומערכת ההפעלה", + "ram_usage": "שימוש בזיכרון RAM של מפקח", + "reload_supervisor": "טען מחדש את המפקח", + "search": "חיפוש", "share_diagnostics": "שתף מידע אבחוני", "share_diagnostics_description": "שתף דוחות קריסה ומידע אבחוני.", - "share_diagonstics_description": "האם ברצונך לשתף באופן אוטומטי דוחות קריסה ומידע אבחון כאשר ה Supervisor נתקל בשגיאות בלתי צפויות? {line_break} זה יאפשר לנו לתקן את הבעיות, המידע נגיש רק לצוות הליבה של Home Assistant ולא ישותף עם אחרים. {line_break} הנתונים אינם כוללים מידע פרטי/רגיש ובאפשרותך להפוך מידע זה ללא זמין בהגדרות בכל עת שתרצה.", + "share_diagonstics_description": "האם ברצונך לשתף באופן אוטומטי דוחות קריסה ומידע אבחון כאשר המפקח נתקל בשגיאות בלתי צפויות? {line_break} זה יאפשר לנו לתקן את הבעיות, המידע נגיש רק לצוות הליבה של Home Assistant ולא ישותף עם אחרים. {line_break} הנתונים אינם כוללים מידע פרטי/רגיש ובאפשרותך להפוך מידע זה ללא זמין בהגדרות בכל עת שתרצה.", "share_diagonstics_title": "עזור לשפר את Home Assistant", "unhealthy_description": "הפעלת התקנה לא בריאה תגרום לבעיות. להלן רשימת הבעיות שנמצאו בהתקנה שלך, לחץ על הקישורים כדי ללמוד כיצד תוכל לפתור את הבעיות.", "unhealthy_reason": { "docker": "סביבת ה- Docker אינה פועלת כראוי", - "privileged": "ל Supervisor אין הרשאות", - "setup": "הגדרת ה Supervisor נכשלה", - "supervisor": "עדכון ה Supervisor לא הצליח", + "privileged": "אין הרשאות למפקח", + "setup": "הגדרת המפקח נכשלה", + "supervisor": "המפקח לא הצליח להתעדכן", "untrusted": "זוהה תוכן לא מהימן" }, "unhealthy_title": "ההתקנה שלך אינה תקינה", "unsupported_description": "למטה רשימת נושאים שנימצאו במהלך ההתקנה, לחץ על קישור על מנת ללמוד איך לפתור את הנושא", "unsupported_reason": { "apparmor": "AppArmor אינו זמין במחשב המארח", - "container": "ה Container ידוע כבעייתי", + "container": "המכולה ידועה כבעייתית", "content-trust": "אימות אמון תוכן מושבת", "dbus": "DBUS", "docker_configuration": "תצורת Docker", @@ -295,20 +495,20 @@ "lxc": "LXC", "network_manager": "מנהל רשת", "os": "מערכת הפעלה", - "privileged": "ל Supervisor אין הרשאות", + "privileged": "אין הרשאות למפקח", "systemd": "Systemd" }, "unsupported_title": "אתה מפעיל התקנה שאינה נתמכת", - "update_supervisor": "עדכן את ה Supervisor", + "update_supervisor": "עדכן את ה המפקח", "warning": "אזהרה" } } }, "ui": { "auth_store": { - "ask": "האם ברצונך לשמור את ההתחברות הזו?", + "ask": "האם ברצונך להישאר מחובר?", "confirm": "כן", - "decline": "לא תודה" + "decline": "לא" }, "card": { "alarm_control_panel": { @@ -322,14 +522,14 @@ }, "automation": { "last_triggered": "הפעלה אחרונה", - "trigger": "הרץ" + "trigger": "הרץ פעולות" }, "camera": { "not_available": "התמונה אינה זמינה" }, "climate": { "aux_heat": "מסייע חום", - "away_mode": "מצב מחוץ לבית", + "away_mode": "מצב לא בבית", "cooling": "{שם} קירור", "current_temperature": "{שם} טמפרטורה נוכחית", "currently": "כעת", @@ -361,6 +561,7 @@ "direction": "כיוון", "forward": "קדימה", "oscillate": "נעים", + "preset_mode": "מצב מוגדר מראש", "reverse": "אחורה", "speed": "מהירות" }, @@ -377,7 +578,7 @@ "color_temperature": "טמפרטורת הצבע", "effect": "אפקט", "warm_white_value": "בהירות לבנה חמה", - "white_value": "לבן" + "white_value": "בהירות לבנה" }, "lock": { "code": "קוד", @@ -385,9 +586,16 @@ "unlock": "ביטול נעילה" }, "media_player": { + "browse_media": "עיון במדיה", + "media_next_track": "הבא", + "media_play": "הפעל", + "media_play_pause": "הפעל/השהה", + "media_previous_track": "הקודם", "sound_mode": "מצב קול", "source": "מקור", - "text_to_speak": "טקסט לדיבור" + "text_to_speak": "טקסט לדיבור", + "turn_off": "כבה", + "turn_on": "הדלק" }, "persistent_notification": { "dismiss": "נקה" @@ -396,11 +604,12 @@ "activate": "הפעל" }, "script": { - "cancel": "בטל", - "cancel_multiple": "בטל {number}" + "cancel": "ביטול", + "cancel_multiple": "בטל {number}", + "run": "רוץ" }, "service": { - "run": "הפעל" + "run": "רוץ" }, "timer": { "actions": { @@ -420,7 +629,7 @@ } }, "water_heater": { - "away_mode": "מצב מחוץ לבית", + "away_mode": "מצב לא בבית", "currently": "כעת", "on_off": "הפעלה / כיבוי", "operation": "פעולה", @@ -453,9 +662,11 @@ "wnw": "צפון מערב", "wsw": "דרום מערב" }, + "day": "יום", "forecast": "תחזית", "high": "גבוה", - "low": "נמוך" + "low": "נמוך", + "night": "לילה" } }, "common": { @@ -470,22 +681,39 @@ "disable": "השבת", "enable": "אפשר", "error_required": "חובה", + "leave": "עזוב", "loading": "טוען", "menu": "תפריט", "next": "הבא", "no": "לא", + "not_now": "לא עכשיו", "overflow_menu": "תפריט גולש", "previous": "הקודם", "refresh": "רענן", "remove": "הסר", + "rename": "שנה שם", "save": "שמור", "skip": "דלג", + "stay": "הישאר", "successfully_deleted": "נמחק בהצלחה", "successfully_saved": "נשמר בהצלחה", "undo": "בטל", "yes": "כן" }, "components": { + "addon-picker": { + "addon": "הרחבה", + "error": { + "fetch_addons": { + "description": "אחזור הרחבות החזירה שגיאה.", + "title": "שגיאה באחזור הרחבות" + }, + "no_supervisor": { + "description": "לא נמצא מפקח, כך שלא היתה אפשרות לטעון הרחבות.", + "title": "אין מפקח" + } + } + }, "area-picker": { "add_dialog": { "add": "הוסף", @@ -494,13 +722,21 @@ "text": "הזן את שם האזור החדש.", "title": "הוסף אזור חדש" }, - "add_new": "הוסף אזור חדש...", + "add_new": "הוספת אזור חדש...", "area": "אזור", "clear": "נקה", "no_areas": "אין לך אזורים", "no_match": "לא נמצאו אזורים תואמים", "show_areas": "הצג אזורים" }, + "attributes": { + "expansion_header": "תכונות" + }, + "blueprint-picker": { + "add_user": "הוסף משתמש", + "remove_user": "הסר משתמש", + "select_blueprint": "בחר תכנית שרטוט" + }, "calendar": { "my_calendars": "היומנים שלי", "today": "היום" @@ -527,6 +763,10 @@ "toggle": "בורר מצבים" }, "entity": { + "entity-attribute-picker": { + "attribute": "תכונה", + "show_attributes": "הצג תכונות" + }, "entity-picker": { "clear": "נקה", "entity": "ישות", @@ -535,24 +775,28 @@ } }, "history_charts": { + "history_disabled": "היסטוריית השילוב מושבתת", "loading_history": "טוען היסטוריה...", "no_history_found": "לא נמצאה היסטוריה" }, "logbook": { "by": "על ידי", "by_service": "באמצעות שרות", + "entries_not_found": "לא נמצאו ערכי יומן רישום.", "messages": { "became_unavailable": "הפך ללא זמין", "changed_to_state": "שונה ל- {state}", "cleared_device_class": "נוקה (לא זוהה {device_class} )", "detected_device_class": "זוהה {device_class}", + "is_closing": "נסגר", + "is_opening": "נפתח", "rose": "זרחה", "set": "שקעה", "turned_off": "נכבה", "turned_on": "הופעל", "was_at_home": "היה בבית", "was_at_state": "היה ב {state}", - "was_away": "לא היה נמצא", + "was_away": "זוהה כלא בבית", "was_closed": "היה סגור", "was_connected": "היה מחובר", "was_disconnected": "היה מנותק", @@ -569,12 +813,47 @@ "show_trace": "הצג מעקב" }, "media-browser": { + "audio_not_supported": "הדפדפן שלך אינו תומך ברכיב השמע.", + "choose_player": "בחר נגן", "class": { - "url": "נתיב כתובת URL", + "album": "אלבום", + "app": "יישום", + "artist": "אמן", + "channel": "ערוץ", + "composer": "מלחין", + "contributing_artist": "אמן תורם", + "directory": "ספריה", + "episode": "פרק", + "game": "משחק", + "genre": "ז'אנר", + "image": "תמונה", + "movie": "סרט", + "music": "מוזיקה", + "playlist": "רשימת השמעה", + "podcast": "פודקאסט", + "season": "עונה", + "track": "רצועה", + "tv_show": "תוכנית טלוויזיה", + "url": "כתובת אתר", "video": "וידאו" }, "documentation": "תיעוד", - "learn_adding_local_media": "למד עוד אודות הוספת מדיה ב-{documentation}." + "learn_adding_local_media": "למד עוד אודות הוספת מדיה ב-{documentation}.", + "local_media_files": "מקם את קבצי הווידאו, השמע והתמונה בספריית המדיה כדי שתוכל לעיין בהם ולהשמיע אותם בדפדפן או בנגני מדיה נתמכים.", + "media_browsing_error": "שגיאת בסיור המדיה", + "media_not_supported": "נגן המדיה של הדפדפן אינו תומך בסוג מדיה זה", + "media_player": "נגן מדיה", + "media-player-browser": "סייר נגן המדיה", + "no_items": "אין פריטים", + "no_local_media_found": "לא נמצאה מדיה מקומית", + "no_media_folder": "נראה שעדיין לא יצרת ספריית מדיה.", + "pick": "בחר", + "pick-media": "בחר מדיה", + "play": "הפעל", + "play-media": "הפעל מדיה", + "setup_local_help": "עיין ב{documentation} כיצד להגדיר מדיה מקומית.", + "video_not_supported": "הדפדפן שלך אינו תומך ברכיב הווידאו.", + "web-browser": "דפדפן" }, "picture-upload": { "label": "תמונה", @@ -596,7 +875,7 @@ "group": "חלק מהקבוצות הבאות", "integration": "אינטגרציה", "no_related_found": "לא נמצאו פריטים קשורים.", - "scene": "חלק מהסצינות הבאות", + "scene": "חלק מהסצנות הבאות", "script": "חלק מהסקריפטים הבאים" }, "relative_time": { @@ -614,6 +893,7 @@ "second": "בעוד {count} {count, plural,\n one {שניה}\n other {שניות}\n}", "week": "בעוד {count} {count, plural,\n one {שבוע}\n other {שבועות}\n}" }, + "just_now": "עכשיו", "never": "אף פעם לא", "past_duration": { "day": "לפני {count} {count, plural,\n one {יום}\n other {ימים}\n}", @@ -625,6 +905,9 @@ }, "service-control": { "integration_doc": "תיעוד אינטגרציה", + "required": "שדה זה נדרש", + "service_data": "נתוני שירות", + "target": "יעדים", "target_description": "אלה האיזורים, התקנים וישויות בהם ישתמש שירות זה" }, "service-picker": { @@ -634,47 +917,62 @@ "add_area_id": "בחר אזור", "add_device_id": "בחר מכשיר", "add_entity_id": "בחר ישות", - "expand_device_id": "הרחב מכשיר זה בישויות נפרדות. לאחר ההרחבה הגופים לא יעודכנו כאשר המכשיר ישתנה.", + "expand_area_id": "הרחב אזור זה למכשירים וליישויות הנפרדות שהוא מכיל. לאחר ההרחבה, הוא לא יעדכן את המכשירים והישויות כאשר האזור משתנה.", + "expand_device_id": "הרחב התקן זה לישויות הנפרדות שהוא מכיל. לאחר ההרחבה, הוא לא יעדכן את הישויות כאשר ההתקן ישתנה.", "remove_area_id": "הסר אזור", "remove_device_id": "הסר מכשיר", "remove_entity_id": "הסר ישות" }, "user-picker": { "add_user": "הוסף משתמש", - "no_user": "אין משתמש" + "no_user": "אין משתמש", + "remove_user": "הסר משתמש" } }, "dialogs": { "config_entry_system_options": { - "enable_new_entities_description": "אם הן מושבתות, ישויות שהתגלו לאחרונה עבור {integration} לא יתווספו אוטומטית ל Home Assistant.", + "enable_new_entities_description": "אם יש להוסיף באופן אוטומטי התקנים שהתגלו לאחרונה עבור {integration}.", "enable_new_entities_label": "הפוך ישויות חדשות שנוספו לזמינות.", - "title": "אפשרויות מערכת", + "enable_polling_description": "אם Home Assistant אמור לתשאל אוטומטית {integration} עבור עדכונים.", + "enable_polling_label": "אפשר תשאול עבור עדכונים.", + "restart_home_assistant": "עליך להפעיל מחדש את Home Assistant כדי שהשינויים שלך ייכנסו לתוקף.", + "title": "אפשרויות מערכת עבור {integration}", "update": "עדכון" }, "domain_toggler": { + "reset_entities": "איפוס ישויות", "title": "החלף דומיינים" }, "entity_registry": { "control": "בקרה", + "customize_link": "התאמות אישיות של ישויות", "dismiss": "בטל", "editor": { + "advanced": "הגדרות מתקדמות", + "area": "הגדרת אזור ישות בלבד", + "area_note": "כברירת מחדל, הישויות של התקן נמצאות באותו אזור כמו ההתקן. אם תשנה את האזור של ישות זו, היא לא תעקוב עוד אחר אזור ההתקן.", + "change_device_area": "שינוי את אזור ההתקן", "confirm_delete": "האם אתה בטוח שברצונך למחוק רשומה זו?", "delete": "מחק", "device_disabled": "המכשיר של ישות זו מושבת.", "enabled_cause": "מושבת עקב {סיבה}.", + "enabled_delay_confirm": "הישויות המופעלות יתווספו ל-Home Assistant בעוד {delay} שניות", "enabled_description": "ישויות מושבתות לא יתווספו ל Home Assistant.", "enabled_label": "הפוך ישות לזמינה", + "enabled_restart_confirm": "הפעל מחדש את Assistant Home כדי להפוך את היישויות לזמינות", "entity_id": "מזהה ישות", - "icon": "סמל חלופי", + "follow_device_area": "עקוב אחר אזור ההתקן", + "icon": "סמליל", "icon_error": "סמלים צריכים להיות בפורמט: prefix:iconname, למשל: mdi:home", - "name": "שם חלופי", - "note": "הערה: יתכן וזה עדיין לא עובד עם כל האינטגרציות.", + "name": "שם", + "note": "הערה: יתכן שזה עדיין לא פועל עם כל השילובים.", "open_device_settings": "פתח את הגדרות המכשיר", "unavailable": "ישות זו אינה זמינה כרגע.", "update": "עדכון" }, "faq": "תיעוד", - "no_unique_id": "לישות זו אין מזהה ייחודי, ולכן לא ניתן לנהל את ההגדרות שלה מממשק המשתמש.", + "info_customize": "באפשרותך להחליף תכונות מסוימות במקטע {customize_link}.", + "no_unique_id": "לישות זו (\"{entity_id}\") אין מזהה ייחודי, ולכן לא ניתן לנהל את הגדרותיה ממשק המשתמש. עיין ב-{faq_link} לפרטים נוספים.", "related": "קשורים", "settings": "הגדרות" }, @@ -685,6 +983,13 @@ "ok": "אישור" }, "helper_settings": { + "counter": { + "initial": "ערך התחלתי", + "maximum": "ערך מרבי", + "minimum": "ערך מינימלי", + "restore": "שחזור הערך הידוע האחרון בעת הפעלת Home Assistant", + "step": "גודל הצעד" + }, "generic": { "icon": "סמל", "name": "שם" @@ -718,18 +1023,30 @@ "pattern": "דפוס Regex לצורך אימות בצד הלקוח", "text": "טקסט" }, - "platform_not_loaded": "האינטגרציה {platform} אינה טעונה. אנא הוסף אותה לקונפיגורציה שלך על ידי הוספת 'default_config:' או '' {platform} : ''.", + "platform_not_loaded": "השילוב {platform} לא נטען. אנא הוסף אותו לתצורה שלך על ידי הוספת 'default_config:' או '' {platform} : ''.", "required_error_msg": "שדה זה הוא חובה", + "timer": { + "duration": "משך" + }, "yaml_not_editable": "אין אפשרות לערוך את ההגדרות של ישות זו מממשק המשתמש. רק ישויות שהוגדרו מממשק המשתמש ניתנות להגדרה מתוך ממשק המשתמש." }, "image_cropper": { "crop": "חתוך" }, "more_info_control": { + "cover": { + "close_cover": "סגור וילון", + "close_tile_cover": "סגור את הטיית הוילון", + "open_cover": "פתח וילון", + "open_tilt_cover": "פתח את הטיית הוילון", + "stop_cover": "עצור וילון מלנוע" + }, + "details": "פרטים", "dismiss": "סגור", "edit": "ערוך יישות", "history": "היסטוריה", - "last_changed": "שונה לאחרונה", + "last_changed": "שינוי אחרון", + "last_updated": "עודכן לאחרונה", "person": { "create_zone": "צור אזור מהמיקום הנוכחי" }, @@ -745,7 +1062,7 @@ }, "script": { "last_action": "פעולה אחרונה", - "last_triggered": "הופעל לאחרונה" + "last_triggered": "גורם הפעיל לאחרונה" }, "settings": "הגדרות ישות", "sun": { @@ -791,11 +1108,63 @@ "quick-bar": { "commands": { "navigation": { - "blueprint": "שרטוטים" + "areas": "אזורים", + "automation": "אוטומציות", + "blueprint": "שרטוטים", + "core": "כללי", + "customize": "התאמות אישיות", + "devices": "התקנים", + "entities": "ישויות", + "helpers": "מסייעים", + "info": "מידע", + "integrations": "שילובים", + "logs": "יומנים", + "lovelace": "לוחות הבקרה של Lovelace", + "navigate_to": "נווט אל {panel}", + "person": "אנשים", + "scene": "סצנות", + "script": "סקריפטים", + "server_control": "פקדי שרת", + "tag": "תגים", + "users": "משתמשים", + "zone": "אזורים" + }, + "reload": { + "automation": "אוטומציות", + "command_line": "ישויות שורת פקודה", + "core": "מיקום והתאמות אישיות", + "filesize": "ישויות בגודל הקובץ", + "filter": "סינון ישויות", + "generic": "ישויות כלליות של מצלמת IP", + "generic_thermostat": "ישויות כלליות של תרמוסטט", + "group": "קבוצות, ישויות קבוצתיות ושירותי הודעה", + "history_stats": "היסטוריית מצב ישויות", + "homekit": "HomeKit", + "input_boolean": "קלט בוליאני", + "input_datetime": "קלט תאריך וזמן", + "input_number": "קלט מספרים", + "input_select": "קלט בחירה", + "input_text": "קלט טקסט", + "min_max": "ישויות מינימום/מקסימום", + "mqtt": "ישויות MQTT שתצורתן נקבעה באופן ידני", + "person": "אנשים", + "ping": "איתות (Ping) ישויות חיישנים בינאריים", + "reload": "{domain}", + "rest": "שאר ישויות ושירותי הודעות", + "rpi_gpio": "ישויות GPIO של רספברי פאי", + "scene": "סצנות", + "script": "סקריפטים", + "smtp": "שירותי הודעת SMTP", + "statistics": "סטטיסטיקה ישויות", + "telegram": "שירותי הודעת טלגרם", + "template": "תבנית ישויות", + "trend": "מגמת ישויות", + "universal": "ישויות אוניברסליות של נגן מדיה", + "zone": "אזורים" }, "server_control": { "perform_action": "{action} שרת", - "restart": "הפעל מחדש", + "restart": "הפעלה מחדש", "stop": "עצור" }, "types": { @@ -816,12 +1185,13 @@ }, "zha_device_info": { "buttons": { - "add": "הוסף מכשירים", + "add": "הוסף התקנים באמצעות התקן זה", "clusters": "ניהול אשכולות", "device_children": "צפה בילדים", "reconfigure": "הגדר מחדש את המכשיר", "remove": "הסר מכשיר", - "zigbee_information": "מידע על Zigbee" + "view_in_visualization": "הצג בפריט חזותי", + "zigbee_information": "חתימת התקן Zigbee" }, "confirmations": { "remove": "האם אתה בטוח שברצונך למחוק מכשיר זה?" @@ -864,24 +1234,31 @@ } }, "duration": { - "day": "יום ימים", + "day": "{count} {count, plural,\n one {יום}\n other {ימים}\n}", "hour": "{count} {count, plural,\n one {שעה}\n other {שעות}\n}", "minute": "{count} {count, plural,\n one {דקה}\n other {דקות}\n}", - "second": "שניה שניות", - "week": "שבוע שבועות" + "second": "{count} {count, plural,\n one {שניה}\n other {שניות}\n}", + "week": "{count} {count, plural,\n one {שבוע}\n other {שבועות}\n}" }, "errors": { "config": { + "edit_in_yaml_supported": "באפשרותך עדיין לערוך את תצורתך ב-YAML.", + "editor_not_available": "אין עורך חזותי זמין עבור הסוג \"{type}\".", + "editor_not_supported": "עורך חזותי אינו נתמך עבור תצורה זו", + "error_detected": "זוהו שגיאות תצורה", + "key_missing": "המפתח הנדרש \"{key}\" חסר.", + "key_not_expected": "המפתח \"{key}\" אינו צפוי או לא נתמך על ידי העורך החזותי.", "key_wrong_type": "הערך שסופק עבור \"{key}\" אינו נתמך על-ידי העורך החזותי. אנו תומכים ({type_correct}) אך קיבלנו ({type_wrong}).", - "no_template_editor_support": "תבניות אינן נתמכות בעורך החזותי" + "no_template_editor_support": "תבניות אינן נתמכות בעורך החזותי", + "no_type_provided": "לא סופק סוג." }, "supervisor": { "ask": "בקש עזרה", "observer": "בדוק את המשקיף", "reboot": "נסה אתחול מחדש של המחשב המארח", "system_health": "בדוק את בריאות המערכת", - "title": "לא היתה אפשרות לטעון את לוח ה Supervisor!", - "wait": "אם רק התחלת, ודא שנתת ל Supervisor מספיק זמן להתחיל." + "title": "לא ניתן לטעון את לוח המפקח!", + "wait": "אם רק התחלת, ודא שנתת למפקח מספיק זמן להתחיל." } }, "login-form": { @@ -892,6 +1269,7 @@ "notification_drawer": { "click_to_configure": "לחץ על הלחצן כדי להגדיר {entity}", "close": "סגור", + "dismiss_all": "שחרר הכל", "empty": "אין התראות", "title": "התראות" }, @@ -902,7 +1280,7 @@ "service_call_failed": "נכשלה הקריאה לשירות {service} .", "started": "Home Assistant עלה!", "starting": "Home Assistant בעלייה, ייתכן שלא הכל יהיה זמין עד שהעליה תסתיים", - "triggered": "הופעל {שם}", + "triggered": "הופעל {name}", "wrapping_up_startup": "סיום העליה, לא הכל יהיה זמין עד לסיום." }, "panel": { @@ -912,7 +1290,7 @@ "link_profile_page": "דף הפרופיל שלך" }, "areas": { - "caption": "מאגר האזורים", + "caption": "אזורים", "data_table": { "area": "אזור", "devices": "התקנים", @@ -922,7 +1300,7 @@ "confirmation_text": "כל ההתקנים באזור זה לא יהיו מוקצים.", "confirmation_title": "האם אתה בטוח שברצונך למחוק אזור זה?" }, - "description": "סקירה של כל האזורים בביתך", + "description": "קיבוץ התקנים וישויות לאזורים", "editor": { "area_id": "מזהה אזור", "create": "צור", @@ -933,11 +1311,11 @@ "name_required": "שם הוא חובה", "no_linked_entities": "אין ישויות המקושרות לאזור זה.", "unknown_error": "שגיאה לא ידועה", - "update": "עדכון" + "update": "עדכן" }, "picker": { "create_area": "צור אזור", - "header": "מאגר האזורים", + "header": "אזורים", "integrations_page": "דף אינטגרציות", "introduction": "אזורים משמשים לארגון המיקום של ההתקנים. Home Assistant יעשה שימוש במידע זה בכדי לסייע לך בארגון הממשק, ההרשאות והאינטגרציות שלך עם מערכות אחרות.", "introduction2": "כדי למקם התקנים באזור זה, השתמש בקישור הבא כדי לנווט אל דף האינטגרציות ולאחר מכן לחץ על אינטגרציה מוגדרת כדי להגיע לכרטיסי המכשיר.", @@ -945,14 +1323,28 @@ } }, "automation": { - "caption": "אוטומציה", - "description": "צור וערוך אוטומציות", + "caption": "אוטומציות", + "description": "יצירת כללי התנהגות מותאמים אישית עבור הבית שלך", + "dialog_new": { + "blueprint": { + "use_blueprint": "השתמש בשרטוט" + }, + "header": "צור אוטומציה חדשה", + "how": "כיצד ברצונך ליצור את האוטומציה החדשה שלך?", + "start_empty": "התחל עם אוטומציה ריקה", + "thingtalk": { + "create": "צור", + "header": "תאר את האוטומציה שברצונך ליצור", + "input_label": "מה האוטומציה הזו צריכה לעשות?", + "intro": "ואנחנו ננסה ליצור את זה בשבילך. לדוגמא: כבה את האורות כשאני עוזב." + } + }, "editor": { "actions": { "add": "הוסף פעולה", - "delete": "מחק", - "delete_confirm": "האם אתה בטוח שאתה רוצה למחוק?", - "duplicate": "שכפל", + "delete": "מחיקה", + "delete_confirm": "האם בוודאות ברצונך למחוק זאת?", + "duplicate": "שיכפול", "header": "פעולות", "introduction": "הפעולות הן מה שHome Assistant יעשה כאשר אוטומציה מופעלת.", "learn_more": "למד עוד על פעולות", @@ -982,13 +1374,16 @@ "code": "קוד", "flash": "הבהוב", "humidity": "לחות", + "message": "הודעה", "mode": "מצב", + "position": "מיקום", + "title": "כותרת", "value": "ערך" }, "label": "מכשיר" }, "event": { - "event": "ארוע", + "event": "אירוע:", "label": "ירה אירוע", "service_data": "נתוני שירות" }, @@ -1001,11 +1396,11 @@ "label": "ספירה" }, "until": { - "conditions": ")תנאי עד ש (Until", + "conditions": "תנאיי עד ש", "label": "עד ש" }, "while": { - "conditions": ")תנאי כל עוד (While", + "conditions": "תנאיי כאשר", "label": "כל עוד" } } @@ -1016,22 +1411,34 @@ "service": { "label": "קריאה לשירות" }, + "wait_for_trigger": { + "continue_timeout": "המשך בפסק הזמן", + "label": "המתן לטריגר", + "timeout": "זמן קצוב (אופציונלי)" + }, "wait_template": { + "continue_timeout": "המשך בפסק הזמן", "label": "לחכות", "timeout": "זמן קצוב (אופציונלי)", "wait_template": "תבנית זמן" } }, - "unsupported_action": "פעולה לא נתמכת: {action}" + "unsupported_action": "אין תמיכה בעורך חזותי לפעולה: {action}" }, "alias": "שם", + "blueprint": { + "blueprint_to_use": "שרטוט לשימוש", + "header": "שרטוט", + "no_blueprints": "אין לך שרטוטים", + "no_inputs": "לשרטוט הזה אין קלט." + }, "conditions": { "add": "הוסף תנאי", - "delete": "מחק", - "delete_confirm": "אתה בטוח שאתה רוצה למחוק?", - "duplicate": "שכפל", + "delete": "מחיקה", + "delete_confirm": "האם בוודאות ברצונך למחוק זאת?", + "duplicate": "שיכפול", "header": "תנאים", - "introduction": "התנאים הם חלק אופציונלי של כלל אוטומציה, וניתן להשתמש בהם כדי למנוע פעולה כלשהי בעת הפעלתה. התנאים נראים דומים מאוד לטריגרים אך הם שונים מאוד. הטריגר יסתכל על האירועים המתרחשים במערכת בעוד תנאי רק מסתכל על איך המערכת נראית עכשיו. הטריגר יכול לדעת כשמתג נדלק. תנאי יכול לראות רק אם מתג מופעל או כבוי.", + "introduction": "התנאים הם אופציונליים וימנעו מהאוטומציה לפעול אלא אם כן כל התנאים מתקיימים.", "learn_more": "למד עוד על תנאים", "name": "תנאים", "type_select": "סוג תנאי", @@ -1057,7 +1464,7 @@ "above": "מעל", "below": "מתחת", "label": "מצב מספרי", - "value_template": "ערך תבנית (אופציונלי)" + "value_template": "תבנית ערך (אופציונלי)" }, "or": { "label": "או" @@ -1083,6 +1490,8 @@ "after": "אחרי", "before": "לפני", "label": "זמן", + "type_input": "הערך של עוזר תאריך/שעה", + "type_value": "זמן קבוע", "weekdays": { "fri": "יום שישי", "mon": "יום שני", @@ -1099,7 +1508,7 @@ "zone": "אזור" } }, - "unsupported_condition": "תנאי לא נתמך: {condition}" + "unsupported_condition": "אין תמיכה בעורך חזותי בתנאי: {condition}" }, "copy_to_clipboard": "העתק ללוח", "default_name": "אוטומציה חדשה", @@ -1107,10 +1516,10 @@ "label": "תיאור", "placeholder": "תיאור אופציונלי" }, - "edit_ui": "ערוך באמצעות ממשק המשתמש", - "edit_yaml": "ערוך כ- YAML", + "edit_ui": "עריכה בעורך חזותי", + "edit_yaml": "עריכה ב-YAML", "enable_disable": "הפעל / השבת אוטומציה", - "introduction": "השתמש/י באוטומציות להפיח חיים בביתך.", + "introduction": "השתמש באוטומציות כדי לעורר את ביתך לחיים.", "load_error_not_editable": "רק אוטומציה ב automations.yaml ניתנים לעריכה.", "load_error_unknown": "שגיאה בטעינת האוטומציה ( {err_no} ).", "max": { @@ -1123,7 +1532,7 @@ "label": "מצב", "parallel": "במקביל", "queued": "בתור", - "restart": "אתחול", + "restart": "הפעלה מחדש", "single": "יחיד (ברירת מחדל)" }, "move_down": "הזז למטה", @@ -1132,9 +1541,9 @@ "show_trace": "הצג מעקב", "triggers": { "add": "הוספת טריגר", - "delete": "מחק", - "delete_confirm": "האם אתה בטוח שברצונך למחוק?", - "duplicate": "שכפל", + "delete": "מחיקה", + "delete_confirm": "האם בוודאות ברצונך למחוק זאת?", + "duplicate": "שיכפול", "header": "טריגרים", "introduction": "טריגרים הם מה שמתחיל כל אוטומציה. ניתן לציין מספר טריגרים עבור אותו כלל. לאחר הפעלת טריגר, Home Assistant יאמת את התנאים, אם ישנם, ויפעיל את הפעולה.", "learn_more": "למד עוד על טריגרים", @@ -1145,13 +1554,16 @@ "extra_fields": { "above": "מעל", "below": "מתחת", - "for": "משך" + "for": "משך", + "zone": "אזור" }, "label": "מכשיר", "trigger": "טריגר" }, "event": { "context_user_pick": "בחר משתמש", + "context_user_picked": "אירוע שיגור של משתמש", + "context_users": "הגבל לאירועים שהופעלו על ידי", "event_data": "נתוני אירוע", "event_type": "סוג אירוע", "label": "אירוע" @@ -1182,13 +1594,14 @@ "value_template": "תבנית ערך (אופציונלי)" }, "state": { + "attribute": "תכונה (אופציונלי)", "for": "למשך", - "from": "מ", + "from": "החל מ", "label": "מצב", - "to": "ל" + "to": "עד ל" }, "sun": { - "event": "אירוע", + "event": "אירוע:", "label": "שמש", "offset": "שקיעה (אופציונלי)", "sunrise": "זריחה", @@ -1199,7 +1612,7 @@ }, "template": { "label": "תבנית", - "value_template": "תבנית ערך" + "value_template": "ערך תבנית" }, "time_pattern": { "hours": "שעות", @@ -1208,8 +1621,10 @@ "seconds": "שניות" }, "time": { - "at": "ב", - "label": "זמן" + "at": "בזמן", + "label": "זמן", + "type_input": "הערך של עוזר תאריך/שעה", + "type_value": "זמן קבוע" }, "webhook": { "label": "Webhook", @@ -1224,7 +1639,7 @@ "zone": "אזור" } }, - "unsupported_platform": "פלטפורמה לא נתמכת: {platform}" + "unsupported_platform": "אין תמיכה בעורך חזותי עבור פלטפורמה: {platform}" }, "unsaved_confirm": "יש לך שינויים שלא נשמרו. אתה בטוח שאתה רוצה לעזוב?" }, @@ -1234,6 +1649,8 @@ "delete_confirm": "האם אתה בטוח שברצונך למחוק אוטומציה זו?", "dev_automation": "דבג אוטומציה", "dev_only_editable": "רק אוטומציות שהוקצה להן מזהה ייחודי ניתנות לדיבוג.", + "duplicate": "שכפל", + "duplicate_automation": "שכפול אוטומציה", "edit_automation": "ערוך אוטומציה", "header": "עורך אוטומציה", "headers": { @@ -1241,7 +1658,7 @@ }, "introduction": "עורך אוטומציה מאפשר לך ליצור ולערוך אוטומציות. אנא עקוב אחר הקישור למטה וקרא את ההוראות כדי לוודא שהגדרת את ה - Home Assistant כהלכה.", "learn_more": "למד עוד על אוטומציות", - "no_automations": "לא מצאנו אוטומציה הניתנת לעריכה", + "no_automations": "לא הצלחנו למצוא אוטומציות", "only_editable": "רק אוטומציות שהוגדרו ב automations.yaml ניתנות לעריכה.", "pick_automation": "בחר אוטומציה לעריכה", "show_info_automation": "הצג מידע על אוטומציה" @@ -1249,10 +1666,17 @@ "thingtalk": { "create": "צור אוטומציה", "link_devices": { + "ambiguous_entities": "התקן אחד או יותר כולל יותר מישות תואמת אחת, נא בחר את הישות שבה ברצונך להשתמש.", + "header": "נהדר! עכשיו אנחנו צריכים לקשר כמה התקנים", "unknown_placeholder": "לא ידוע" }, "task_selection": { - "for_example": "לדוגמה:" + "error_empty": "הזן פקודה או הקש על דלג.", + "error_unsupported": "לא יכולנו ליצור אוטומציה לזה (עדיין?).", + "for_example": "לדוגמה:", + "header": "צור אוטומציה חדשה", + "introduction": "הקלד להלן את מה שאוטומציה זו צריכה לעשות, וננסה להמיר אותה לאוטומציה של Home Assistant.", + "language_note": "הערה: רק אנגלית נתמכת לעת עתה." } } }, @@ -1276,13 +1700,17 @@ "description": "ניהול שרטוטים", "overview": { "add_blueprint": "יבוא שרטוט", + "confirm_delete_header": "למחוק את השרטוט הזה?", "confirm_delete_text": "האם אתה בטוח שברצונך למחוק שרטוט זה?", "delete_blueprint": "מחק שרטוט", "discover_more": "גלה שרטוטים נוספים", + "header": "עורך השרטוטים", "headers": { "domain": "דומיין", - "file_name": "שם קובץ" + "file_name": "שם קובץ", + "name": "שם" }, + "introduction": "התצורה של שרטוטים מאפשרת לך לייבא ולנהל את השרטוטים שלך.", "learn_more": "למד עוד אודות שימוש בשרטוטים", "share_blueprint": "שתף שרטוט", "share_blueprint_no_url": "אין אפשרות לשתף שרטוט: אין כתובת URL", @@ -1292,7 +1720,7 @@ "cloud": { "account": { "alexa": { - "config_documentation": "הגדרת תיעוד", + "config_documentation": "תיעוד תצורה", "disable": "השבתה", "enable": "אפשור", "enable_ha_skill": "הפעל את מיומנות Home Assistant עבור אלקסה", @@ -1301,21 +1729,22 @@ "info_state_reporting": "אם תאפשר דיווח על מצב, Home Assistant ישלח כל שינוי מצב של ישויות חשופות לאמזון. זה יאפשר לך לראות תמיד את המצב העדכני באפליקציית Alexa ולהשתמש בשינויי המצב ליצירת שגרות.", "manage_entities": "נהל ישויות", "state_reporting_error": "אין אפשרות לעשות {enable_disable} לדיווח מצב.", - "sync_entities": "סנכרון ישויות", + "sync_entities": "סנכרן ישויות לאמזון", "sync_entities_error": "סינכרון ישויות נכשל:", "title": "Alexa" }, "connected": "מחובר", + "connecting": "מתחבר...", "connection_status": "מצב חיבור ענן", - "fetching_subscription": "מביא מנוי...", + "fetching_subscription": "מאחזר מנוי...", "google": { - "config_documentation": "הגדרת תיעוד", - "devices_pin": "Pin התקני אבטחה", - "enable_ha_skill": "הפעל את יכולת Home Assistant עבור עוזר הבית עבור מסייע Google", + "config_documentation": "תיעוד תצורה", + "devices_pin": "PIN של התקני אבטחה", + "enable_ha_skill": "הפעלת מיומנות הענן של Home Assistant עבור Google Assistant", "enable_state_reporting": "אפשר דיווח מצב", - "enter_pin_error": "אין אפשרות לאחסן את הקוד ה PIN:", + "enter_pin_error": "אין אפשרות לאחסן PIN:", "enter_pin_hint": "הזן קוד PIN לשימוש בהתקני אבטחה", - "enter_pin_info": "נא הזן קוד PIN כדי לעבוד עם מכשירי אבטחה. מכשירי אבטחה הם דלתות, דלתות מוסך ומנעולים. תתבקש לומר/להזין את קוד ה PIN כאשר אתה מקיים אינטראקציה עם התקנים אלה באמצעות המסייע של Google.", + "enter_pin_info": "נא הזן מספר זיהוי אישי (PIN) כדי לקיים אינטראקציה עם התקני אבטחה. מכשירי אבטחה הם דלתות, דלתות מוסך ומנעולים. תתבקש לומר/להזין מספר זיהוי אישי זה בעת אינטראקציה עם מכשירים כאלה באמצעות Google Assistant.", "info": "עם שילוב מסייע Google עבור ענן Home Assistant תוכל לשלוט בכל מכשירי Home Assistant שלך באמצעות כל מכשיר המקושר למסייע של Google.", "info_state_reporting": "אם תפעיל דיווח מצב, Home Assistant ישלח את כל שינויי המצבים של ישויות חשופות ל-Google. זה מאפשר לך תמיד לראות את המצבים האחרונים באפליקציה של גוגל.", "manage_entities": "נהל ישויות", @@ -1326,15 +1755,15 @@ "sync_entities_404_message": "כישלון בסינכרון היישויות שלך ל-Google, בקש מ Google 'Hey Google, sync my devices' כדי לסנכרן את הישויות שלך.", "title": "Google Assistant" }, - "integrations": "אינטגרציות", - "integrations_introduction": "אינטגרציות עבור ענן Home Assistant מאפשרות לך להתחבר לשירותים בענן מבלי שתצטרך לחשוף את המופע של עוזר הבית שלך באופן ציבורי באינטרנט.", + "integrations": "שילובים", + "integrations_introduction": "שילובים עבור ענן Home Assistant מאפשרים לך להתחבר לשירותים בענן מבלי שתצטרך לחשוף את המופע של Home Assistant שלך באופן ציבורי באינטרנט.", "integrations_introduction2": "בדוק באתר האינטרנט ", "integrations_link_all_features": " כל התכונות הזמינות", "manage_account": "נהל חשבון", "nabu_casa_account": "חשבון נאבו קאסה", "not_connected": "לא מחובר", "remote": { - "access_is_being_prepared": "מכינים גישה מרחוק. אנו נודיע לך כשזה יהיה מוכן.", + "access_is_being_prepared": "מתבצעת הכנה של שליטה מרחוק. נודיע לך כשזה יהיה מוכן.", "certificate_info": "פרטי התעודה", "connected": "מחובר", "info": "ענן Home Assistant מספק חיבור מרוחק מאובטח למערכת שלך כשאתה רחוק מהבית.", @@ -1344,7 +1773,7 @@ "not_connected": "לא מחובר", "remote_enabled": { "caption": "התחבר אוטומטית", - "description": "אפשר אפשרות זו כדי לוודא שה- Home Assistant שלך תמיד נגיש מרחוק." + "description": "אפשר אפשרות זו כדי לוודא שמופע ה-Home Assistant שלך תמיד נגיש מרחוק." }, "title": "שליטה מרחוק" }, @@ -1352,6 +1781,13 @@ "thank_you_note": "תודה לך על היותך חלק בענן Home Assistant. בזכות אנשים כמוך אנחנו מסוגלים לייצר חווית בית חכם עבור כולם. תודה!", "tts": { "default_language": "שפת ברירת מחדל לשימוש", + "dialog": { + "example_message": "שלום {name} , אתה יכול לנגן כל טקסט בכל נגן מדיה נתמך!", + "header": "נסה טקסט לדיבור", + "play": "הפעל", + "target": "יעד", + "target_browser": "סייר" + }, "female": "נקבה", "info": "הבא אישיות לביתך על-ידי כך שהוא ידבר אליך באמצעות שירותי המרת הטקסט לדיבור שלנו. באפשרותך להשתמש באפשרות זו באוטומציות ובקבצי Script באמצעות שירות {service}.", "male": "זכר", @@ -1362,7 +1798,7 @@ "disable_hook_error_msg": "השבתת הwebhook נכשלה:", "info": "לכל דבר שתצורתו נקבעה כמופעלת על-ידי webhook יכולה להינתן כתובת URL ציבורית כדי לאפשר לך לשלוח נתונים בחזרה ל Home Assistant מכל מקום, מבלי לחשוף את המערכת שלך לאינטרנט.", "link_learn_more": "למד עוד אודות יצירת אוטומציות המונעות על-ידי webhook.", - "loading": "טעינה ...", + "loading": "טוען...", "manage": "ניהול", "no_hooks_yet": "נראה שעדיין אין לך אף webhook. התחל על ידי קביעת התצורה של ", "no_hooks_yet_link_automation": "אוטומצית webhook", @@ -1373,8 +1809,13 @@ }, "alexa": { "banner": "עריכת היישויות החשופות באמצעות ממשק משתמש זה אינה זמינה מאחר שקבעת את תצורת מסנני הישויות ב configuration.yaml.", + "dont_expose_entity": "אל תחשוף ישות", "expose": "חשוף בפני אלכסה", + "expose_entity": "חשוף ישות", + "exposed": "{selected} נחשף", "exposed_entities": "ישויות חשופות", + "follow_domain": "עקוב אחר התחום", + "manage_domains": "נהל תחומים", "not_exposed": "{selected} לא חשוף", "not_exposed_entities": "ישויות לא חשופות", "title": "Alexa" @@ -1383,7 +1824,7 @@ "description_login": "מחובר בתור {email} מה", "description_not_login": "לא מחובר", "dialog_certificate": { - "certificate_expiration_date": "תאריך תפוגה של התעודה", + "certificate_expiration_date": "תאריך תפוגה של התעודה:", "certificate_information": "פרטי התעודה", "close": "סגור", "fingerprint": "טביעת אצבע של התעודה:", @@ -1412,9 +1853,13 @@ "google": { "banner": "עריכת היישויות החשופות באמצעות ממשק משתמש זה אינה זמינה מאחר שקבעת את תצורת מסנני הישויות ב configuration.yaml.", "disable_2FA": "השבת אימות דו-שלבי", + "dont_expose_entity": "אל תחשוף ישות", "expose": "חשוף בפני Google Assistant", + "expose_entity": "חשוף ישות", "exposed": "{selected} חשוף", "exposed_entities": "ישויות חשופות", + "follow_domain": "עקוב אחר התחום", + "manage_domains": "נהל תחומים", "not_exposed": "{selected} לא חשוף", "not_exposed_entities": "ישויות לא חשופות", "sync_to_google": "מסנכרן שינויים ל-Google.", @@ -1426,7 +1871,7 @@ "dismiss": "בטל", "email": "דוא\"ל", "email_error_msg": "דואר אלקטרוני לא חוקי", - "forgot_password": "שכחת סיסמא?", + "forgot_password": "שכחת סיסמה?", "introduction": "שירות Home Assistant Cloud מספק לך חיבור מרוחק מאובטח למערכת שלך כשאתה מחוץ לבית. הוא גם מאפשר לך להתחבר לשירותים הזמינים בענן בלבד: Alexa ו-Google Assistant.", "introduction2": "שירות זה מנוהל על ידי השותף שלנו ", "introduction2a": ", חברה שהוקמה על ידי מייסדי Home Assistant ו Hass.io.", @@ -1470,7 +1915,7 @@ }, "core": { "caption": "כללי", - "description": "שנה את התצורה הכללית של Home Assistant", + "description": "מערכת היחידה, מיקום, אזור זמן ופרמטרים כלליים אחרים", "section": { "core": { "analytics": { @@ -1478,7 +1923,7 @@ "header": "ניתוח", "instance_id": "מזהה מופע: {huuid}", "introduction": "שתף את פרטי ההתקנה שלך כדי לעזור לשפר את Home Assistant ולעזור לנו לשכנע יצרנים להוסיף שליטה מקומית ותכונות ממוקדות לפרטיות.", - "learn_more": "למד עוד על אופן עיבוד הנתונים שלך.", + "learn_more": "כיצד אנו מעבדים את הנתונים שלך", "needs_base": "עליך לאפשר ניתוח בסיס כדי שאפשרות זו תהיה זמינה", "preference": { "base": { @@ -1520,7 +1965,7 @@ "unit_system_imperial": "אימפריאלי", "unit_system_metric": "מטרי" }, - "header": "הגדרות כלליות", + "header": "תצורה כללית", "introduction": "שינוי התצורה שלך יכול להיות תהליך מייגע. אנחנו יודעים. חלק זה ינסה להפוך את החיים שלך קצת יותר קלים." } } @@ -1531,42 +1976,51 @@ "attributes_outside": "התכונות הבאות מותאמות אישית מחוץ ל- customize.yaml", "attributes_override": "אתה יכול לדרוס אותן אם תרצה.", "attributes_set": "התכונות הבאות של הישות מוגדרות באופן תכנותי.", - "caption": "התאמה אישית", + "caption": "התאמות אישיות", "description": "התאם אישית את הישויות שלך", "different_include": "יתכן דרך דומיין, גלובלי או כלול אחר.", "pick_attribute": "בחר תכונה לדריסה", "picker": { "documentation": "תיעוד התאמה אישית", - "header": "התאמה אישית", - "introduction": "כוונן תכונות של כל ישות. ההתאמות הנוספות שנוספו / ייכנסו לתוקף באופן מיידי. התאמות אישיות שהוסרו ייכנסו לתוקף כאשר הישות תעודכן." + "header": "התאמות אישיות", + "introduction": "כוונן תכונות לפי ישות. התאמות אישיות שנוספו/נערכו ייכנסו לתוקף באופן מיידי. התאמות אישיות שהוסרו ייכנסו לתוקף כאשר הישות תעודכן." }, "warning": { "include_link": "את customize.yaml באופן תקין", "include_sentence": "נראה כי ה- configuration.yaml שלך אינו כולל", - "not_applied": "שינויים שנעשו כאן כתובים בו, אך לא יוחלו לאחר טעינה מחדש של הקונפיגורציה אלא אם הכלול במקום." + "not_applied": "שינויים שבוצעו כאן כתובים בו, אך לא יחולו לאחר טעינה מחדש של תצורה אלא אם הכלל נמצא במקומו." } }, "devices": { + "add_prompt": "אף {name} לא נוסף באמצעות מכשיר זה. אתה יכול להוסיף אחד על ידי לחיצה על כפתור + למעלה.", "automation": { "actions": { - "caption": "כשמשהו מופעל..." + "caption": "כשמשהו מופעל...", + "no_actions": "אין פעולות", + "unknown_action": "פעולה לא ידועה" }, "automations": "אוטומציות", "conditions": { - "caption": "בצע משהו רק אם..." + "caption": "בצע משהו רק אם...", + "no_conditions": "ללא תנאים", + "unknown_condition": "תנאי לא ידוע" }, "create": "צור אוטומציה עם המכשיר", "create_disable": "non posso creare automazioni condispositivi disabilitati", "no_automations": "אין אוטומציות", "no_device_automations": "אין אוטומציות זמינות עבור מכשיר זה.", "triggers": { - "caption": "עשה משהו כש ..." - } + "caption": "עשה משהו כש ...", + "no_triggers": "אין טריגרים", + "unknown_trigger": "טריגר לא ידוע" + }, + "unknown_automation": "אוטומציה לא ידועה" }, "cant_edit": "באפשרותך לערוך פריטים שנוצרו בממשק המשתמש בלבד.", "caption": "התקנים", "confirm_delete": "האם אתה בטוח שברצונך למחוק התקן זה?", - "confirm_rename_entity_ids": "האם אתה רוצה גם לשנות את המזהים של הישויות שלך?", + "confirm_disable_config_entry": "אין התקנים נוספים עבור ערך התצורה {entry_name} , האם ברצונך להשבית את ערך התצורה?", + "confirm_rename_entity_ids": "האם ברצונך גם לשנות את שמות מזהי הישויות של הישויות שלך?", "confirm_rename_entity_ids_warning": "שינוי זה לא ישפיע על התצורה (כמו אוטומציות, קבצי Script, סצנות, Lovelace) המשתמשת כעת בישויות אלה! יהיה עליך לעדכן אותן בעצמך כדי להשתמש במזהים של הישויות החדשות.", "data_table": { "area": "אזור", @@ -1578,7 +2032,7 @@ "no_devices": "אין התקנים" }, "delete": "מחיקה", - "description": "ניהול התקנים מחוברים", + "description": "ניהול התקנים שתצורתם נקבעה", "device_info": "פרטי התקן", "device_not_found": "המכשיר לא נמצא.", "disabled": "מושבת", @@ -1611,10 +2065,10 @@ "scene": { "create": "צור סצינה עם המכשיר", "create_disable": "לא ניתן ליצור סצנה עם מכשיר מושבת", - "no_scenes": "אין סצינות", - "scenes": "סצינות" + "no_scenes": "אין סצנות", + "scenes": "סצנות" }, - "scenes": "סצינות", + "scenes": "סצנות", "script": { "create": "צור סקריפט עם המכשיר", "create_disable": "לא ניתן ליצור סקריפט עם מכשיר מושבת", @@ -1624,21 +2078,22 @@ "scripts": "סקריפטים", "unknown_error": "שגיאה לא ידועה", "unnamed_device": "מכשיר ללא שם", - "update": "עדכון" + "update": "עדכון", + "update_device_error": "עדכון ההתקן נכשל" }, "entities": { - "caption": "מאגר הישויות", - "description": "סקירה של כל הישויות המוכרות", + "caption": "ישויות", + "description": "ניהול ישויות מוכרות", "picker": { "disable_selected": { "button": "השבת מסומנים", "confirm_text": "ישויות מושבתות לא יתווספו ל Home Assistant.", - "confirm_title": "האם אתה רוצה להשבית {number} ישויות?" + "confirm_title": "האם אתה רוצה להשבית את ה{number} {number, plural,\n one {ישות}\n other {ישויות}\n}?" }, "enable_selected": { "button": "אפשר מסומנים", "confirm_text": "זה יהפוך אותם לזמינים ב Home Assistant שוב אם הם מושבתים כעת.", - "confirm_title": "האם אתה רוצה לאפשר {number} ישויות?" + "confirm_title": "האם אתה רוצה להפעיל את ה{number} {number, plural,\n one {ישות}\n other {ישויות}\n}?" }, "filter": { "filter": "סנן", @@ -1648,7 +2103,7 @@ "show_readonly": "הצג ישויות לקריאה בלבד", "show_unavailable": "הצג ישויות לא זמינות" }, - "header": "מאגר הישויות", + "header": "ישויות", "headers": { "area": "אֵזוֹר", "entity_id": "מזהה ישות", @@ -1657,13 +2112,13 @@ "status": "סטטוס" }, "introduction": "Home Assistant מנהל רישום של כל ישות שנראתה אי פעם ואשר ניתנת לזיהוי ייחודי. לכל אחד מישויות אלו יהיה מזהה ישות שהוקצה ואשר יהה שמור רק עבור ישות זו.", - "introduction2": "השתמש במאגר הישויות בכדי לשנות את השם, מזהה הישות או להסיר את הערך מ- Home Assistant. שים לב, הסרת הישות ממאגר זה לא תסיר את הישות. לשם כך, פעל לפי הקישור שלהלן והסר אותו מדף האינטגרציות.", + "introduction2": "השתמש ברישום הישויות כדי לעקוף את השם, לשנות את מזהה הישות או להסיר את הערך מ-Home Assistant.", "remove_selected": { "button": "הסר את המסומנים", "confirm_partly_text": "אתה יכול להסיר רק את {removable} מהישויות שנבחרו {selected}. ניתן להסיר ישויות רק כאשר האינטגרציה כבר לא מספקת את הישויות. לפעמים אתה צריך להפעיל מחדש את עוזר הבית לפני שתוכל להסיר את הישויות של אינטגרציה שהוסרה. האם אתה בטוח שברצונך להסיר את הישויות הניתנות להסרה?", - "confirm_partly_title": "ניתן להסיר רק {number} ישויות שנבחרו.", + "confirm_partly_title": "רק {number} {number, plural,\n one {ישות שנבחרה}\n other {ישויות שנבחרו}\n} ניתן להסיר.", "confirm_text": "עליך להסיר אותם מתצורת ה- Lovelace ומהאוטומציות שלך אם הם מכילים ישויות אלה.", - "confirm_title": "האם ברצונך להסיר {number} ישויות?" + "confirm_title": "האם ברצונך להסיר את ה{number} {number, plural,\n one {ישות}\n other {ישויות}\n}?" }, "search": "חיפוש ישויות", "selected": "{number} נבחרו", @@ -1678,15 +2133,16 @@ }, "filtering": { "clear": "נקה", - "filtering_by": "סינון לפי" + "filtering_by": "סינון לפי", + "show": "הצג" }, "hassio": { "button": "הגדר" }, "header": "הגדר את Home Assistant", "helpers": { - "caption": "עוזרים", - "description": "רכיבים שיכולים לסייע בבניית אוטומציות.", + "caption": "מסייעים", + "description": "רכיבים המסייעים בבניית אוטומציות", "dialog": { "add_helper": "הוסף עוזר", "add_platform": "הוסף {platform}", @@ -1700,21 +2156,25 @@ "name": "שם", "type": "סוג" }, - "no_helpers": "נראה שאין לך עדיין עזרים!" + "no_helpers": "נראה שאין לך עדיין מסייעים!" }, "types": { + "counter": "מונה", "input_boolean": "בורר מצבים", "input_datetime": "תאריך ו/או שעה", "input_number": "מספר", "input_select": "תיבת בחירה", - "input_text": "טקסט" + "input_text": "טקסט", + "timer": "טיימר" } }, "info": { "built_using": "נבנה באמצעות", "caption": "מידע", + "copy_github": "עבור GitHub", + "copy_raw": "טקסט גולמי", "custom_uis": "ממשקי משתמש מותאמים אישית:", - "description": "צפה במידע על התקנת Home Assistant שלך", + "description": "גרסה, תקינות המערכת וקישורים לתיעוד", "developed_by": "פותח על ידי חבורה של אנשים מדהימים.", "documentation": "תיעוד", "frontend": "frontend-ui", @@ -1728,52 +2188,68 @@ "server": "שרת", "setup_time": "זמן התקנה", "source": "מקור:", - "system_health_error": "רכיב ה System Health אינו טעון. הוסף 'system_health:' ל - configuration.yaml" + "system_health_error": "רכיב בריאות המערכת לא נטען. הוסף את 'system_health:' ל- configuration.yaml", + "system_health": { + "manage": "נהל", + "more_info": "מידע נוסף" + } }, "integration_panel_move": { - "link_integration_page": "עמוד אינטגרציות", + "link_integration_page": "עמוד שילובים", "missing_zha": "חסר את לוח התצורה של ZHA? הוא הועבר לכניסה של ZHA בדף {integrations_page} .", "missing_zwave": "חסר את לוח התצורה של Z-Wave? הוא הועבר לכניסה של Z-Wave בכרטיסייה {integrations_page} ." }, "integrations": { - "add_integration": "הוסף אינטגרציה", - "caption": "אינטגרציות", + "add_integration": "הוסף שילוב", + "attention": "דרושה תשומת לב", + "caption": "שילובים", "config_entry": { "area": "ב-{area}", "check_the_logs": "בדוק את היומנים", "configure": "הגדר", "delete": "מחק", - "delete_confirm": "האם אתה בטוח שברצונך למחוק אינטגרציה זו?", + "delete_confirm": "האם אתה בטוח שברצונך למחוק שילוב זה?", "depends_on_cloud": "תלוי בענן", - "device_unavailable": "מכשיר אינו זמין", + "device_unavailable": "ההתקן אינו זמין", "devices": "{count} {count, plural,\n one {device}\n other {devices}\n}", + "disable_error": "ההפעלה או השבתה של השילוב נכשלה", + "disable_restart_confirm": "הפעל מחדש את Assistant Home כדי לסיים את השבתת השילוב הזה", "disable": { + "disable_confirm": "האם אתה בטוח שברצונך להשבית את רשומת התצורה הזו? המכשירים והישויות שלו יושבתו.", + "disabled": "מושבת", "disabled_by": { "device": "מכשיר", - "integration": "אינטגרציה", + "integration": "שילוב", "user": "משתמש" - } + }, + "disabled_cause": "מושבת על ידי {cause}" }, + "disabled_polling": "תשאול אוטומטי עבור עדכוני נתונים אינו זמין", "documentation": "תיעוד", + "enable_restart_confirm": "הפעל מחדש את Assistant Home כדי לסיים את הפעלת השילוב הזה", "entities": "{count} {count, plural,\n one {entity}\n other {entities}\n}", - "entity_unavailable": "ישות לא זמינה", + "entity_unavailable": "הישות אינה זמינה", "firmware": "קושחה: {version}", "hub": "מחובר באמצעות", "logs": "יומן אירועים", "manuf": "על ידי {manufacturer}", "no_area": "ללא אזור", - "not_loaded": "לא נטען, בדוק את {logs_link}", + "not_loaded": "לא נטען", "options": "אפשרויות", "provided_by_custom_integration": "מסופק על ידי אינטגרציה מותאמת אישית", + "reload": "טען מחדש", + "reload_confirm": "השילוב נטען מחדש", + "reload_restart_confirm": "הפעל מחדש את Assistant Home כדי לסיים את הטעינה מחדש של שילוב זה", "rename": "שנה שם", - "restart_confirm": "הפעל מחדש את Home Assistant כדי להשלים את הסרת האינטגרציה", + "restart_confirm": "הפעל מחדש את Home Assistant כדי לסיים את הסרת השילוב", + "services": "{count} {count, plural,\n one {שירות}\n other {שירותים}\n}", "state": { "failed_unload": "ביטול הטעינה נכשל", "loaded": "טעון", "migration_error": "שגיאת המרה", "not_loaded": "לא טעון", "setup_error": "ההגדרה נכשלה", - "setup_retry": "מנסה להגדיר מחדש" + "setup_retry": "מנסה להתקין מחדש" }, "system_options": "אפשרויות מערכת", "unnamed_entry": "ערך ללא שם" @@ -1781,8 +2257,10 @@ "config_flow": { "aborted": "הופסק", "close": "סגור", + "could_not_load": "לא היתה אפשרות לטעון זרימת תצורה", "created_config": "נוצרה תצורה עבור {name}.", "dismiss": "ביטול תיבת דו-שיח", + "error": "שגיאה", "error_saving_area": "שגיאה בשמירת האזור: {error}", "external_step": { "description": "שלב זה מחייב אותך לבקר באתר אינטרנט חיצוני להשלמת הפעולה.", @@ -1792,41 +2270,50 @@ "loading_first_time": "אנא המתן בזמן שהאינטגרציה מותקנת", "next": "הבא", "not_all_required_fields": "לא כל שדות החובה מולאו.", - "not_loaded": "לא ניתן היה לטעון את האינטגרציה, נסה להפעיל מחדש את Home Assistant.", + "not_loaded": "לא ניתן היה לטעון את השילוב, נסה להפעיל מחדש את Home Assistant.", + "pick_flow_step": { + "new_flow": "לא, הגדר מופע אחר של {integration}", + "title": "גילינו את אלה, רוצים להגדיר אותם?" + }, "submit": "המשך" }, "configure": "הגדר", "configured": "הוגדר", - "description": "ניהול והגדרת אינטגרציות", - "details": "פרטי האינטגרציה", + "confirm_new": "האם אתה רוצה להגדיר {integration}?", + "description": "ניהול שילובים עם שירותים או התקנים", + "details": "פרטי השילוב", "disable": { - "show": "הצג" + "disabled_integrations": "{number} מושבת", + "hide_disabled": "הסתר שילובים מושבתים", + "show": "הצג", + "show_disabled": "הצג שילובים מושבתים" }, "discovered": "זוהו", "home_assistant_website": "אתר Home Assistant", "ignore": { - "confirm_delete_ignore": "פעולה זו תגרום לאינטגרציה להופיע באינטגרציות שהתגלו שוב כאשר היא תתגלה. ייתכן שתידרש הפעלה מחדש או להמתין כדי שזה יקרה.", - "confirm_delete_ignore_title": "הפסק להתעלם מ- {name} ?", - "confirm_ignore": "האם אתה בטוח שאתה לא רוצה להגדיר אינטגרציה זו? אתה יכול לבטל את זה על ידי לחיצה על 'הצג אינטגרציות שמתעלמים מהן' בתפריט שמשמאל למעלה.", + "confirm_delete_ignore": "פעולה זו תגרום לשילוב להופיע בשילובים שהתגלו שוב כאשר היא תתגלה. ייתכן שתידרש הפעלה מחדש או להמתין כדי שזה יקרה.", + "confirm_delete_ignore_title": "הפסק להתעלם מ-{name}?", + "confirm_ignore": "האם אתה בטוח שאתה לא רוצה להגדיר שילוב זה? אתה יכול לבטל את זה על ידי לחיצה על 'הצג שילובים שמתעלמים מהן' בתפריט שמשמאל למעלה.", "confirm_ignore_title": "התעלם מגילוי {name}?", - "hide_ignored": "הסתר אינטגרציות שמתעלמים מהן", + "hide_ignored": "הסתר שילובים שמתעלמים מהן", "ignore": "התעלם", "ignored": "מתעלם", - "show_ignored": "הצג אינטגרציות שמתעלמים מהן", + "show_ignored": "הצג שילובים שמתעלמים מהן", "stop_ignore": "הפסק להתעלם" }, - "integration": "אינטגרציה", - "integration_not_found": "האינטגרציה לא נמצאה.", - "new": "הגדר אינטגרציה", - "no_integrations": "נראה שעדיין אין לך אינטגציות. לחץ על הכפתור למטה כדי להוסיף את האינטגרציה הראשונה שלך!", + "integration": "שילוב", + "integration_not_found": "השילוב לא נמצא.", + "new": "הגדר שילוב", + "no_integrations": "נראה שעדיין לא הוגדרו שילובים. לחץ על הכפתור למטה כדי להוסיף את השילוב הראשון שלך!", "none": "כלום אינו הוגדר עדיין", "none_found": "לא נמצאו אינטגרציות", "none_found_detail": "התאם את קריטריוני החיפוש שלך.", - "note_about_integrations": "קיימות אינטגרציות שלא ניתן עדיין להגדירן ע\"י ממשק המשתמש.", + "note_about_integrations": "לא ניתן להגדיר עדיין את כל השילובים דרך ממשק המשתמש.", "note_about_website_reference": "מידע נוסף זמין ב:", + "reconfigure": "קביעת תצורה מחדש", "rename_dialog": "ערוך את שם ישות התצורה הזו", "rename_input_label": "שם ישות", - "search": "חיפוש אינטגרציות" + "search": "חפש שילובים" }, "introduction": "כאן ניתן להגדיר את הרכיבים ואת ה-Home Assistant. לא הכל ניתן להגדיר עם ממשק המשתמש עדיין, אבל אנחנו עובדים על זה.", "logs": { @@ -1844,14 +2331,14 @@ "warning": "WARNING" }, "load_full_log": "טען את הלוג המלא של Home Assistant", - "loading_log": "טוען יומן שגיאות ...", + "loading_log": "טוען יומן שגיאות...", "multiple_messages": "ההודעה התרחשה לראשונה בשעה {time} והיא מופיעה {counter} פעמים", - "no_errors": "לא דווחו שגיאות.", + "no_errors": "לא דווח על שגיאות", "no_issues": "אין נושאים חדשים!", "refresh": "רענן" }, "lovelace": { - "caption": "לוחות מחוונים של Lovelace", + "caption": "לוחות הבקרה של Lovelace", "dashboards": { "cant_edit_default": "לא ניתן לערוך את לוח המחוונים של לאבלייס מממשק המשתמש. באפשרותך להסתירו על-ידי הגדרת לוח מחוונים אחר כברירת מחדל.", "cant_edit_yaml": "לא ניתן לערוך שלוחות מחוונים המוגדרים ב- YAML מממשק המשתמש. שנה אותם ב- configuration.yaml.", @@ -1876,13 +2363,13 @@ "title": "כותרת", "title_required": "הכותרת נדרשת.", "update": "עדכן", - "url": "URL", + "url": "כתובת אתר", "url_error_msg": "כתובת האתר צריכה להכיל - ולא יכולה להכיל רווחים או תווים מיוחדים, למעט _ ו- -" }, "picker": { "add_dashboard": "הוסף לוח בקרה חדש", "headers": { - "conf_mode": "שיטת קביעת קונפיגרציה", + "conf_mode": "שיטת קביעת תצורה", "default": "ברירת מחדל", "filename": "שם קובץ", "require_admin": "מנהל בלבד", @@ -1892,7 +2379,7 @@ "open": "פתח" } }, - "description": "נהל/י את לוח הבקרה של Lovelace", + "description": "יצירת ערכות כרטיסים מותאמות אישית כדי לשלוט בביתך", "resources": { "cant_edit_yaml": "אתה משתמש ב- Lovelace במצב YAML, לכן אינך יכול לנהל את המשאבים שלך דרך ממשק המשתמש. נהל אותם ב- configuration.yaml.", "caption": "משאבים", @@ -1904,8 +2391,8 @@ "new_resource": "הוסף משאב חדש", "type": "סוג המשאב", "update": "עדכן", - "url": "URL", - "url_error_msg": "כתובת URL היא שדה נדרש", + "url": "כתובת אתר", + "url_error_msg": "כתובת אתר היא שדה חובה", "warning_header": "היה זהיר!", "warning_text": "הוספת משאבים יכולה להיות מסוכנת, וודא שאתה יודע את מקור המשאב וסומך עליו. משאבים רעים עלולים לפגוע קשות במערכת שלך." }, @@ -1913,11 +2400,11 @@ "add_resource": "הוסף משאב", "headers": { "type": "סוג", - "url": "URL" + "url": "כתובת אתר" }, "no_resources": "אין משאבים" }, - "refresh_body": "אתה צריך לרענן את הדף כדי להשלים את ההסרה, האם אתה רוצה לרענן עכשיו?", + "refresh_body": "עליך לרענן את הדף כדי להשלים את ההסרה. האם ברצונך לרענן כעת?", "refresh_header": "האם אתה רוצה לרענן?", "types": { "css": "Stylesheet", @@ -1942,55 +2429,118 @@ "topic": "נושא" }, "ozw": { + "button": "הגדר", "common": { - "node_id": "מזהה רכיב", + "controller": "בקר", + "instance": "מופע", + "network": "רשת", + "node_id": "מזהה צומת", "ozw_instance": "מופע OpenZWave", + "query_stage": "שלב שאילתה", + "wakeup_instructions": "הוראות השכמה", "zwave": "Z-Wave" }, "device_info": { - "node_failed": "הרכיב נכשל", + "node_failed": "הצומת נכשל", "stage": "שלב", "zwave_info": "מידע Z-Wave" }, + "navigation": { + "network": "רשת", + "node": { + "config": "תצורה", + "dashboard": "לוח בקרה" + }, + "nodes": "צמתים", + "select_instance": "בחר מופע" + }, "network_status": { + "details": { + "driverallnodesqueried": "כל הצמתים נחקרו", + "driverallnodesqueriedsomedead": "כל הצמתים נחקרו. כמה צמתים נמצאו מתים", + "driverawakenodesqueries": "כל הצמתים הערים נחקרו", + "driverfailed": "ההתחברות לבקר Z-Wave נכשלה", + "driverready": "אתחול בקר Z-Wave", + "driverremoved": "מנהל ההתקן הוסר", + "driverreset": "מנהל ההתקן אופס", + "offline": "OZWDaemon לא מקוון", + "ready": "מוכן להתחברות", + "started": "מחובר ל-MQTT", + "starting": "מתחבר ל-MQTT", + "stopped": "OpenZWave הופסק" + }, + "offline": "לא מקוון", + "online": "מקוון", + "starting": "מתחיל", "unknown": "לא ידוע" }, + "network": { + "header": "ניהול רשת", + "introduction": "נהל פונקציות ברחבי הרשת.", + "node_count": "{count} צמתים" + }, + "node_config": { + "header": "תצורת צומת", + "help_source": "תיאור פרמטרי תצורה וטקסט עזרה ניתנים על ידי פרויקט OpenZWave.", + "introduction": "נהל את פרמטרי התצורה השונים עבור צומת Z-Wave.", + "wakeup_help": "צמתים המופעלים באמצעות סוללה חייבים להיות ערים כדי לשנות את התצורה שלהם. אם הצומת אינו ער, OpenZWave ינסה לעדכן את תצורת הצומת בפעם הבאה שהוא יתעורר, דבר שעשוי להיות מספר שעות (או ימים) מאוחר יותר. בצע את השלבים הבאים כדי להעיר את המכשיר:" + }, + "node_metadata": { + "product_manual": "מדריך מוצר" + }, "node_query_stages": { "associations": "מרענן קבוצות וחברויות", - "cacheload": "טוען מידע מקובץ המטמון של OpenZWave. רכיבי סוללה יישארו בשלב זה עד שהרכיב יתעורר.", + "cacheload": "טוען מידע מקובץ המטמון של OpenZWave. צמתי סוללה יישארו בשלב זה עד שהצומת יתעורר.", "complete": "תהליך הראיון הושלם", - "configuration": "מקבל ערכי תצורה מהרכיב", - "dynamic": "מקבל ערכים המשתנים לעתים קרובות מהרכיב", - "instances": "מקבל פרטים אודות המופעים או הערוצים שבהם הרכיב תומך", - "manufacturerspecific1": "קבלת קודי יצרן ומזהי מוצר מהרכיב", - "manufacturerspecific2": "מקבל קודי יצרן ומזהי מוצר נוספים מהרכיב", - "neighbors": "קבלת רשימת שכנים מהרכיב", - "nodeinfo": "קבלת מחלקות פקודות נתמכות מהרכיב", - "nodeplusinfo": "קבלת מידע Z-Wave+ מהרכיב", - "probe": "בדיקה האם הרכיב ער/חי", - "protocolinfo": "קבלת יכולות Z-Wave בסיסיות של רכיב זה מהבקר", - "session": "מקבל ערכים המשתנים לעתים רחוקות מהרכיב", - "static": "מקבל ערכים סטטיים מהרכיב", + "configuration": "קבלת ערכי תצורה מהצומת", + "dynamic": "קבלת ערכים המשתנים לעתים קרובות מהצומת", + "instances": "קבלת פרטים אודות המופעים או הערוצים שבהם תומך התקן", + "manufacturerspecific1": "קבלת קודי יצרן ומזהה מוצר מהצומת", + "manufacturerspecific2": "קבלת קודי יצרן ומזהה מוצר נוספים מהצומת", + "neighbors": "קבלת רשימת שכני הצומת", + "nodeinfo": "קבלת מחלקות פקודה נתמכות מהצומת", + "nodeplusinfo": "קבלת מידע Z-Wave+ מהצומת", + "probe": "בדיקה אם הצומת ער/חי", + "protocolinfo": "קבלת יכולות Z-Wave בסיסיות של צומת זה מהבקר", + "session": "קבלת ערכים המשתנים לעתים רחוקות מהצומת", + "static": "קבלת ערכים סטטיים מההתקן", "versions": "מקבל מידע אודות גירסאות קושחה ומחלקות פקודות", - "wakeup": "הגדרת תמיכה עבור תורי התעוררות והודעות" + "wakeup": "הגדרת תמיכה בתורים והודעות השכמה" + }, + "node": { + "button": "פרטי צומת", + "not_found": "הצומת לא נמצא" + }, + "nodes_table": { + "failed": "נכשל", + "id": "מזהה", + "manufacturer": "יצרן", + "model": "דגם", + "query_stage": "שלב שאילתה", + "zwave_plus": "Z-Wave Plus" }, "refresh_node": { - "battery_note": "אם הרכיב מופעל באמצעות סוללה, הקפד להעיר אותו לפני שתמשיך", - "complete": "רענון הרכיב הושלם", - "description": "זה יגיד ל- OpenZWave לראיין מחדש את הרכיב ולעדכן את הפקודות, היכולות והערכים של הרכיב.", - "node_status": "מצה הרכיב", - "refreshing_description": "מרענן מידע על הרכיב", + "battery_note": "אם הצומת מופעל באמצעות סוללה, הקפד להעיר אותו לפני שתמשיך", + "button": "רענן צומת", + "complete": "רענון הצומת הושלם", + "description": "פעולה זו תגיד ל-OpenZWave לראיין מחדש צומת ולעדכן את מחלקות הפקודות, היכולות והערכים של הצומת.", + "node_status": "מצב הצומת", + "refreshing_description": "מרענן מידע צומת...", "start_refresh_button": "התחל לרענן", "step": "שלב", - "title": "רענן מידע הרכיב", + "title": "רענן מידע צומת", "wakeup_header": "הוראות התעוררות עבור", - "wakeup_instructions_source": "הוראות ההתעוררות מקורן במסד הנתונים של קהילת ה OpenZWave." + "wakeup_instructions_source": "הוראות ההשכמה מגיעות ממסד הנתונים של ההתקנים הקהילתיים OpenZWave." }, "select_instance": { + "header": "בחר מופע OpenZWave", + "introduction": "רצים יותר ממופע OpenZWave אחד. איזה מופע ברצונך לנהל?", "none_found": "לא הצלחנו למצוא שרת OpenZWave. אם אתה סבור שזה לא נכון, בדוק את הגדרות OpenZWave ו- MQTT וודא ש Home Assistant יכול לתקשר עם ה MQTT broker." }, "services": { - "cancel_command": "בטל פקודה" + "add_node": "הוסף צומת", + "cancel_command": "בטל פקודה", + "remove_node": "הסר צומת" } }, "person": { @@ -1999,7 +2549,7 @@ "confirm_delete": "האם אתה בטוח שברצונך למחוק אדם זה?", "confirm_delete2": "כל ההתקנים השייכים לאדם זה לא יהיו מוקצים.", "create_person": "צור אדם", - "description": "נהל את האנשים ש Home Assistant יעקב אחריהם.", + "description": "נהל את האנשים ש-Home Assistant עוקב אחריהם.", "detail": { "admin": "מנהל המערכת", "allow_login": "אפשר לאדם להתחבר", @@ -2009,13 +2559,13 @@ "device_tracker_intro": "בחר את המכשירים השייכים לאדם זה.", "device_tracker_pick": "בחר מכשיר למעקב", "device_tracker_picked": "עקוב אחר מכשיר", - "link_integrations_page": "עמוד אינטגרציות", - "link_presence_detection_integrations": "אינטגרציות זיהוי נוכחות", + "link_integrations_page": "עמוד שילובים", + "link_presence_detection_integrations": "שילובי איתור נוכחות", "linked_user": "משתמש מקושר", "name": "שם", "name_error_msg": "שם נדרש", "new_person": "אדם חדש", - "no_device_tracker_available_intro": "כאשר יש לך התקנים המציינים את נוכחותו של אדם, כאן תוכל להקצותם לאדם זה. באפשרותך להוסיף את המכשיר הראשון על-ידי הוספת אינטגרציה של זיהוי נוכחות מעמוד האינטגרציות.", + "no_device_tracker_available_intro": "כאשר יש לך התקנים המציינים את נוכחותו של אדם, כאן תוכל להקצותם לאדם זה. באפשרותך להוסיף את המכשיר הראשון על ידי הוספת שילוב של זיהוי נוכחות מעמוד השילובים.", "update": "עדכון" }, "introduction": "כאן תוכלו להגדיר כל אדם ב Home Assistant.", @@ -2027,8 +2577,8 @@ }, "scene": { "activated": "הופעלה סצינה {name}.", - "caption": "סצינות", - "description": "צור וערוך סצינות", + "caption": "סצנות", + "description": "צור וערוך סצנות", "editor": { "default_name": "סצינה חדשה", "devices": { @@ -2042,12 +2592,12 @@ "delete": "מחק ישות", "device_entities": "אם תוסיף ישות השייכת למכשיר, המכשיר יתווסף.", "header": "ישויות", - "introduction": "ניתן להגדיר כאן ישויות שאינן שייכות להתקנים.", + "introduction": "ניתן להגדיר כאן ישויות שאינן שייכות להתקן.", "without_device": "ישויות ללא מכשיר" }, "icon": "סמל", - "introduction": "השתמש בסצינות כדי להחיות את הבית שלך.", - "load_error_not_editable": "רק סצינות ב scenes.yaml ניתנות לעריכה.", + "introduction": "השתמש בסצנות כדי להחיות את ביתך.", + "load_error_not_editable": "רק סצנות ב-scenes.yaml ניתנות לעריכה.", "load_error_unknown": "שגיאה בטעינת סצנה ({err_no}).", "name": "שם", "save": "שמור", @@ -2057,22 +2607,24 @@ "add_scene": "הוסף סצנה", "delete_confirm": "האם אתה בטוח שברצונך למחוק את הסצינה הזו?", "delete_scene": "מחק סצנה", + "duplicate": "שכפל", + "duplicate_scene": "שכפל סצנה", "edit_scene": "ערוך סצנה", - "header": "עורך סצינות", + "header": "עורך סצנות", "headers": { "name": "שם" }, - "introduction": "עורך הסצנות מאפשר לך ליצור ולערוך סצינות. אנא עקוב אחר הקישור למטה כדי לקרוא את ההוראות בכדי לוודא שהגדרת נכון את Home Assistant.", - "learn_more": "למידע נוסף על סצינות", - "no_scenes": "לא מצאנו סצינות הניתנות לעריכה", - "only_editable": "רק סצינות שב scenes.yaml ניתנות לעריכה.", + "introduction": "עורך הסצנות מאפשר לך ליצור ולערוך סצנות. נא עקוב אחר הקישור שלהלן כדי לקרוא את ההוראות כדי לוודא שתצורת Home Assistant נקבעה כראוי.", + "learn_more": "למידע נוסף על סצנות", + "no_scenes": "לא הצלחנו למצוא סצנות", + "only_editable": "רק סצנות שהוגדרו ב-scenes.yaml ניתנות לעריכה.", "pick_scene": "בחר סצינה לעריכה", "show_info_scene": "הצג מידע על הסצנה" } }, "script": { - "caption": "סקריפט", - "description": "צור וערוך סקריפטים", + "caption": "סקריפטים", + "description": "ביצוע רצף של פעולות", "editor": { "alias": "שם", "default_name": "סקריפט חדש", @@ -2083,7 +2635,7 @@ "id": "מזהה ישות", "id_already_exists": "מזהה זה כבר קיים", "id_already_exists_save_error": "אינך יכול לשמור סקריפט זה מכיוון שהמזהה אינו ייחודי, בחר מזהה אחר או השאר אותו ריק כדי ליצור אוטומטית.", - "introduction": "השתמש בסקריפטים כדי לבצע רצף של פעולות.", + "introduction": "השתמש בסקריפטים כדי לבצע רצף של הרצות.", "link_available_actions": "למד עוד אודות פעולות זמינות.", "load_error_not_editable": "רק סקריפטים בתוך קובץ scripts.yaml ניתנים לעריכה.", "max": { @@ -2091,12 +2643,12 @@ "queued": "אורך התור" }, "modes": { - "description": "המצב שולט במה שקורה כאשר מופעל סקריפט בזמן שהוא עדיין פועל מהפעלה קודמת אחת או יותר. עיין ב {documentation_link} למידע נוסף.", + "description": "המצב שולט במה שקורה כאשר רץ סקריפט בזמן שהוא עדיין רץ מהרצה קודמת אחת או יותר. עיין ב-{documentation_link} למידע נוסף.", "documentation": "תיעוד סקריפט", "label": "מצב", "parallel": "מַקְבִּיל", "queued": "בתור", - "restart": "אתחול", + "restart": "הפעלה מחדש", "single": "יחיד (ברירת מחדל)" }, "save_script": "שמור סקריפט", @@ -2105,6 +2657,8 @@ }, "picker": { "add_script": "הוסף סקריפט", + "duplicate": "שכפל", + "duplicate_script": "שכפול סקריפט", "edit_script": "ערוך סקריפט", "header": "עורך סקריפטים", "headers": { @@ -2112,45 +2666,64 @@ }, "introduction": "עורך הסקריפטים מאפשר לך ליצור ולערוך סקריפטים. נא כנס לקישור שלמטה כדי לקרוא את ההוראות בכדי לוודא שקבעת את תצורת Home Assistant כהלה.", "learn_more": "למד עוד אודות קבצי סקריפטים", - "no_scripts": "לא מצאנו סקריפטים הניתנים לעריכה", - "run_script": "הפעל סקריפט", + "no_scripts": "לא הצלחנו למצוא סקריפטים", + "run_script": "הרץ סקריפט", "show_info": "הצג מידע על התסריט" } }, "server_control": { - "caption": "בקרת שרת", + "caption": "פקדי שרת", "description": "אתחל וכבה את שרת ה Home Assistant", "section": { "reloading": { - "automation": "טען מחדש אוטומציות", - "core": "טען מחדש את הליבה", - "group": "טען מחדש קבוצות", - "heading": "טען מחדש קונפיגורציה", - "input_boolean": "טען מחדש input boolean", - "input_datetime": "טען מחדש input date time", - "input_number": "טען מחדש input number", - "input_select": "טען מחדש input selects", - "input_text": "טען מחדש input text", - "introduction": "חלקים מסוימים של Home Assistant יכולים להטען מחדש ללא צורך בהפעלה מחדש.\nטעינה מחדש תשנה את הקונפיגורציה הנוכחית ותטען קונפיגורציה חדשה.", - "person": "טען מחדש אנשים", - "scene": "טען מחדש סצנות", - "script": "טען מחדש סקריפטים", - "zone": "טען מחדש אזורים" + "automation": "אוטומציות", + "command_line": "ישויות שורת פקודה", + "core": "מיקום והתאמות אישיות", + "filesize": "ישויות בגודל הקובץ", + "filter": "סינון ישויות", + "generic": "ישויות כלליות של מצלמת IP", + "generic_thermostat": "ישויות כלליות של תרמוסטט", + "group": "קבוצות, ישויות קבוצתיות ושירותי הודעה", + "heading": "טעינה מחדש של תצורת YAML", + "history_stats": "היסטוריית מצב ישויות", + "homekit": "HomeKit", + "input_boolean": "קלט בוליאני", + "input_datetime": "קלט תאריך וזמן", + "input_number": "קלט מספרים", + "input_select": "קלט בחירה", + "input_text": "קלט טקסט", + "introduction": "חלקים מסוימים של Home Assistant יכולים להטען מחדש ללא צורך בהפעלה מחדש.\nטעינה מחדש תשנה את התצורה הנוכחית ותטען תצורה חדשה.", + "min_max": "ישויות מינימום/מקסימום", + "mqtt": "ישויות MQTT שתצורתן נקבעה באופן ידני", + "person": "אנשים", + "ping": "איתות (Ping) ישויות חיישנים בינאריים", + "reload": "{domain}", + "rest": "שאר ישויות ושירותי הודעות", + "rpi_gpio": "ישויות GPIO של רספברי פאי", + "scene": "סצנות", + "script": "סקריפטים", + "smtp": "שירותי הודעת SMTP", + "statistics": "סטטיסטיקה ישויות", + "telegram": "שירותי הודעת טלגרם", + "template": "תבנית ישויות", + "trend": "מגמת ישויות", + "universal": "ישויות אוניברסליות של נגן מדיה", + "zone": "אזורים" }, "server_management": { "confirm_restart": "האם אתה בטוח שברצונך להפעיל מחדש את Home Assistant?", "confirm_stop": "האם אתה בטוח שברצונך לעצור את Home Assistant?", "heading": "ניהול שרת", "introduction": "לשלוט על שרת Home Assistant שלך... מ-Home Assistant.", - "restart": "אתחל", + "restart": "הפעלה מחדש", "stop": "עצור" }, "validation": { - "check_config": "בדיקת הקונפיגורציה", - "heading": "בדיקת הקונפיגורציה", - "introduction": "אמת את הקונפיגורציה שלך אם ביצעת לאחרונה שינויים מסוימים וברצונך לוודא שהיא תקינה", - "invalid": "קונפיגורציה לא תקנית", - "valid": "קונפיגורציה תקינה!" + "check_config": "בדיקת התצורה", + "heading": "בדיקת התצורה", + "introduction": "אמת את התצורה שלך אם ביצעת לאחרונה כמה שינויים בתצורה שלך וברצונך לוודא שהכול תקין.", + "invalid": "תצורה לא תקנית", + "valid": "תצורה תקינה!" } } }, @@ -2158,8 +2731,10 @@ "add_tag": "הוסף תג", "automation_title": "התג {name} נסרק", "caption": "תגים", + "confirm_remove": "האם בוודאות ברצונך להסיר את התג {tag}?", + "confirm_remove_title": "להסיר תג?", "create_automation": "צור אוטומציה עם תג", - "description": "ניהול תגים", + "description": "אוטומציות מופעלות כאשר תג NFC, קוד QR וכו' נסרק", "detail": { "companion_apps": "אפליקציות נלוות", "create": "צור", @@ -2178,6 +2753,8 @@ "last_scanned": "נסרק לאחרונה", "name": "שם" }, + "learn_more": "למד עוד אודות תגיות", + "never_scanned": "מעולם לא נסרק", "no_tags": "אין תגים", "write": "כתוב" }, @@ -2185,10 +2762,12 @@ "add_user": { "caption": "הוסף משתמש", "create": "צור", - "password": "סיסמה" + "password": "סיסמה", + "password_confirm": "אשר סיסמה", + "password_not_match": "סיסמאות אינן תואמות" }, "caption": "משתמשים", - "description": "ניהול משתמשים", + "description": "נהל את חשבונות המשתמש ב-Home Assistant", "editor": { "activate_user": "הפעל משתמש", "active": "פעיל", @@ -2201,8 +2780,10 @@ "delete_user": "מחיקת משתמש", "group": "קבוצה", "id": "מזהה", - "name": "שם", + "name": "שם תצוגה", + "new_password": "סיסמה חדשה", "owner": "בעלים", + "password_changed": "הסיסמה שונתה בהצלחה", "system_generated": "נוצר ע\"י המערכת", "system_generated_users_not_editable": "לא ניתן לעדכן משתמשים שנוצרו על ידי המערכת.", "system_generated_users_not_removable": "לא ניתן להסיר משתמשים שנוצרו על ידי המערכת.", @@ -2211,22 +2792,23 @@ "username": "שם משתמש" }, "picker": { + "add_user": "הוסף משתמש", "headers": { "group": "קבוצה", "is_active": "פעיל", "is_owner": "בעלים", - "name": "שם", - "system": "מערכת", + "name": "שם תצוגה", + "system": "המערכת נוצרה", "username": "שם משתמש" } }, - "users_privileges_note": "קבוצת המשתמשים הינה עבודה בעיצומה. המשתמש לא יוכל לנהל את המופע באמצעות ממשק המשתמש. אנו עדיין בודקים את כל נקודות הקצה של ממשק ה- API כדי לוודא שהם מגבילים נכון את הגישה למנהלים." + "users_privileges_note": "תכונת קבוצת המשתמשים מתבצעת כעת. למשתמש לא תהיה אפשרות לנהל את המופע באמצעות ממשק המשתמש. אנו עדיין בודקים את כל נקודות הקצה של ניהול API כדי לוודא שהן מגבילות כראוי את הגישה למנהלי מערכת." }, "zha": { "add_device": "הוסף מכשיר", "add_device_page": { "discovered_text": "התקנים יופיעו כאן לאחר שהתגלו.", - "no_devices_found": "לא נמצאו התקנים כלשהם, וודא שהם במצב צימוד והקפד שיהיו פעילים בזמן החיפוש.", + "no_devices_found": "לא נמצאו התקנים, ודא שהם נמצאים במצב שיוך ושמור אותם ערים בזמן שהגילוי פועל.", "pairing_mode": "ודא שההתקנים שלך נמצאים במצב צימוד. בדוק את הוראות ההתקן כיצד לבצע זאת.", "search_again": "חפש שוב", "spinner": "מחפש מכשירי ZHA Zigbee..." @@ -2252,7 +2834,7 @@ "clusters": { "header": "אשכולות", "help_cluster_dropdown": "בחר אשכול כדי להציג תכונות ופקודות.", - "introduction": "אשכולות הם אבני הבניין עבור פונקציונליות Zigbee. הן מפרידות את הפונקציונליות ליחידות לוגיות. קיימים סוגים של לקוחות ושרתים הכוללים תכונות ופקודות." + "introduction": "אשכולות הם אבני הבניין עבור פונקציונליות Zigbee. הם מפרידים פונקציונליות ליחידות לוגיות. קיימים סוגי לקוחות ושרתים המורכבים מתכונות ופקודות." }, "common": { "clusters": "אשכולות", @@ -2315,6 +2897,7 @@ "caption": "ויזואליזציה", "header": "הדמית רשת", "highlight_label": "הדגש התקנים", + "refresh_topology": "רענן טופולוגיה", "zoom_label": "הכנס למכשיר" } }, @@ -2324,12 +2907,12 @@ "configured_in_yaml": "לא ניתן לערוך אזורים המוגדרים באמצעות configuration.yaml באמצעות ממשק המשתמש.", "confirm_delete": "האם אתה בטוח שברצונך למחוק אזור זה?", "create_zone": "צור אזור", - "description": "נהל את האזורים שבהם ברצונך לעקוב אחר אנשים.", + "description": "נהל את האזורים שבהם ברצונך לעקוב אחר אנשים", "detail": { "create": "צור", "delete": "מחק", "icon": "סמל", - "icon_error_msg": "הסמל צריך להיות בפורמט: prefix:iconname, למשל: mdi:home", + "icon_error_msg": "הסמליל צריך להיות בפורמט: קידומת:שםסמליל, למשל: mdi:home", "latitude": "קו רוחב", "longitude": "קו אורך", "name": "שם", @@ -2341,32 +2924,72 @@ "update": "עדכן" }, "edit_home_zone": "עדיין לא ניתן לערוך את רדיוס אזור הבית מממשק המשתמש. גרור את הסמן על המפה כדי להזיז את אזור הבית.", - "edit_home_zone_narrow": "הרדיוס של אזור הבית שלך ניתן לעריכה מדף הקונפיגורציה הכללי. עדיין לא ניתן לערוך את רדיוס אזור הבית מממשק המשתמש. האם ברצונך לעבור לקונפיגורציה הכללית?", - "go_to_core_config": "לעבור לקונפיגורציה הכללית?", - "home_zone_core_config": "המיקום של אזור הבית שלך ניתן לעריכה מדף הקונפיגורציה הכללי. עדיין לא ניתן לערוך את מיקום אזור הבית מממשק המשתמש. האם ברצונך לעבור לקונפיגורציה הכללית?", + "edit_home_zone_narrow": "עדיין לא ניתן לערוך את הרדיוס של אזור הבית מהחזית. ניתן לשנות את המיקום מהתצורה הכללית.", + "go_to_core_config": "לעבור לתצורה כללית?", + "home_zone_core_config": "המיקום של אזור הבית שלך ניתן לעריכה מדף התצורה הכללי. עדיין לא ניתן לערוך את הרדיוס של אזור הבית מהחזית. האם ברצונך לעבור לתצורה הכללית?", "introduction": "אזורים מאפשרים לך לציין אזורים מסוימים בכדור הארץ. כאשר אדם נמצא באזור, הסטטוס יקח את השם מהאזור. אזורים יכולים לשמש גם כטריגר או תנאי בתוך הגדרות אוטומציה.", "no_zones_created_yet": "נראה שעדיין לא יצרת אזורים." }, "zwave_js": { + "add_node": { + "cancel_inclusion": "בטל הכללה", + "controller_in_inclusion_mode": "בקר Z-Wave נמצא כעת במצב הכללה.", + "follow_device_instructions": "בצע את ההוראות המצורפת להתקן כדי להפעיל את השיוך בהתקן.", + "inclusion_failed": "לא היתה אפשרות להוסיף את הצומת. יש לבדוק את יומני הרישום לקבלת מידע נוסף.", + "inclusion_finished": "הצומת נוסף.", + "interview_failed": "ראיון ההתקן נכשל. ייתכן שמידע נוסף יהיה זמין ביומני הרישום.", + "interview_started": "המתקן מתראיין. פעולה זו עשויה להימשך זמן מה.", + "introduction": "אשף זה ינחה אותך לאורך הוספת צומת לרשת Z-Wave שלך.", + "secure_inclusion_warning": "התקנים מאובטחים דורשים רוחב פס נוסף; התקנים מאובטחים רבים מדי יכולים להאט את רשת Z-Wave שלך. אנו ממליצים להשתמש בהכללה מאובטחת רק עבור מכשירים הדורשים זאת, כגון מנעולים או פותחני דלתות מוסך.", + "start_inclusion": "התחל הכללה", + "start_secure_inclusion": "התחל הכללה מאובטחת", + "title": "הוסף צומת Z-Wave", + "use_secure_inclusion": "השתמש בהכללה מאובטחת", + "view_device": "הצג התקן" + }, + "button": "הגדר", + "common": { + "add_node": "הוסף צומת", + "close": "סגור", + "home_id": "מזהה בית", + "network": "רשת", + "node_id": "מזהה צומת", + "remove_node": "הסר צומת" + }, "dashboard": { + "driver_version": "גירסת מנהל התקן", "dump_dead_nodes_text": "חלק מהצמתים שלך לא הגיבו ונחשבים מתים. אלה לא ייוצאו לחלוטין.", "dump_dead_nodes_title": "חלק מהצמתים שלך מתים", "dump_debug": "הורד תמונת מצב של הרשת שלך כדי לעזור באבחון בעיות", "dump_not_ready_confirm": "הורדה", "dump_not_ready_text": "אם אתה יוצר ייצוא בזמן שלא כל הצמתים מוכנים, אתה עלול לפספס את הנתונים הדרושים. תן לרשת שלך זמן לשאילת כל הצמתים. האם אתה רוצה להמשיך?", "dump_not_ready_title": "עדיין לא כל הצמתים מוכנים", - "nodes_ready": "צמתים מוכנים" + "header": "נהל את רשת Z-Wave שלך", + "home_id": "מזהה בית", + "introduction": "ניהול את רשת Z-Wave וצמתי Z-Wave", + "nodes_ready": "צמתים מוכנים", + "server_version": "גירסת שרת" }, "device_info": { - "device_config": "הגדר את המכשיר" + "device_config": "הגדר את המכשיר", + "node_ready": "הצומת מוכן", + "node_status": "מצב הצומת", + "zwave_info": "מידע Z-Wave" }, "logs": { "log_level": "רמת יומן", + "log_level_changed": "רמת היומן שונתה ל: {level}", "subscribed_to_logs": "הרשם כמנוי להודעות יומן Z-Wave JS ...", "title": "יומני Z-Wave JS" }, "navigation": { - "logs": "יומנים" + "logs": "יומנים", + "network": "רשת" + }, + "network_status": { + "connected": "מחובר", + "connecting": "מתחבר", + "unknown": "לא ידוע" }, "node_config": { "attribution": "פרמטרים ותיאורי תצורת המכשיר מסופקים על ידי {device_database}", @@ -2380,36 +3003,59 @@ "set_param_queued": "שינוי הפרמטר נכנס לתור ויעודכן כאשר ההתקן יתעורר.", "zwave_js_device_database": "מאגר התקני Z-Wave JS" }, + "node_status": { + "alive": "חי", + "asleep": "ישן", + "awake": "ער", + "dead": "מת", + "unknown": "לא ידוע" + }, "reinterview_node": { "battery_device_warning": "יהיה עליך להעיר התקנים המופעלים באמצעות סוללה לפני שתתחיל בראיון מחדש. עיין במדריך למשתמש של המכשיר לקבלת הוראות להעיר את ההתקן.", "in_progress": "המכשיר מתראיין. זה עלול לקחת זמן מה.", - "interview_complete": "ראיון המכשיר הושלם.", + "interview_complete": "ראיון ההתקן הושלם.", "interview_failed": "ראיון המכשיר נכשל. מידע נוסף עשוי להיות זמין ביומנים.", "introduction": "ראיינו מחדש מכשיר ברשת Z-Wave שלכם. השתמש בתכונה זו אם הפונקציונליות של ההתקן שלך חסרה או שגויה.", "run_in_background": "ניתן לסגור תיבת דו-שיח זו והראיון יימשך ברקע.", "start_reinterview": "מתחיל ראיון מחדש", "title": "ראיון מחדש של התקן Z-Wave" + }, + "remove_node": { + "cancel_exclusion": "בטל אי הכללה", + "controller_in_exclusion_mode": "בקר Z-Wave שלך נמצא כעת במצב אי הכללה.", + "exclusion_failed": "לא היתה אפשרות להסיר את הצומת. יש לבדוק את יומני הרישום לקבלת מידע נוסף.", + "exclusion_finished": "צומת {id} הוסר מרשת Z-Wave שלך.", + "follow_device_instructions": "בצעו את ההוראות המצורף להתקן כדי להפעיל אי הכללה בהתקן.", + "introduction": "הסר צומת מרשת Z-Wave שלך והסר את ההתקן והישויות המשויכים מ-Home Assistant.", + "start_exclusion": "התחל אי הכללה", + "title": "הסר צומת Z-Wave" } }, "zwave": { "button": "הגדר", "common": { "index": "אינדקס", - "instance": "פרמטר", + "instance": "מופע", "unknown": "לא ידוע", "value": "ערך תצורה", - "wakeup_interval": "מרווח פעולה" + "wakeup_interval": "מרווח זמן להתעוררות" }, "description": "נהל את רשת ה- Z-Wave שלך", "learn_more": "למידע נוסף על Z-Wave", + "migration": { + "ozw": { + "header": "העבר ל-OpenZWave", + "introduction": "אשף זה יעזור לך לעבור משילוב Z-Wave מדור קודם לשילוב OpenZWave שנמצא כעת בגרסת ביטא." + } + }, "network_management": { "header": "ניהול רשת ה Z-Wave", "introduction": "הפעל פקודות המשפיעות על רשת ה-Z Wave. לא תקבל משוב אם רוב הפקודות הצליחו, אך באפשרותך לבדוק את יומן ה-OZW כדי לנסות לגלות." }, "network_status": { "network_started": "רשת ה Z-Wave הופעלה", - "network_started_note_all_queried": "כל הרכיבים נבדקו", - "network_started_note_some_queried": "רכיבים דלוקים נבדקו. רכיבים כבויים יבדקו כאשר ידלקו.", + "network_started_note_all_queried": "כל הצמתים נחקרו.", + "network_started_note_some_queried": "בוצעה שאילתה על צמתים ערים. צמתים ישנים יישאלו כאשר הם יתעוררו.", "network_starting": "מפעיל את רשת ה Z-Wave", "network_starting_note": "הדבר עשוי להימשך זמן מה בהתאם לגודל הרשת.", "network_stopped": "רשת ה Z-Wave נעצרה" @@ -2418,10 +3064,10 @@ "config_parameter": "פרמטר תצורה", "config_value": "ערך תצורה", "false": "False", - "header": "עריכת קונפיגורציה", + "header": "אפשרויות תצורת צומת", "seconds": "שניות", - "set_config_parameter": "הגדר פרמטר Config", - "set_wakeup": "בחירת מרווח פעולה", + "set_config_parameter": "הגדרת פרמטר תצורה", + "set_wakeup": "הגדרת מרווח זמן להתעוררות", "true": "True" }, "node_management": { @@ -2438,7 +3084,7 @@ "node_to_control": "יחידה לניהול", "nodes": "יחידות", "nodes_hint": "בחר יחידה כדי להציג אפשרויות ליחידה", - "nodes_in_group": "יחידות אחרות בקבוצה זו:", + "nodes_in_group": "צמתים אחרים בקבוצה זו:", "pooling_intensity": "עוצמת דגימה", "protection": "הגנה", "remove_broadcast": "הסר שידור רחב", @@ -2453,8 +3099,8 @@ "tail": "סוף" }, "services": { - "add_node": "הוסף רכיב", - "add_node_secure": "הוסף רכיב מאובטח", + "add_node": "הוסף צומת", + "add_node_secure": "הוסף צומת מאובטח", "cancel_command": "ביטול פקודה", "heal_network": "ריפוי רשת", "heal_node": "תיקון יחידה", @@ -2463,9 +3109,9 @@ "refresh_entity": "רענן ישות", "refresh_node": "רענן יחידה", "remove_failed_node": "הסר יחידה תקולה", - "remove_node": "הסר רכיב", + "remove_node": "הסר צומת", "replace_failed_node": "החלף יחידה תקולה", - "save_config": "שמור קונפיגורציה", + "save_config": "שמור תצורה", "soft_reset": "איפוס רך", "start_network": "הפעל רשת", "stop_network": "עצור רשת", @@ -2480,7 +3126,7 @@ "custom": { "external_panel": { "complete_access": "תהיה לו גישה לכל הנתונים ב- Assistant Home.", - "hide_message": "בדוק במסמכים את הרכיב panel_custom כדי להסתיר הודעה זו", + "hide_message": "בדוק מסמכים עבור רכיב panel_custom כדי להסתיר הודעה זו", "question_trust": "האם אתה סומך על הפאנל החיצוני {name} ב {link} ?" } }, @@ -2492,12 +3138,12 @@ "count_listeners": "({count} מאזינים)", "data": "נתוני אירוע (YAML, אופציונלי)", "description": "יריית אירוע במערכת", - "documentation": "תיעוד אירועים.", + "documentation": "תיעוד אירועים", "event_fired": "אירוע {name} נורה", "fire_event": "שגר אירוע", "listen_to_events": "האזן לאירועים", "listening_to": "מאזין ל", - "notification_event_fired": "אירוע {type} נורה בהצלחה!", + "notification_event_fired": "האירוע {type} הופעל בהצלחה!", "start_listening": "התחל להאזין", "stop_listening": "עצור האזנה", "subscribe_to": "אירוע להירשם אליו", @@ -2505,6 +3151,8 @@ "type": "סוג אירוע" }, "services": { + "accepts_target": "שירות זה מקבל יעד, לדוגמה: 'entity_id: light.bed_light'", + "all_parameters": "כל הפרמטרים הזמינים", "call_service": "קריאה לשירות", "column_description": "תיאור", "column_example": "דוגמא", @@ -2512,18 +3160,24 @@ "description": "כלי הפיתוח של השירותים מאפשר לך לקרוא לכל שירות ב Home Assistant.", "fill_example_data": "מלא נתונים לדוגמה", "no_template_ui_support": "ממשק המשתמש אינו תומך בתבניות, עדיין תוכל להשתמש בעורך ה YAML.", - "title": "שירותים" + "title": "שירותים", + "ui_mode": "עבור למצב ממשק משתמש", + "yaml_mode": "עבור למצב YAML", + "yaml_parameters": "פרמטרים זמינים במצב YAML בלבד" }, "states": { "alert_entity_field": "ישות היא שדה חובה", "attributes": "תכונות", + "copy_id": "העתק מזהה ללוח", "current_entities": "ישויות נוכחיות", - "description1": "הגדר את הייצוג של המכשיר בתוך Home Assistant.", - "description2": "זה לא יתקשר עם המכשיר עצמו.", + "description1": "הגדר את ייצוג המצב הנוכחי של ישות במסגרת Assistant Home.", + "description2": "אם הישות שייכת להתקן, לא תהיה תקשורת ממשית עם התקן זה.", "entity": "ישות", "filter_attributes": "סנן תכונות", "filter_entities": "סנן ישויות", "filter_states": "סנן מצבים", + "last_changed": "שינוי אחרון", + "last_updated": "עודכן לאחרונה", "more_info": "מידע נוסף", "no_entities": "אין ישויות", "set_state": "קבע מצב", @@ -2532,10 +3186,18 @@ "title": "מצבים" }, "templates": { + "all_listeners": "תבנית זו מאזינה לכל האירועים שהשתנו על ידי המצב.", "description": "Templates are rendered using the Jinja2 template engine with some Home Assistant specific extensions.", + "domain": "תחום", "editor": "Template editor", + "entity": "ישות", "jinja_documentation": "Jinja2 template documentation", + "listeners": "תבנית זו מאזינה לאירועים הבאים שהשתנו במצב:", + "no_listeners": "תבנית זו אינה מאזינה לאירועים כלשהם ולא תתעדכן באופן אוטומטי.", + "reset": "איפוס לתבנית הדגמה", + "result_type": "סוג תוצאה", "template_extensions": "Home Assistant template extensions", + "time": "תבנית זו מתעדכנת בתחילת כל דקה.", "title": "תבניות", "unknown_error_template": "Unknown error rendering template" } @@ -2548,8 +3210,8 @@ "observer": "בדוק את הצופה", "reboot": "נסה אתחול מחדש של המחשב המארח", "system_health": "בדוק את בריאות המערכת", - "title": "לא היתה אפשרות לטעון את לוח ה Supervisor!", - "wait": "אם רק התחלת, ודא שנתת ל Supervisor מספיק זמן להתחיל." + "title": "לא היתה אפשרות לטעון את לוח המפקח!", + "wait": "אם רק התחלת, ודא שנתת למפקח מספיק זמן להתחיל." } }, "history": { @@ -2576,14 +3238,17 @@ }, "cards": { "actions": { - "action_confirmation": "האם אתה בטוח שברצונך לבצע פעולה \" {action} \"?", - "no_service": "לא צוין שירות להפעלה", + "action_confirmation": "האם אתה בטוח שברצונך להריץ את \"{action}\"?", + "no_entity_more_info": "לא סופקה ישות עבור תיבת דו שיח של מידע נוסף", + "no_entity_toggle": "אין ישות שניתנה להחלפה", + "no_navigation_path": "לא צוין נתיב ניווט", + "no_service": "לא צוין שירות להרצה", "no_url": "לא צוין כתובת אתר לפתיחה" }, "confirm_delete": "האם אתה בטוח שברצונך למחוק את הכרטיס הזה?", "empty_state": { - "go_to_integrations_page": "עבור אל דף האינטגרציות.", - "no_devices": "דף זה מאפשר לך לשלוט במכשירים שלך, אך נראה שעדיין לא הוגדרו מכשירים. עבור אל דף האינטגרציות כדי להתחיל.", + "go_to_integrations_page": "עבור לדף השילובים.", + "no_devices": "דף זה מאפשר לך לשלוט במכשירים שלך, אולם נראה שעדיין לא הגדרת התקנים. עבור לדף שילובים כדי להתחיל.", "title": "ברוך הבא הביתה" }, "entities": { @@ -2614,7 +3279,7 @@ } }, "changed_toast": { - "message": "תצורת Lovelace עודכנה, האם ברצונך לרענן?" + "message": "תצורת ממשק המשתמש Lovelace עבור לוח בקרה זה עודכנה. האם לרענן כדי לראות את השינויים?" }, "components": { "timestamp-display": { @@ -2631,8 +3296,9 @@ "navigate": "נווט", "none": "אין פעולה", "toggle": "החלף מצב", - "url": "Url" + "url": "כתובת אתר" }, + "navigation_path": "נתיב ניווט", "url_path": "נתיב כתובת URL" }, "card": { @@ -2642,12 +3308,13 @@ "name": "לוח אזעקה" }, "button": { - "default_action_help": "פעולת ברירת המחדל תלויה ביכולות הישות, היא תופעל או שמידע נוסף יוצג.", + "default_action_help": "פעולת ברירת המחדל תלויה ביכולות הישות, היא תוחלף או שתוצג תיבת הדו שיח של מידע נוסף.", "description": "כרטיס ה־Button מאפשר להוסיף כפתורים לביצוע משימות.", "name": "כפתור" }, "calendar": { "calendar_entities": "ישויות לוח שנה", + "description": "כרטיס לוח השנה מציג לוח שנה הכולל תצוגות יום, שבוע ורשימה", "inital_view": "תצוגה ראשונית", "name": "לוח שנה", "views": { @@ -2662,9 +3329,9 @@ "condition_explanation": "הכרטיס יוצג כאשר מתקיימים *כל* התנאים להלן.", "conditions": "תנאים", "current_state": "נוכחי", - "description": "הכרטיס ה־Conditional מציג כרטיס אחר המבוסס על מצבי ישוית (States).", + "description": "הכרטיס המותנה מציג כרטיס נוסף המבוסס על מצבי ישויות.", "name": "מותנה", - "state_equal": "כאשר המצב (State)שווה ל", + "state_equal": "כאשר המצב (State) שווה ל", "state_not_equal": "כאשר המצב (State) אינו שווה ל" }, "config": { @@ -2673,12 +3340,18 @@ }, "entities": { "description": "כרטיס היישויות הוא סוג הכרטיס הנפוץ ביותר. הוא מקבץ ישויות יחד לרשימות.", + "edit_special_row": "הצג את הפרטים של שורה זו על ידי לחיצה על לחצן העריכה", "entity_row_editor": "עורך שורת ישות", "entity_row": { "attribute": "שדה", "button": "כפתור", "buttons": "כפתורים", - "conditional": "מותנה" + "call-service": "הפעל שירות", + "cast": "Cast", + "conditional": "מותנה", + "divider": "מפריד", + "section": "מקטע", + "weblink": "קישור" }, "name": "ישויות", "secondary_info_values": { @@ -2686,12 +3359,13 @@ "entity-id": "מזהה ישות", "last-changed": "שונה לאחרונה", "last-triggered": "הופעל לאחרונה", - "last-updated": "עודכן לאחרונה", + "last-updated": "עדכון אחרון", "none": "אין מידע משני", "position": "מיקום", "tilt-position": "הטה מיקום" }, "show_header_toggle": "הצג שינוי מצב כותרת?", + "special_row": "שורה מיוחדת", "toggle": "החלף מצב ישויות." }, "entity-filter": { @@ -2726,7 +3400,7 @@ "icon_height": "גובה אייקון", "image": "נתיב תמונה", "manual": "ידני", - "manual_description": "צריך להוסיף כרטיס מותאם אישית או פשוט רוצה לכתוב באופן ידני את ה-yaml?", + "manual_description": "צריך להוסיף כרטיס מותאם אישית או רק רוצה לכתוב באופן ידני את YAML?", "maximum": "מקסימום", "minimum": "מינימום", "name": "שם", @@ -2738,11 +3412,12 @@ "show_name": "להציג שם?", "show_state": "הצג מצב?", "state": "מצב", + "state_color": "צבע סמלילים על סמך מצב?", "tap_action": "פעולת הקשה", "theme": "ערכת נושא", "title": "כותרת", "unit": "יחידה", - "url": "Url" + "url": "כתובת אתר" }, "glance": { "columns": "עמודות", @@ -2751,6 +3426,7 @@ }, "grid": { "columns": "עמודות", + "description": "כרטיס הרשת מאפשר לך להציג כרטיסים מרובים ברשת.", "name": "רשת", "square": "הצג כרטיסים כריבועים" }, @@ -2768,12 +3444,16 @@ }, "iframe": { "description": "כרטיס דף האינטרנט מאפשר לך להטביע את דף האינטרנט המועדף עליך ישירות לתוך Home Assistant.", - "name": "iFrame" + "name": "דף אינטרנט" }, "light": { "description": "כרטיס האור מאפשר לך לשנות את בהירות האור.", "name": "תאורה" }, + "logbook": { + "description": "כרטיס יומן הרישום מציג רשימה של אירועים עבור ישויות.", + "name": "יומן רישום" + }, "map": { "dark_mode": "מצב כהה?", "default_zoom": "זום התחלתי", @@ -2801,7 +3481,7 @@ "name": "Picture Entity" }, "picture-glance": { - "description": "כרטיס ה- Picture Glance מציג תמונה ומצבי ישות תואמים כסמל. הישויות בצד שמאל מאפשרות לבצע פעולות, אחרות מציגות דיאלוג מידע נוסף.", + "description": "הכרטיס מבט מהיר על תמונה מציג תמונה ואת מצבי הישות המתאימים כסמל. הישויות בצד ימין מאפשרות פעולות דו מצביות, אחרות מציגות את תיבת הדו שיח של מידע נוסף.", "name": "Picture Glance", "state_entity": "ישות מצב" }, @@ -2816,7 +3496,8 @@ "sensor": { "description": "כרטיס החיישן מעניק לך סקירה מהירה של מצב החיישנים שלך באמצעות גרף אופציונלי להמחשת שינוי לאורך זמן.", "graph_type": "סוג גרף", - "name": "חיישן" + "name": "חיישן", + "show_more_detail": "הצג פרטים נוספים" }, "shopping-list": { "description": "כרטיס רשימת הקניות מאפשר לך להוסיף, לערוך, לבצע הוצאה ולנקות פריטים מרשימת הקניות שלך.", @@ -2838,25 +3519,37 @@ } }, "cardpicker": { + "by_card": "לפי כרטיס", + "by_entity": "לפי ישות", "custom_card": "מותאם אישית", + "domain": "תחום", + "entity": "ישות", "no_description": "אין תיאור זמין" }, + "common": { + "add": "הוסף", + "clear": "נקה", + "edit": "ערוך", + "none": "ללא" + }, "edit_badges": { "panel_mode": "תגים אלה לא יוצגו מאחר שתצוגה זו נמצאת במצב \"לוח\"." }, "edit_card": { "add": "הוסף כרטיסייה", + "clear": "נקה", "confirm_cancel": "האם אתה בטוח שברצונך לבטל?", - "delete": "מחק", + "delete": "מחק כרטיס", "duplicate": "שכפל כרטיס", "edit": "ערוך", - "header": "הגדרות כרטיסייה", - "move": "הזז", + "header": "תצורת כרטיסייה", + "move": "עבור לתצוגה", "move_after": "העבר כרטיס אחרי", "move_before": "העבר כרטיס לפני", "options": "אפשרויות נוספות", - "pick_card": "בחר את הכרטיסייה שברצונך להוסיף.", + "pick_card": "איזה כרטיס ברצונך להוסיף?", "pick_card_view_title": "איזה כרטיס ברצונך להוסיף לתצוגת {name}?", + "search_cards": "כרטיסי חיפוש", "show_code_editor": "הצג עורך קוד", "show_visual_editor": "הצג עורך ויזואלי", "toggle_editor": "עורך בורר מצבים", @@ -2865,7 +3558,7 @@ }, "edit_lovelace": { "edit_title": "ערוך כותרת", - "explanation": "כותרת זו מוצגת מעל לכל התצוגות שלך ב- Lovelace.", + "explanation": "כותרת זו מוצגת מעל לכל התצוגות שלך בממשק המשתמש של Lovelace.", "header": "כותרת ממשק ה- Lovelace שלך", "title": "כותרת" }, @@ -2873,7 +3566,7 @@ "add": "הוסף תצוגה", "delete": "מחק תצוגה", "edit": "ערוך תצוגה", - "header": "הצג הגדרות", + "header": "הצג תצורה", "header_name": "הצג את תצורת {name}", "move_left": "הזז את התצוגה שמאלה", "move_right": "הזז את התצוגה ימינה", @@ -2885,14 +3578,32 @@ } }, "header": "ערוך UI", + "header-footer": { + "choose_header_footer": "בחר {type}", + "footer": "כותרת תחתונה", + "header": "כותרת עליונה", + "types": { + "buttons": { + "name": "כפתורים" + }, + "graph": { + "name": "גרף" + }, + "picture": { + "name": "תמונה" + } + } + }, "menu": { - "open": "פתח את תפריט Lovelace", - "raw_editor": "עורך הקונפיגורציה" + "manage_dashboards": "נהל לוחות מחוונים", + "manage_resources": "נהל משאבים", + "open": "פתיחת את תפריט ממשק המשתמש Lovelace", + "raw_editor": "עורך תצורה גולמית" }, "migrate": { - "header": "ההגדרה לא מתאימה", - "migrate": "הגר הגדרה", - "para_migrate": "Home Assistant יכול להוסיף מזהה יחודי לכל הכרטיסיות והתצוגות שלך בצורה אוטומטית בכך שתלחץ על לחצן ״הגר הגדרה״.", + "header": "תצורה אינה תואמת", + "migrate": "העבר תצורה", + "para_migrate": "Home Assistant יכול להוסיף מזהים לכל הכרטיסים והתצוגות שלך באופן אוטומטי עבורך על ידי לחיצה על לחצן 'העבר תצורה'.", "para_no_id": "האלמנט הנוכחי לא מכיל מזהה יחודיי. בבקשה הוסף מזהה יחודי לאלמט זה בקובץ 'ui-lovelace.yaml'." }, "move_card": { @@ -2900,14 +3611,16 @@ }, "raw_editor": { "confirm_remove_config_text": "אנו ניצור אוטומטית את תצוגות ממשק המשתמש של Lovelace עם האזורים והמכשירים שלך אם תסיר את קונפיגורציית ממשק המשתמש שלך ב- Lovelace.", - "confirm_remove_config_title": "האם אתה בטוח שברצונך להסיר את תצורת ממשק המשתמש של Lovelace? אנו נייצר אוטומטית את תצוגות ממשק המשתמש שלך ב- Lovelace עם האזורים והמכשירים שלך.", + "confirm_remove_config_title": "האם אתה בטוח שברצונך להסיר את תצורת ממשק המשתמש של Lovelace?", "confirm_unsaved_changes": "יש לך שינויים שלא נשמרו, אתה בטוח שברצונך לצאת?", - "confirm_unsaved_comments": "התצורה שלך מכילה הערות, אלה לא יישמרו. האם אתה רוצה להמשיך?", - "error_invalid_config": "התצורה שלך אינה תקפה: {error}", + "confirm_unsaved_comments": "ייתכן שהתצורה שלך מכילה הערות, הערות אלה לא יישמרו. האם ברצונך להמשיך?", + "error_invalid_config": "התצורה שלך אינה חוקית: {error}", "error_parse_yaml": "לא ניתן לנתח את ה-YAML: {error}", - "error_remove": "לא ניתן להסיר את הקונפיגורציה: {error}", + "error_remove": "לא ניתן להסיר את התצורה: {error}", "error_save_yaml": "אין אפשרות לשמור את ה-YAML: {error}", - "header": "עריכת קונפיגורציה", + "header": "עריכת תצורה", + "lovelace_changed": "התצורה של Lovelace עודכנה, האם ברצונך לטעון את התצורה המעודכנת בעורך ולאבד את השינויים הנוכחיים שלך?", + "reload": "טען מחדש", "resources_moved": "אין להוסיף עוד משאבים לתצורת Lovelace אך ניתן להוסיף אותם בלוח התצורה של Lovelace.", "save": "שמור", "saved": "נשמר", @@ -2918,7 +3631,7 @@ "close": "סגור", "empty_config": "התחל עם לוח בקרה ריק", "header": "קח שליטה על Lovelace ממשק המשתמש שלך", - "para": "כברירת מחדל Home Assistant יתחזק את ממשק המשתמש שלך , יעדכן אותו כאשר קומפוננטות או ישויות חדשות יהפכו לזמינות. אם תקח שליטה אנו לא נוכל לבצע שינויים בצורה אוטומטית בשבילך.", + "para": "לוח המחוונים הזה מתוחזק כעת על ידי Home Assistant. זה מתעדכן אוטומטית כאשר ישויות חדשות או רכיבי ממשק משתמש Lovelace זמינים. אם אתה לוקח שליטה, לוח המחוונים הזה כבר לא יעודכן אוטומטית. אתה תמיד יכול ליצור לוח מחוונים חדש בתצורה כדי לשחק איתו.", "para_sure": "האם אתה בטוח שאתה רוצה לקחת שליטה על ממשק המשתמש?", "save": "קח שליטה", "yaml_config": "כדי לעזור לך להתחיל הנה התצורה הנוכחית של לוח מחוונים זה:", @@ -2929,6 +3642,13 @@ "dashboard_label": "לוח בקרה", "header": "בחר תצוגה" }, + "sub-element-editor": { + "types": { + "footer": "עורך כותרת תחתונה", + "header": "עורך כותרת עליונה", + "row": "עורך שורות ישות" + } + }, "suggest_card": { "add": "הוסף לממשק המשתמש של Lovelace", "create_own": "בחר כרטיס אחר", @@ -2936,7 +3656,7 @@ }, "view": { "panel_mode": { - "description": "מציג את הכרטיס הראשון ברוחב המלא; כרטיסים אחרים בתצוגה זו לא יוצגו.", + "description": "פעולה זו מעבדת את הכרטיס הראשון ברוחב מלא. כרטיסים אחרים בתצוגה זו, כמו גם תגים לא יעובדו.", "title": "מצב לוח?", "warning_multiple_cards": "תצוגה זו מכילה יותר מכרטיס אחד, אך בתצוגת פאנל ניתן להציג כרטיס אחד בלבד." } @@ -2944,14 +3664,15 @@ }, "menu": { "close": "סגור", - "configure_ui": "הגדר UI", + "configure_ui": "ערוך לוח בקרה", "exit_edit_mode": "צא ממצב עריכה של ממשק המשתמש", "help": "עזרה", - "reload_resources": "רענן משאבים" + "reload_resources": "רענן משאבים", + "start_conversation": "התחל שיחה" }, - "reload_lovelace": "טען מחדש את Lovelace", + "reload_lovelace": "טען מחדש את ממשק המשתמש", "reload_resources": { - "refresh_body": "אתה צריך לרענן כדי להשלים את הטעינה מחדש, האם אתה רוצה לרענן עכשיו?", + "refresh_body": "עליך לרענן את הדף כדי להשלים את הטעינה מחדש. האם ברצונך לרענן כעת?", "refresh_header": "האם אתה רוצה לרענן?" }, "unused_entities": { @@ -2966,7 +3687,7 @@ "title": "ישויות שאינן בשימוש" }, "views": { - "confirm_delete": "האם אתה בטוח שברצונך למחוק תצוגה זו?", + "confirm_delete": "למחוק תצוגה?", "confirm_delete_existing_cards": "מחיקת תצוגה זו תסיר גם את הכרטיסים", "confirm_delete_existing_cards_text": "האם אתה בטוח שברצונך למחוק את התצוגה '' {name} '' שלך? התצוגה כוללת {number} כרטיסים שיימחקו. לא ניתן לבטל פעולה זו.", "confirm_delete_text": "האם את/ה בטוח שברצונך למחוק את התצוגה \"{name}\"?" @@ -2975,7 +3696,7 @@ "attribute_not_found": "השדה {attribute} אינו זמין ב־{entity}", "entity_non_numeric": "הישות אינה מספרית: {entity}", "entity_not_found": "הישות אינה זמינה: {entity}", - "entity_unavailable": "כרגע {entity} אינו זמין", + "entity_unavailable": "הישות אינה זמינה כרגע: {entity}", "starting": "Home Assistant בעלייה, ייתכן שלא הכל יהיה זמין" } }, @@ -2985,6 +3706,14 @@ "empty": "אין לך הודעות", "playback_title": "הודעת ניגון" }, + "my": { + "component_not_loaded": "הפניה זו אינה נתמכת על ידי מופע ה-Home Assistant שלך. אתה זקוק לשילוב {integration} כדי להשתמש בהפניה מחדש.", + "documentation": "תיעוד", + "error": "אירעה שגיאה לא ידועה", + "faq_link": "שאלות נפוצות על Home Assistant שלי", + "no_supervisor": "הפניה זו אינה נתמכת על ידי התקנת ה-Home Assistant שלך. זה זקוק למערכת ההפעלה Assistant Home או לשיטת ההתקנה בפיקוח Assistant Home. למידע נוסף, עיין ב-{docs_link}.", + "not_supported": "הפניה זו אינה נתמכת על ידי מופע ה-Home Assistant שלך. בדוק ב-{link} את ההפניות הנתמכות ואת הגרסה שהוצגה." + }, "page-authorize": { "abort_intro": "הכניסה בוטלה", "authorizing_client": "אתה עומד לתת גישה ל{clientId} עבור הHome Assistant שלך.", @@ -2994,33 +3723,10 @@ "providers": { "command_line": { "abort": { - "login_expired": "פג תוקף הפעילות באתר, היכנס שוב." + "login_expired": "פג תוקף ההפעלה, נא להתחבר שוב." }, "error": { - "invalid_auth": "שם משתמש או סיסמא לא נכונים", - "invalid_code": "קוד אימות לא חוקי" - }, - "step": { - "init": { - "data": { - "password": "סיסמא", - "username": "שם משתמש" - } - }, - "mfa": { - "data": { - "code": "קוד אימות דו-שלבי" - }, - "description": "פתח את **{mfa_module_name}** במכשיר שלך כדי להציג את קוד האימות הדו שלבי ולאמת את הזהות שלך:" - } - } - }, - "homeassistant": { - "abort": { - "login_expired": "פג תוקף הפעילות באתר, היכנס שוב." - }, - "error": { - "invalid_auth": "שם משתמש או סיסמה לא חוקיים", + "invalid_auth": "שם משתמש או סיסמה אינם חוקיים", "invalid_code": "קוד אימות לא חוקי" }, "step": { @@ -3032,7 +3738,30 @@ }, "mfa": { "data": { - "code": "קוד אימות דו" + "code": "קוד אימות דו שלבי" + }, + "description": "פתח את **{mfa_module_name}** במכשיר שלך כדי להציג את קוד האימות הדו שלבי ולאמת את הזהות שלך:" + } + } + }, + "homeassistant": { + "abort": { + "login_expired": "פג תוקף ההפעלה, נא להתחבר שוב." + }, + "error": { + "invalid_auth": "שם משתמש או סיסמה אינם חוקיים", + "invalid_code": "קוד אימות לא חוקי" + }, + "step": { + "init": { + "data": { + "password": "סיסמה", + "username": "שם משתמש" + } + }, + "mfa": { + "data": { + "code": "קוד אימות דו שלבי" }, "description": "פתח את **{mfa_module_name}** במכשיר שלך כדי להציג את קוד האימות הדו שלבי ולאמת את הזהות שלך:" } @@ -3040,7 +3769,7 @@ }, "legacy_api_password": { "abort": { - "login_expired": "פג תוקף הפעילות, היכנס שוב.", + "login_expired": "פג תוקף ההפעלה, נא להתחבר שוב.", "no_api_password_set": "לא הגדרת את סיסמת הAPI." }, "error": { @@ -3052,11 +3781,11 @@ "data": { "password": "סיסמת הAPI." }, - "description": "הזן את סיסמת הAPI שלך תחת http בקונפיגורציה:" + "description": "אנא הזן את סיסמת ה-API בתצורת ה-HTTP שלך:" }, "mfa": { "data": { - "code": "קוד אימות דו" + "code": "קוד אימות דו שלבי" }, "description": "פתח את **{mfa_module_name}** במכשיר שלך כדי להציג את קוד האימות הדו שלבי ולאמת את הזהות שלך:" } @@ -3132,7 +3861,7 @@ "page-onboarding": { "analytics": { "finish": "הבא", - "intro": "שתף ניתוחים אנליטים מהמקרה שלך. נתונים אלו יהיו זמינים באופן ציבורי בכתובת {link}" + "intro": "שתף ניתוח מהמופע שלך. נתונים אלה יהיו זמינים לציבור בכתובת {link}" }, "core-config": { "button_detect": "לזהות", @@ -3140,6 +3869,7 @@ "intro": "שלום {name} , ברוך הבא ל- Home Assistant. איך היית רוצה את שם הבית שלך?", "intro_location": "אנחנו רוצים לדעת איפה אתה גר. מידע זה יעזור עם הצגת מידע והגדרת אוטומציה מבוססת שמש. נתונים אלה לעולם אינם משותפים מחוץ לרשת שלך.", "intro_location_detect": "אנו יכולים לעזור לך למלא מידע זה על ידי ביצוע בקשה חד פעמית לשירות חיצוני.", + "location_name": "שם ההתקנה של Home Assistant שלך", "location_name_default": "בית" }, "finish": "סיום", @@ -3174,7 +3904,7 @@ }, "profile": { "advanced_mode": { - "description": "Home Assistant מסתיר תכונות ואפשרויות מתקדמות כברירת מחדל. ביכולתך לחשוף אותן ע\"י בחירת תיבת הסימון זו. הגדרה זו היא עבור המשתמש הנוכחי ולא תשפיע על משתמשים אחרים ב Home Assistant.", + "description": "ביטול נעילה של תכונות מתקדמות.", "link_promo": "למד עוד", "title": "מצב מתקדם" }, @@ -3190,12 +3920,18 @@ "success": "הסיסמה שונתה בהצלחה" }, "current_user": "אתה מחובר כעת כ- {fullName} .", + "customize_sidebar": { + "button": "ערוך", + "description": "באפשרותך גם ללחוץ לחיצה ארוכה על הכותרת של הסרגל הצידי כדי להפעיל מצב עריכה.", + "header": "שינוי הסדר והסתרת פריטים מהסרגל הצידי" + }, "dashboard": { "description": "בחר לוח בקרה ברירת מחדל עבור התקן זה.", "dropdown_label": "לוח בקרה", "header": "לוח בקרה" }, "enable_shortcuts": { + "description": "הפוך קיצורי מקשים לזמינים או ללא זמינים לביצוע פעולות שונות בממשק המשתמש.", "header": "קיצורי מקשים" }, "force_narrow": { @@ -3215,13 +3951,15 @@ "confirm_delete": "האם אתה בטוח שברצונך למחוק את אסימון הגישה עבור {name} ?", "create": "צור אסימון", "create_failed": "יצירת אסימון הגישה נכשלה.", + "created": "נוצר {date}", "delete_failed": "מחיקת אסימון הגישה נכשלה.", "description": "צור אסימוני גישה ארוכי טווח כדי לאפשר לסקריפטים שלך לקיים אינטראקציה עם Home Assistant.\nאסימונים אלו פועלים כיום:", "empty_state": "אין לך עדיין אסימוני גישה ארוכים.", "header": "אסימוני גישה ארוכי חיים", "learn_auth_requests": "למד כיצד לבצע בקשות מאומתות.", + "name": "שם", "prompt_copy_token": "העתק את אסימון הגישה שלך. הוא לא יוצג שוב.", - "prompt_name": "שֵׁם?" + "prompt_name": "תן שם לאסימון" }, "mfa_setup": { "close": "סגור", @@ -3263,12 +4001,12 @@ }, "refresh_tokens": { "confirm_delete": "האם אתה בטוח שברצונך למחוק את אסימון הרענון עבור {name}", - "created_at": "נוצר בתאריך {date}", + "created_at": "נוצר {date}", "current_token_tooltip": "לא ניתן למחוק את אסימון הרענון הנוכחי", "delete_failed": "מחיקת אסימון הרענון נכשלה.", "description": "כל אסימון רענון מייצג הפעלת התחברות. אסימוני רענון יוסרו באופן אוטומטי כאשר תלחץ על יציאה. אסימוני הרענון הבאים פעילים כעת עבור חשבונך.", "header": "רענן אסימונים", - "last_used": "נעשה שימוש לאחרונה ב {date} מ{location}", + "last_used": "נעשה שימוש לאחרונה בתאריך {date} מהמיקום {location}", "not_used": "לא היה בשימוש", "token_title": "אסימון רענון עבור {clientId}" }, @@ -3290,6 +4028,17 @@ "primary_color": "צבע ראשי", "reset": "איפוס" }, + "time_format": { + "description": "בחר כיצד לעצב שעות.", + "dropdown_label": "תבנית שעה", + "formats": { + "12": "12 שעות (AM/PM)", + "24": "24 שעות", + "language": "אוטומטי (השתמש בהגדרות השפה)", + "system": "השתמש באזור המערכת" + }, + "header": "תבנית שעה" + }, "vibrate": { "description": "הפעל או בטל את הרטט במכשיר זה בעת שליטה בהתקנים.", "header": "רטט" @@ -3300,6 +4049,7 @@ } }, "sidebar": { + "done": "בוצע", "external_app_configuration": "הגדרות היישום", "sidebar_toggle": "שנה מצב סרגל צידי" } diff --git a/translations/frontend/it.json b/translations/frontend/it.json index 96779a9caf..ab08f71ffb 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -413,7 +413,7 @@ "select_type": "Seleziona cosa ripristinare", "selected": "{number} selezionato/i", "type": "Tipo di istantanea", - "upload_snapshot": "Invia istantanea" + "upload_snapshot": "Aggiungi istantanea" }, "store": { "missing_addons": "Componenti aggiuntivi mancanti? Abilita la modalità avanzata nella pagina del tuo profilo utente", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 37753f8016..94ff9453cf 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -402,10 +402,10 @@ "ssl": "SSL" }, "folders": "Папки", - "full_snapshot": "Полный", + "full_snapshot": "Все файлы", "name": "Название", "no_snapshots": "Не найдено ни одного снимка", - "partial_snapshot": "Выборочный", + "partial_snapshot": "Выбрать из списка", "password": "Пароль", "password_protected": "защищено паролем", "password_protection": "Защита паролем", From 1e6e99e3c7c0fc8c3a4ca5389d7f484c9a27d18e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 7 Jun 2021 00:49:13 +0000 Subject: [PATCH 07/73] Translation update --- translations/frontend/cs.json | 4 ++-- translations/frontend/he.json | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index 2197c06ff2..c22492e14b 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -1169,7 +1169,7 @@ }, "types": { "navigation": "Navigovat", - "reload": "Znovu načíst", + "reload": "Nově načíst", "server_control": "Server" } }, @@ -3101,7 +3101,7 @@ "heal_node": "Uzdravit uzel", "node_info": "Informace o uzlu", "print_node": "Otisk uzlu", - "refresh_entity": "Znovu načíst Entitu", + "refresh_entity": "Nově načíst Entitu", "refresh_node": "Obnovit uzel", "remove_failed_node": "Odebrat selhaný uzel", "remove_node": "Odebrat uzel", diff --git a/translations/frontend/he.json b/translations/frontend/he.json index a50118c73d..a71c787e63 100644 --- a/translations/frontend/he.json +++ b/translations/frontend/he.json @@ -1687,7 +1687,7 @@ "file_name": "נתיב שרטוט", "header": "יבוא שרטוט", "import_btn": "תצוגה מקדימה של שרטוט", - "import_header": "שרטוט \" {name} \"", + "import_header": "שרטוט \"{name}\"", "import_introduction_link": "באפשרותך לייבא שרטוטים של משתמשים אחרים מ- Github ומ {community_link}. הזן את כתובת ה- URL של השרטוט.", "importing": "טוען שרטוט ...", "raw_blueprint": "תוכן שרטוט", @@ -1843,7 +1843,7 @@ }, "forgot_password": { "check_your_email": "בדוק את הדואר האלקטרוני שלך לקבלת הוראות כיצד לאפס את סיסמתך.", - "email": "כתובת דוא\"ל", + "email": "דוא\"ל", "email_error_msg": "דואר אלקטרוני לא חוקי", "instructions": "הזן את כתובת הדוא\"ל שלך ואנו נשלח לך קישור כדי לאפס את הסיסמה שלך.", "send_reset_email": "שלח אימייל לאיפוס", @@ -1935,7 +1935,7 @@ "title": "אבחון" }, "statistics": { - "description": "סה\"כ ישויות בשימוש, משתמשים ואלמנטים אחרים.", + "description": "סך הכל ישויות בשימוש, משתמשים ואלמנטים אחרים.", "title": "סטטיסטיקות שימוש" }, "usage_supervisor": { @@ -2775,7 +2775,7 @@ "admin": "מנהל", "caption": "הצג משתמש", "change_password": "שינוי סיסמה", - "confirm_user_deletion": "האם הינך בטוח/ה שברצונך למחוק את {name} ?", + "confirm_user_deletion": "האם בוודאות ברצונך למחוק את {name}?", "deactivate_user": "בטל את המשתמש", "delete_user": "מחיקת משתמש", "group": "קבוצה", @@ -2784,7 +2784,7 @@ "new_password": "סיסמה חדשה", "owner": "בעלים", "password_changed": "הסיסמה שונתה בהצלחה", - "system_generated": "נוצר ע\"י המערכת", + "system_generated": "המערכת נוצרה", "system_generated_users_not_editable": "לא ניתן לעדכן משתמשים שנוצרו על ידי המערכת.", "system_generated_users_not_removable": "לא ניתן להסיר משתמשים שנוצרו על ידי המערכת.", "unnamed_user": "משתמש ללא שם", @@ -3690,7 +3690,7 @@ "confirm_delete": "למחוק תצוגה?", "confirm_delete_existing_cards": "מחיקת תצוגה זו תסיר גם את הכרטיסים", "confirm_delete_existing_cards_text": "האם אתה בטוח שברצונך למחוק את התצוגה '' {name} '' שלך? התצוגה כוללת {number} כרטיסים שיימחקו. לא ניתן לבטל פעולה זו.", - "confirm_delete_text": "האם את/ה בטוח שברצונך למחוק את התצוגה \"{name}\"?" + "confirm_delete_text": "האם בוודאות ברצונך למחוק את התצוגה \"{name}\"?" }, "warning": { "attribute_not_found": "השדה {attribute} אינו זמין ב־{entity}", @@ -3810,7 +3810,7 @@ "working": "אנא המתן" }, "initializing": "מאתחל", - "logging_in_to_with": "כניסה ל- ** {locationName} ** באמצעות ** {authProviderName} **.", + "logging_in_to_with": "כניסה אל **{locationName}** באמצעות **{authProviderName}**.", "logging_in_with": "מתחבר עם **{authProviderName}**.", "pick_auth_provider": "או התחבר עם" }, @@ -3835,7 +3835,7 @@ "information": "מידע", "lights": "אורות", "morning_commute": "נסיעת בוקר", - "total_tv_time": "סה\"כ זמן טלוויזיה", + "total_tv_time": "סך הכל זמן טלוויזיה", "turn_tv_off": "כבה את הטלוויזיה", "volume": "ווליום" }, @@ -3919,7 +3919,7 @@ "submit": "שלח", "success": "הסיסמה שונתה בהצלחה" }, - "current_user": "אתה מחובר כעת כ- {fullName} .", + "current_user": "אתה מחובר כעת כ-{fullName}.", "customize_sidebar": { "button": "ערוך", "description": "באפשרותך גם ללחוץ לחיצה ארוכה על הכותרת של הסרגל הצידי כדי להפעיל מצב עריכה.", From 342020b4200b08d322edce8b3162f5fbea47e0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 7 Jun 2021 10:15:43 +0200 Subject: [PATCH 08/73] Fix downloads on mobile (#9375) --- .../src/dialogs/snapshot/dialog-hassio-snapshot.ts | 12 ++++++------ src/components/ha-gauge.ts | 6 +++--- .../zwave_js/zwave_js-config-dashboard.ts | 8 ++------ src/resources/safari-14-attachshadow-patch.ts | 1 + src/util/file_download.ts | 14 ++++++++++++++ src/util/is_safari.ts | 0 6 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 src/util/file_download.ts create mode 100644 src/util/is_safari.ts diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts index e934bced92..e7afcdbad1 100755 --- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts +++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts @@ -22,6 +22,7 @@ import { import { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; import { HomeAssistant } from "../../../../src/types"; +import { fileDownload } from "../../../../src/util/file_download"; import "../../components/supervisor-snapshot-content"; import type { SupervisorSnapshotContent } from "../../components/supervisor-snapshot-content"; import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot"; @@ -288,12 +289,11 @@ class HassioSnapshotDialog } } - const a = document.createElement("a"); - a.href = signedPath.path; - a.download = `home_assistant_snapshot_${slugify(this._computeName)}.tar`; - this.shadowRoot!.appendChild(a); - a.click(); - this.shadowRoot!.removeChild(a); + fileDownload( + this, + signedPath.path, + `home_assistant_snapshot_${slugify(this._computeName)}.tar` + ); } private get _computeName() { diff --git a/src/components/ha-gauge.ts b/src/components/ha-gauge.ts index 26b4ae52aa..2f0e71cabc 100644 --- a/src/components/ha-gauge.ts +++ b/src/components/ha-gauge.ts @@ -7,14 +7,14 @@ import { afterNextRender } from "../common/util/render-status"; import { FrontendLocaleData } from "../data/translation"; import { getValueInPercentage, normalize } from "../util/calculate"; +// Workaround for https://github.com/home-assistant/frontend/issues/6467 +const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + const getAngle = (value: number, min: number, max: number) => { const percentage = getValueInPercentage(normalize(value, min, max), min, max); return (percentage * 180) / 100; }; -// Workaround for https://github.com/home-assistant/frontend/issues/6467 -const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - @customElement("ha-gauge") export class Gauge extends LitElement { @property({ type: Number }) public min = 0; diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts index 6a9580cb7f..44c66b7ba4 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts @@ -24,6 +24,7 @@ import { import "../../../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; +import { fileDownload } from "../../../../../util/file_download"; import "../../../ha-config-section"; import { showZWaveJSAddNodeDialog } from "./show-dialog-zwave_js-add-node"; import { showZWaveJSRemoveNodeDialog } from "./show-dialog-zwave_js-remove-node"; @@ -312,12 +313,7 @@ class ZWaveJSConfigDashboard extends LitElement { return; } - const a = document.createElement("a"); - a.href = signedPath.path; - a.download = `zwave_js_dump.jsonl`; - this.shadowRoot!.appendChild(a); - a.click(); - this.shadowRoot!.removeChild(a); + fileDownload(this, signedPath.path, `zwave_js_dump.jsonl`); } static get styles(): CSSResultGroup { diff --git a/src/resources/safari-14-attachshadow-patch.ts b/src/resources/safari-14-attachshadow-patch.ts index 88954ab4d2..93a4a5b78a 100644 --- a/src/resources/safari-14-attachshadow-patch.ts +++ b/src/resources/safari-14-attachshadow-patch.ts @@ -2,6 +2,7 @@ const isSafari14 = /^((?!chrome|android).)*version\/14\.0\s.*safari/i.test( navigator.userAgent ); + if (isSafari14) { const origAttachShadow = window.Element.prototype.attachShadow; window.Element.prototype.attachShadow = function (init) { diff --git a/src/util/file_download.ts b/src/util/file_download.ts new file mode 100644 index 0000000000..6f7eed86dd --- /dev/null +++ b/src/util/file_download.ts @@ -0,0 +1,14 @@ +export const fileDownload = ( + element: HTMLElement, + href: string, + filename: string +): void => { + const a = document.createElement("a"); + a.target = "_blank"; + a.href = href; + a.download = filename; + + element.shadowRoot!.appendChild(a); + a.dispatchEvent(new MouseEvent("click")); + element.shadowRoot!.removeChild(a); +}; diff --git a/src/util/is_safari.ts b/src/util/is_safari.ts new file mode 100644 index 0000000000..e69de29bb2 From c68b76e2da58839a056766943e79af5d2e4b70ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 7 Jun 2021 10:16:33 +0200 Subject: [PATCH 09/73] Add hardware dialog (#9348) Co-authored-by: Bram Kragten --- .../hardware/dialog-hassio-hardware.ts | 194 ++++++++++++++++++ .../hardware/show-dialog-hassio-hardware.ts | 19 ++ hassio/src/system/hassio-host-info.ts | 14 +- src/components/ha-expansion-panel.ts | 17 +- src/data/hassio/hardware.ts | 15 +- src/translations/en.json | 8 + 6 files changed, 253 insertions(+), 14 deletions(-) create mode 100755 hassio/src/dialogs/hardware/dialog-hassio-hardware.ts create mode 100644 hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts diff --git a/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts b/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts new file mode 100755 index 0000000000..f7ccbd970b --- /dev/null +++ b/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts @@ -0,0 +1,194 @@ +import { mdiClose } from "@mdi/js"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import "../../../../src/common/search/search-input"; +import { compare } from "../../../../src/common/string/compare"; +import "../../../../src/components/ha-dialog"; +import "../../../../src/components/ha-expansion-panel"; +import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware"; +import { dump } from "../../../../src/resources/js-yaml-dump"; +import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; +import { HomeAssistant } from "../../../../src/types"; +import { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware"; + +const _filterDevices = memoizeOne( + (showAdvanced: boolean, hardware: HassioHardwareInfo, filter: string) => + hardware.devices + .filter( + (device) => + (showAdvanced || + ["tty", "gpio", "input"].includes(device.subsystem)) && + (device.by_id?.toLowerCase().includes(filter) || + device.name.toLowerCase().includes(filter) || + device.dev_path.toLocaleLowerCase().includes(filter) || + JSON.stringify(device.attributes) + .toLocaleLowerCase() + .includes(filter)) + ) + .sort((a, b) => compare(a.name, b.name)) +); + +@customElement("dialog-hassio-hardware") +class HassioHardwareDialog extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _dialogParams?: HassioHardwareDialogParams; + + @state() private _filter?: string; + + public showDialog(params: HassioHardwareDialogParams) { + this._dialogParams = params; + } + + public closeDialog() { + this._dialogParams = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render(): TemplateResult { + if (!this._dialogParams) { + return html``; + } + + const devices = _filterDevices( + this.hass.userData?.showAdvanced || false, + this._dialogParams.hardware, + (this._filter || "").toLowerCase() + ); + + return html` + +
+

+ ${this._dialogParams.supervisor.localize("dialog.hardware.title")} +

+ + + + + +
+ + ${devices.map( + (device) => + html` +
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.subsystem" + )}: + + ${device.subsystem} +
+
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.device_path" + )}: + + ${device.dev_path} +
+ ${device.by_id + ? html`
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.id" + )}: + + ${device.by_id} +
` + : ""} +
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.attributes" + )}: + +
${dump(device.attributes, { indent: 2 })}
+
+
` + )} +
+ `; + } + + private _handleSearchChange(ev: CustomEvent) { + this._filter = ev.detail.value; + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + haStyleDialog, + css` + mwc-icon-button { + position: absolute; + right: 16px; + top: 10px; + text-decoration: none; + color: var(--primary-text-color); + } + h2 { + margin: 18px 42px 0 18px; + color: var(--primary-text-color); + } + + ha-expansion-panel { + margin: 4px 0; + } + pre, + code { + background-color: var(--markdown-code-background-color, none); + border-radius: 3px; + } + pre { + padding: 16px; + overflow: auto; + line-height: 1.45; + font-family: var(--code-font-family, monospace); + } + code { + font-size: 85%; + padding: 0.2em 0.4em; + } + search-input { + margin: 0 16px; + display: block; + } + .device-property { + display: flex; + justify-content: space-between; + } + .attributes { + margin-top: 12px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-hassio-hardware": HassioHardwareDialog; + } +} diff --git a/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts b/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts new file mode 100644 index 0000000000..4ca15734e8 --- /dev/null +++ b/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts @@ -0,0 +1,19 @@ +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware"; +import { Supervisor } from "../../../../src/data/supervisor/supervisor"; + +export interface HassioHardwareDialogParams { + supervisor: Supervisor; + hardware: HassioHardwareInfo; +} + +export const showHassioHardwareDialog = ( + element: HTMLElement, + dialogParams: HassioHardwareDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-hassio-hardware", + dialogImport: () => import("./dialog-hassio-hardware"), + dialogParams, + }); +}; diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts index cde6becf58..1381bf291a 100644 --- a/hassio/src/system/hassio-host-info.ts +++ b/hassio/src/system/hassio-host-info.ts @@ -2,7 +2,6 @@ import "@material/mwc-button"; import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical } from "@mdi/js"; -import { dump } from "js-yaml"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; @@ -41,8 +40,8 @@ import { roundWithOneDecimal, } from "../../../src/util/calculate"; import "../components/supervisor-metric"; -import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio-markdown"; import { showNetworkDialog } from "../dialogs/network/show-dialog-network"; +import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware"; import { hassioStyle } from "../resources/hassio-style"; @customElement("hassio-host-info") @@ -229,20 +228,19 @@ class HassioHostInfo extends LitElement { } private async _showHardware(): Promise { + let hardware; try { - const content = await fetchHassioHardwareInfo(this.hass); - showHassioMarkdownDialog(this, { - title: this.supervisor.localize("system.host.hardware"), - content: `
${dump(content, { indent: 2 })}
`, - }); + hardware = await fetchHassioHardwareInfo(this.hass); } catch (err) { - showAlertDialog(this, { + await showAlertDialog(this, { title: this.supervisor.localize( "system.host.failed_to_get_hardware_list" ), text: extractApiErrorMessage(err), }); + return; } + showHassioHardwareDialog(this, { supervisor: this.supervisor, hardware }); } private async _hostReboot(ev: CustomEvent): Promise { diff --git a/src/components/ha-expansion-panel.ts b/src/components/ha-expansion-panel.ts index f553e3ffc6..705b5a6b81 100644 --- a/src/components/ha-expansion-panel.ts +++ b/src/components/ha-expansion-panel.ts @@ -14,12 +14,17 @@ class HaExpansionPanel extends LitElement { @property() header?: string; + @property() secondary?: string; + @query(".container") private _container!: HTMLDivElement; protected render(): TemplateResult { return html`
- ${this.header} + + ${this.header} + ${this.secondary} + ; + by_id: null | string; + dev_path: string; + name: string; + subsystem: string; + sysfs: string; +} + export interface HassioHardwareInfo { - serial: string[]; - input: string[]; - disk: string[]; - gpio: string[]; - audio: Record; + devices: HardwareDevice[]; } export const fetchHassioHardwareAudio = async ( diff --git a/src/translations/en.json b/src/translations/en.json index 22cb216393..a3b898bd77 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3980,6 +3980,14 @@ "create_snapshot": "Create a snapshot of {name} before updating", "updating": "Updating {name} to version {version}", "snapshotting": "Creating snapshot of {name}" + }, + "hardware": { + "title": "Hardware", + "search": "Search hardware", + "subsystem": "Subsystem", + "id": "ID", + "attributes": "Attributes", + "device_path": "Device path" } } } From ce419fae7bd6040975b485df6ddc60ecd5575b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 7 Jun 2021 10:45:20 +0200 Subject: [PATCH 10/73] Add password confirmation to snapshot creation (#9349) * Add password confirmation to snapshot creation * Remove confirm_password before sending * change layout * style changes * Adjust styling Co-authored-by: Bram Kragten --- .../components/supervisor-formfield-label.ts | 1 - .../components/supervisor-snapshot-content.ts | 61 ++++++++++++------- .../snapshot/dialog-hassio-create-snapshot.ts | 17 ++++-- src/data/hassio/snapshot.ts | 1 + src/translations/en.json | 2 + 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/hassio/src/components/supervisor-formfield-label.ts b/hassio/src/components/supervisor-formfield-label.ts index e173c0c44c..9220d20946 100644 --- a/hassio/src/components/supervisor-formfield-label.ts +++ b/hassio/src/components/supervisor-formfield-label.ts @@ -29,7 +29,6 @@ class SupervisorFormfieldLabel extends LitElement { static get styles(): CSSResultGroup { return css` :host { - cursor: pointer; display: flex; align-items: center; } diff --git a/hassio/src/components/supervisor-snapshot-content.ts b/hassio/src/components/supervisor-snapshot-content.ts index 2d95864d33..c585c61ba6 100644 --- a/hassio/src/components/supervisor-snapshot-content.ts +++ b/hassio/src/components/supervisor-snapshot-content.ts @@ -85,6 +85,8 @@ export class SupervisorSnapshotContent extends LitElement { @property() public snapshotPassword = ""; + @property() public confirmSnapshotPassword = ""; + public willUpdate(changedProps) { super.willUpdate(changedProps); if (!this.hasUpdated) { @@ -160,9 +162,9 @@ export class SupervisorSnapshotContent extends LitElement {
` : ""} - ${this.snapshot && this.snapshotType === "partial" - ? html` - ${this.snapshot.homeassistant + ${this.snapshotType === "partial" + ? html`
+ ${this.snapshot && this.snapshot.homeassistant ? html` ` : ""} - ` - : ""} - ${this.snapshotType === "partial" - ? html` ${foldersSection?.templates.length ? html` ${addonsSection.templates}
` : ""} - ` + ` : ""} ${!this.snapshot ? html` - ` + + ` : ""} ${this.snapshotHasPassword ? html` @@ -249,6 +248,18 @@ export class SupervisorSnapshotContent extends LitElement { @value-changed=${this._handleTextValueChanged} > + ${!this.snapshot + ? html` + ` + : ""} ` : ""} `; @@ -256,35 +267,38 @@ export class SupervisorSnapshotContent extends LitElement { static get styles(): CSSResultGroup { return css` - ha-checkbox { - --mdc-checkbox-touch-target-size: 16px; + .partial-picker ha-formfield { display: block; - margin: 4px 12px 8px 0; } - ha-formfield { - display: contents; + .partial-picker ha-checkbox { + --mdc-checkbox-touch-target-size: 32px; + } + .partial-picker { + display: block; + margin: 0px -6px; + padding-right: 6px; + padding-bottom: 8px; + border-bottom: 1px solid var(--divider-color); } supervisor-formfield-label { display: inline-flex; align-items: center; } - paper-input[type="password"] { - display: block; - margin: 4px 0 4px 16px; - } .details { color: var(--secondary-text-color); } .section-content { display: flex; flex-direction: column; - margin-left: 16px; + margin-left: 30px; } - .security { - margin-top: 16px; + ha-formfield.password { + display: block; + margin: 0 -14px -16px; } .snapshot-types { display: flex; + margin-left: -13px; } .sub-header { margin-top: 8px; @@ -303,6 +317,9 @@ export class SupervisorSnapshotContent extends LitElement { if (this.snapshotHasPassword) { data.password = this.snapshotPassword; + if (!this.snapshot) { + data.confirm_password = this.confirmSnapshotPassword; + } } if (this.snapshotType === "full") { diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts index 395640401f..dbb7c503c7 100755 --- a/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts +++ b/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts @@ -95,16 +95,25 @@ class HassioCreateSnapshotDialog extends LitElement { this._creatingSnapshot = true; this._error = ""; - if ( - this._snapshotContent.snapshotHasPassword && - !this._snapshotContent.snapshotPassword.length - ) { + if (snapshotDetails.password && !snapshotDetails.password.length) { this._error = this._dialogParams!.supervisor.localize( "snapshot.enter_password" ); this._creatingSnapshot = false; return; } + if ( + snapshotDetails.password && + snapshotDetails.password !== snapshotDetails.confirm_password + ) { + this._error = this._dialogParams!.supervisor.localize( + "snapshot.passwords_not_matching" + ); + this._creatingSnapshot = false; + return; + } + + delete snapshotDetails.confirm_password; try { if (this._snapshotContent.snapshotType === "full") { diff --git a/src/data/hassio/snapshot.ts b/src/data/hassio/snapshot.ts index b2f1c36c25..35220e80b6 100644 --- a/src/data/hassio/snapshot.ts +++ b/src/data/hassio/snapshot.ts @@ -41,6 +41,7 @@ export interface HassioSnapshotDetail extends HassioSnapshot { export interface HassioFullSnapshotCreateParams { name: string; password?: string; + confirm_password?: string; } export interface HassioPartialSnapshotCreateParams extends HassioFullSnapshotCreateParams { diff --git a/src/translations/en.json b/src/translations/en.json index a3b898bd77..0a9ab32f6d 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3924,9 +3924,11 @@ "addons": "Add-ons", "folders": "Folders", "password": "Snapshot password", + "confirm_password": "Confirm Snapshot password", "password_protection": "Password protection", "password_protected": "password protected", "enter_password": "Please enter a password.", + "passwords_not_matching": "The passwords does not match", "folder": { "homeassistant": "Home Assistant configuration", "ssl": "SSL", From 82a4806e01f9756a81a0117a1f7a05b126edef11 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 7 Jun 2021 10:45:57 +0200 Subject: [PATCH 11/73] Change line logic --- hassio/src/components/supervisor-snapshot-content.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hassio/src/components/supervisor-snapshot-content.ts b/hassio/src/components/supervisor-snapshot-content.ts index c585c61ba6..d1095179ca 100644 --- a/hassio/src/components/supervisor-snapshot-content.ts +++ b/hassio/src/components/supervisor-snapshot-content.ts @@ -226,6 +226,10 @@ export class SupervisorSnapshotContent extends LitElement { : ""} ` : ""} + ${this.snapshotType === "partial" && + (!this.snapshot || this.snapshotHasPassword) + ? html`
` + : ""} ${!this.snapshot ? html` Date: Tue, 8 Jun 2021 00:49:18 +0000 Subject: [PATCH 12/73] Translation update --- translations/frontend/bg.json | 14 ++++++++++++-- translations/frontend/ca.json | 10 ++++++++++ translations/frontend/cs.json | 12 +++++++++++- translations/frontend/en.json | 10 ++++++++++ translations/frontend/es.json | 10 ++++++++++ translations/frontend/et.json | 10 ++++++++++ translations/frontend/he.json | 10 ++++++++++ translations/frontend/ko.json | 10 ++++++++++ translations/frontend/nb.json | 8 ++++++++ translations/frontend/ru.json | 10 ++++++++++ translations/frontend/zh-Hant.json | 10 ++++++++++ 11 files changed, 111 insertions(+), 3 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index 55c754025b..cf1bc4e394 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -285,6 +285,12 @@ "no_addons": "Все още нямате инсталирани добавки. Насочете се към хранилището за добавки, за да започнете!" }, "dialog": { + "hardware": { + "attributes": "Атрибути", + "id": "ID", + "search": "Търсене на хардуер", + "title": "Хардуер" + }, "network": { "connected_to": "Свързан с {ssid}", "dhcp": "DHCP", @@ -346,6 +352,7 @@ "snapshot": { "addons": "Добавки", "available_snapshots": "Налични снапшоти", + "confirm_password": "Потвърдете паролата за снапшота", "could_not_create": "Не можа да се създаде снапшот", "create": "Създаване", "create_blocked_not_running": "Създаването на снапшот в момента не е възможно, тъй като системата е в състояние {state}.", @@ -353,7 +360,7 @@ "created": "Създаден", "delete_selected": "Изтриване на избраните снапшоти", "delete_snapshot_confirm": "Изтрий", - "delete_snapshot_title": "Изтриване на снапшот", + "delete_snapshot_title": "Изтриване на снапшота", "description": "Снапшотите ви позволяват лесно да архивирате и възстановявате всички данни от вашия екземпляр на Home Assistant.", "enter_password": "Моля, въведете парола.", "folder": { @@ -371,7 +378,9 @@ "password": "Парола", "password_protected": "защитен с парола", "password_protection": "Защита с парола", + "passwords_not_matching": "Паролите не съвпадат", "security": "Сигурност", + "select_type": "Изберете какво да възстановите", "selected": "{number} избрани", "type": "Тип", "upload_snapshot": "Качване на снапшот" @@ -1642,7 +1651,8 @@ "link_learn_how_it_works": "Научете как работи", "not_connected": "Не е свързан", "remote_enabled": { - "caption": "Автоматично свързване" + "caption": "Автоматично свързване", + "description": "Активирайте тази опция, за да сте сигурни, че вашият Home Assistant е винаги достъпен от разстояние." }, "title": "Дистанционен контрол" }, diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index 09b15bcbb9..f00ce7e49e 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -318,6 +318,14 @@ "no_addons": "Encara no tens cap complement instal·lat. Vés al directori de complements per començar!" }, "dialog": { + "hardware": { + "attributes": "Atributs", + "device_path": "Ruta del dispositiu", + "id": "ID", + "search": "Cercar maquinari", + "subsystem": "Subsistema", + "title": "Maquinari" + }, "network": { "connected_to": "Connectat a {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Complements", "available_snapshots": "Instantànies disponibles", + "confirm_password": "Confirma la contrasenya de la instantània", "could_not_create": "No s'ha pogut crear la instantània", "create": "Crea", "create_blocked_not_running": "Ara mateix no és possible crear una instantània perquè el sistema es troba en estat {state}.", @@ -409,6 +418,7 @@ "password": "Contrasenya de la instantània", "password_protected": "protegit amb contrasenya", "password_protection": "Protecció amb contrasenya", + "passwords_not_matching": "Les contrasenyes no coincideixen", "security": "Seguretat", "select_type": "Selecciona què vols restaurar", "selected": "{number} seleccionada/es", diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index c22492e14b..c117b7aefb 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -318,6 +318,14 @@ "no_addons": "Zatím nemáte nainstalované žádné doplňky. Chcete-li začít, přejděte do obchodu s doplňky." }, "dialog": { + "hardware": { + "attributes": "Atributy", + "device_path": "Cesta k zařízení", + "id": "ID", + "search": "Hledat hardware", + "subsystem": "Subsystém", + "title": "Hardware" + }, "network": { "connected_to": "Připojeno k {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Doplňky", "available_snapshots": "Dostupné zálohy", + "confirm_password": "Potvrďte heslo zálohy", "could_not_create": "Nelze vytvořit zálohu", "create": "Vytvořit", "create_blocked_not_running": "Vytvoření zálohy není momentálně možné, protože systém je ve \"{state}\".", @@ -409,6 +418,7 @@ "password": "Heslo zálohy", "password_protected": "chráněno heslem", "password_protection": "Ochrana heslem", + "passwords_not_matching": "Hesla se neshodují", "security": "Zabezpečení", "select_type": "Vyberte, co chcete obnovit", "selected": "{number} vybraných", @@ -3544,7 +3554,7 @@ "options": "Více možností", "pick_card": "Kterou kartu chcete přidat?", "pick_card_view_title": "Kterou kartu byste chtěli přidat do svého {name} pohledu?", - "search_cards": "Vyhledat karty", + "search_cards": "Hledat karty", "show_code_editor": "Zobrazit editor kódu", "show_visual_editor": "Zobrazit vizuální editor", "toggle_editor": "Přepnout Editor", diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 00c78cbeeb..f18b30e269 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -318,6 +318,14 @@ "no_addons": "You don't have any add-ons installed yet. Head over to the add-on store to get started!" }, "dialog": { + "hardware": { + "attributes": "Attributes", + "device_path": "Device path", + "id": "ID", + "search": "Search hardware", + "subsystem": "Subsystem", + "title": "Hardware" + }, "network": { "connected_to": "Connected to {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Add-ons", "available_snapshots": "Available Snapshots", + "confirm_password": "Confirm Snapshot password", "could_not_create": "Could not create snapshot", "create": "Create", "create_blocked_not_running": "Creating a snapshot is not possible right now because the system is in {state} state.", @@ -409,6 +418,7 @@ "password": "Snapshot password", "password_protected": "password protected", "password_protection": "Password protection", + "passwords_not_matching": "The passwords does not match", "security": "Security", "select_type": "Select what to restore", "selected": "{number} selected", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index 9b28f1c447..c161b2a757 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -318,6 +318,14 @@ "no_addons": "Aún no tienes ningún complemento instalado. ¡Dirígete a la tienda de complementos para comenzar!" }, "dialog": { + "hardware": { + "attributes": "Atributos", + "device_path": "Ruta del dispositivo", + "id": "ID", + "search": "Buscar hardware", + "subsystem": "Subsistema", + "title": "Hardware" + }, "network": { "connected_to": "Conectado a {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Complementos", "available_snapshots": "Instantáneas disponibles", + "confirm_password": "Confirma la contraseña de la instantánea", "could_not_create": "No se pudo crear la instantánea", "create": "Crear", "create_blocked_not_running": "No es posible crear una instantánea en este momento porque el sistema está en el estado {state}.", @@ -409,6 +418,7 @@ "password": "Contraseña de la instantánea", "password_protected": "protegida por contraseña", "password_protection": "Protección con contraseña", + "passwords_not_matching": "Las contraseñas no coinciden", "security": "Seguridad", "select_type": "Selecciona qué restaurar", "selected": "{number} {number, plural,\n one {seleccionada}\n other {seleccionadas}\n}", diff --git a/translations/frontend/et.json b/translations/frontend/et.json index 18ce2c5330..129e23b248 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -318,6 +318,14 @@ "no_addons": "Ühtegi lisandmoodulit pole veel paigaldatud. Alustamiseks mine lisandmoodulite hoidlasse!" }, "dialog": { + "hardware": { + "attributes": "Atribuudid", + "device_path": "Seadme asukoht", + "id": "ID", + "search": "Otsi riistvara", + "subsystem": "Alamsüsteem", + "title": "Riistvara" + }, "network": { "connected_to": "Ühendatud pääsupunktiga {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Lisandmoodulid", "available_snapshots": "Saadaolevad hetktõmmised", + "confirm_password": "Hetktõmmise parooli kinnitamine", "could_not_create": "Hetktõmmise loomine nurjus", "create": "Loo", "create_blocked_not_running": "Hetktõmmise loomine pole praegu võimalik kuna süsteem on olekus {state}.", @@ -409,6 +418,7 @@ "password": "Hetktõmmise salasõna", "password_protected": "salasõnaha kaitstud", "password_protection": "Salasõnaga kaitstud", + "passwords_not_matching": "Salasõnad ei ühti", "security": "Turvalisus", "select_type": "Vali mida taastada", "selected": "{number} valitud", diff --git a/translations/frontend/he.json b/translations/frontend/he.json index a71c787e63..e6bbeb6be8 100644 --- a/translations/frontend/he.json +++ b/translations/frontend/he.json @@ -318,6 +318,14 @@ "no_addons": "עדיין לא מותקנות הרחבות. גשו לחנות ההרחבה כדי להתחיל!" }, "dialog": { + "hardware": { + "attributes": "תכונות", + "device_path": "נתיב התקן", + "id": "מזהה", + "search": "חפש חומרה", + "subsystem": "תת מערכת", + "title": "חומרה" + }, "network": { "connected_to": "מחובר אל {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "תוספים", "available_snapshots": "גיבויים זמינים", + "confirm_password": "אישור סיסמת גיבוי", "could_not_create": "לא ניתן ליצור גיבוי", "create": "צור", "create_blocked_not_running": "יצירת גיבוי אינה אפשרית כרגע מכיוון שהמערכת במצב {state} .", @@ -409,6 +418,7 @@ "password": "סיסמה", "password_protected": "מוגן באמצעות סיסמה", "password_protection": "הגנה באמצעות סיסמה", + "passwords_not_matching": "הסיסמאות אינן תואמות", "security": "אבטחה", "select_type": "בחר מה לשחזר", "selected": "{number} נבחרו", diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index 8165ff6aed..c769c47971 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -318,6 +318,14 @@ "no_addons": "아직 설치된 애드온이 없습니다. 시작하려면 애드온 스토어로 이동해보세요!" }, "dialog": { + "hardware": { + "attributes": "속성", + "device_path": "장치 경로", + "id": "ID", + "search": "하드웨어 검색", + "subsystem": "서브 시스템", + "title": "하드웨어" + }, "network": { "connected_to": "{ssid}에 연결되었습니다", "dhcp": "자동 구성", @@ -382,6 +390,7 @@ "snapshot": { "addons": "애드온", "available_snapshots": "사용 가능한 스냅숏", + "confirm_password": "스냅샷 비밀번호 확인", "could_not_create": "스냅숏을 만들 수 없습니다", "create": "생성하기", "create_blocked_not_running": "시스템이 {state} 상태이기 때문에 지금은 스냅숏을 생성할 수 없습니다.", @@ -409,6 +418,7 @@ "password": "비밀번호", "password_protected": "비밀번호로 보호됨", "password_protection": "비밀번호 보호", + "passwords_not_matching": "비밀번호가 일치하지 않습니다", "security": "보안", "select_type": "복원 할 항목 선택", "selected": "{number}개 선택됨", diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index db2b6757ab..eddfb6ab81 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -318,6 +318,14 @@ "no_addons": "Du har ikke installert tilleggsprogrammer ennå. Gå over til tilleggsbutikken for å komme i gang!" }, "dialog": { + "hardware": { + "attributes": "Attributter", + "device_path": "Bane til enhet", + "id": "ID", + "search": "Søk i maskinvare", + "subsystem": "Delsystem", + "title": "Maskinvare" + }, "network": { "connected_to": "Koblet til {ssid}", "dhcp": "", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 94ff9453cf..c7c1eb240c 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -318,6 +318,14 @@ "no_addons": "Нет установленных дополнений. Вы можете установить их из магазина дополнений." }, "dialog": { + "hardware": { + "attributes": "Атрибуты", + "device_path": "Путь к устройству", + "id": "ID", + "search": "Поиск оборудования", + "subsystem": "Подсистема", + "title": "Оборудование" + }, "network": { "connected_to": "Подключено к {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Дополнения", "available_snapshots": "Доступные снимки", + "confirm_password": "Подтверждение пароля", "could_not_create": "Не удалось создать снимок", "create": "Создать", "create_blocked_not_running": "Создание снимка сейчас невозможно, потому что система находится в состоянии {state}.", @@ -409,6 +418,7 @@ "password": "Пароль", "password_protected": "защищено паролем", "password_protection": "Защита паролем", + "passwords_not_matching": "Пароли не совпадают", "security": "Безопасность", "select_type": "Выберите что нужно восстановить из этого снимка файловой системы", "selected": "Выбрано: {number}", diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index 81805be4b7..19be965c7e 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -318,6 +318,14 @@ "no_addons": "目前似乎沒有安裝任何附加元件。點選下方附加元件商店以新增!" }, "dialog": { + "hardware": { + "attributes": "屬性", + "device_path": "裝置路徑", + "id": "ID", + "search": "搜尋硬體", + "subsystem": "子系統", + "title": "硬體" + }, "network": { "connected_to": "已連線至 {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "附加元件", "available_snapshots": "可用系統備份", + "confirm_password": "確認系統備份密碼", "could_not_create": "無法製作系統備份", "create": "新增", "create_blocked_not_running": "由於系統為 {state} 狀態,無法製作系統備份。", @@ -409,6 +418,7 @@ "password": "系統備份密碼", "password_protected": "密碼保護未顯示", "password_protection": "密碼保護", + "passwords_not_matching": "密碼不相符", "security": "加密", "select_type": "選擇所要回復內容", "selected": "已選擇 {number} 個", From 226d6216b7f73a3dce34fa854bf7a1f420fb382a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Tue, 8 Jun 2021 13:07:02 +0200 Subject: [PATCH 13/73] Build wheels for 3.9-alpine3.13 (#9390) --- .github/workflows/release.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c753ac8479..23eddb8005 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,7 +6,6 @@ on: - published env: - WHEELS_TAG: 3.8-alpine3.12 PYTHON_VERSION: 3.8 NODE_VERSION: 12.1 @@ -64,6 +63,9 @@ jobs: strategy: matrix: arch: ["aarch64", "armhf", "armv7", "amd64", "i386"] + tag: + - "3.8-alpine3.12" + - "3.9-alpine3.13" steps: - name: Download requirements.txt uses: actions/download-artifact@v2 @@ -73,7 +75,7 @@ jobs: - name: Build wheels uses: home-assistant/wheels@master with: - tag: ${{ env.WHEELS_TAG }} + tag: ${{ matrix.tag }} arch: ${{ matrix.arch }} wheels-host: ${{ secrets.WHEELS_HOST }} wheels-key: ${{ secrets.WHEELS_KEY }} From 8a33d174d737052724f5cec49ef26c043f4603f9 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 8 Jun 2021 14:24:58 +0200 Subject: [PATCH 14/73] FIx selecting service/url path action after choosing default action (#9376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joakim Sørensen --- src/panels/lovelace/components/hui-action-editor.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/panels/lovelace/components/hui-action-editor.ts b/src/panels/lovelace/components/hui-action-editor.ts index 3bc6853ed2..91292ccfd1 100644 --- a/src/panels/lovelace/components/hui-action-editor.ts +++ b/src/panels/lovelace/components/hui-action-editor.ts @@ -33,18 +33,18 @@ export class HuiActionEditor extends LitElement { @property() protected hass?: HomeAssistant; get _navigation_path(): string { - const config = this.config as NavigateActionConfig; - return config.navigation_path || ""; + const config = this.config as NavigateActionConfig | undefined; + return config?.navigation_path || ""; } get _url_path(): string { - const config = this.config as UrlActionConfig; - return config.url_path || ""; + const config = this.config as UrlActionConfig | undefined; + return config?.url_path || ""; } get _service(): string { const config = this.config as CallServiceActionConfig; - return config.service || ""; + return config?.service || ""; } private _serviceAction = memoizeOne( From e9b1b3d8535c7b87fed836f7080301424cec0e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Tue, 8 Jun 2021 17:57:53 +0200 Subject: [PATCH 15/73] Fix issues with restoring snapshot during onboarding (#9385) Co-authored-by: Bram Kragten --- .../components/supervisor-snapshot-content.ts | 48 +++++++++++-------- .../snapshot/dialog-hassio-snapshot.ts | 48 +++++++++++++------ .../snapshot/show-dialog-hassio-snapshot.ts | 2 + src/onboarding/ha-onboarding.ts | 8 +++- src/onboarding/onboarding-restore-snapshot.ts | 24 ++++++---- src/translations/en.json | 11 ++++- 6 files changed, 95 insertions(+), 46 deletions(-) diff --git a/hassio/src/components/supervisor-snapshot-content.ts b/hassio/src/components/supervisor-snapshot-content.ts index d1095179ca..b420f00959 100644 --- a/hassio/src/components/supervisor-snapshot-content.ts +++ b/hassio/src/components/supervisor-snapshot-content.ts @@ -5,6 +5,7 @@ import { customElement, property } from "lit/decorators"; import { atLeastVersion } from "../../../src/common/config/version"; import { formatDate } from "../../../src/common/datetime/format_date"; import { formatDateTime } from "../../../src/common/datetime/format_date_time"; +import { LocalizeFunc } from "../../../src/common/translations/localize"; import "../../../src/components/ha-checkbox"; import "../../../src/components/ha-formfield"; import "../../../src/components/ha-radio"; @@ -67,6 +68,8 @@ const _computeAddons = (addons): AddonCheckboxItem[] => export class SupervisorSnapshotContent extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + @property() public localize?: LocalizeFunc; + @property({ attribute: false }) public supervisor?: Supervisor; @property({ attribute: false }) public snapshot?: HassioSnapshotDetail; @@ -81,6 +84,8 @@ export class SupervisorSnapshotContent extends LitElement { @property({ type: Boolean }) public snapshotHasPassword = false; + @property({ type: Boolean }) public onboarding = false; + @property() public snapshotName = ""; @property() public snapshotPassword = ""; @@ -106,8 +111,12 @@ export class SupervisorSnapshotContent extends LitElement { } } + private _localize = (string: string) => + this.supervisor?.localize(`snapshot.${string}`) || + this.localize!(`ui.panel.page-onboarding.restore.${string}`); + protected render(): TemplateResult { - if (!this.supervisor) { + if (!this.onboarding && !this.supervisor) { return html``; } const foldersSection = @@ -119,14 +128,16 @@ export class SupervisorSnapshotContent extends LitElement { ${this.snapshot ? html`
${this.snapshot.type === "full" - ? this.supervisor.localize("snapshot.full_snapshot") - : this.supervisor.localize("snapshot.partial_snapshot")} + ? this._localize("full_snapshot") + : this._localize("partial_snapshot")} (${Math.ceil(this.snapshot.size * 10) / 10 + " MB"})
- ${formatDateTime(new Date(this.snapshot.date), this.hass.locale)} + ${this.hass + ? formatDateTime(new Date(this.snapshot.date), this.hass.locale) + : this.snapshot.date}
` : html` @@ -134,13 +145,11 @@ export class SupervisorSnapshotContent extends LitElement { ${!this.snapshot || this.snapshot.type === "full" ? html`
${!this.snapshot - ? this.supervisor.localize("snapshot.type") - : this.supervisor.localize("snapshot.select_type")} + ? this._localize("type") + : this._localize("select_type")}
- + - + `} @@ -208,7 +215,7 @@ export class SupervisorSnapshotContent extends LitElement { ? html` `} @@ -233,7 +240,7 @@ export class SupervisorSnapshotContent extends LitElement { ${!this.snapshot ? html` ${!this.snapshot ? html` [item.slug, item]) + this.supervisor?.addon.addons.map((item) => [item.slug, item]) ) : undefined; let checkedItems = 0; @@ -367,6 +372,7 @@ export class SupervisorSnapshotContent extends LitElement { .label=${item.name} .iconPath=${section === "addons" ? mdiPuzzle : mdiFolder} .imageUrl=${section === "addons" && + !this.onboarding && atLeastVersion(this.hass.config.version, 0, 105) && addons?.get(item.slug)?.icon ? `/api/hassio/addons/${item.slug}/icon` diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts index e7afcdbad1..93938903c9 100755 --- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts +++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts @@ -1,13 +1,13 @@ import { ActionDetail } from "@material/mwc-list"; import "@material/mwc-list/mwc-list-item"; -import { mdiDotsVertical } from "@mdi/js"; +import { mdiClose, mdiDotsVertical } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import { slugify } from "../../../../src/common/string/slugify"; import "../../../../src/components/buttons/ha-progress-button"; import "../../../../src/components/ha-button-menu"; -import { createCloseHeading } from "../../../../src/components/ha-dialog"; +import "../../../../src/components/ha-header-bar"; import "../../../../src/components/ha-svg-icon"; import { getSignedPath } from "../../../../src/data/auth"; import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; @@ -67,14 +67,24 @@ class HassioSnapshotDialog open scrimClickAction @closed=${this.closeDialog} - .heading=${createCloseHeading(this.hass, this._computeName)} + .heading=${true} > +
+ + ${this._snapshot.name} + + + + +
${this._restoringSnapshot ? html` ` : html` `} ${this._error ? html`

Error: ${this._error}

` : ""} @@ -87,18 +97,20 @@ class HassioSnapshotDialog Restore - ev.stopPropagation()} - > - - - - Download Snapshot - Delete Snapshot - + ${!this._dialogParams.onboarding + ? html` ev.stopPropagation()} + > + + + + Download Snapshot + Delete Snapshot + ` + : ""} `; } @@ -115,6 +127,12 @@ class HassioSnapshotDialog display: block; text-align: center; } + ha-header-bar { + --mdc-theme-on-primary: var(--primary-text-color); + --mdc-theme-primary: var(--mdc-theme-surface); + flex-shrink: 0; + display: block; + } `, ]; } diff --git a/hassio/src/dialogs/snapshot/show-dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/show-dialog-hassio-snapshot.ts index 8c7bcd2be7..fd74e90ea7 100644 --- a/hassio/src/dialogs/snapshot/show-dialog-hassio-snapshot.ts +++ b/hassio/src/dialogs/snapshot/show-dialog-hassio-snapshot.ts @@ -1,4 +1,5 @@ import { fireEvent } from "../../../../src/common/dom/fire_event"; +import { LocalizeFunc } from "../../../../src/common/translations/localize"; import { Supervisor } from "../../../../src/data/supervisor/supervisor"; export interface HassioSnapshotDialogParams { @@ -6,6 +7,7 @@ export interface HassioSnapshotDialogParams { onDelete?: () => void; onboarding?: boolean; supervisor?: Supervisor; + localize?: LocalizeFunc; } export const showHassioSnapshotDialog = ( diff --git a/src/onboarding/ha-onboarding.ts b/src/onboarding/ha-onboarding.ts index 2a7c66bd9f..cea41caaa6 100644 --- a/src/onboarding/ha-onboarding.ts +++ b/src/onboarding/ha-onboarding.ts @@ -12,7 +12,10 @@ import { HASSDomEvent } from "../common/dom/fire_event"; import { extractSearchParamsObject } from "../common/url/search-params"; import { subscribeOne } from "../common/util/subscribe-one"; import { AuthUrlSearchParams, hassUrl } from "../data/auth"; -import { fetchDiscoveryInformation } from "../data/discovery"; +import { + DiscoveryInformation, + fetchDiscoveryInformation, +} from "../data/discovery"; import { fetchOnboardingOverview, OnboardingResponses, @@ -68,6 +71,8 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) { @state() private _steps?: OnboardingStep[]; + @state() private _discoveryInformation?: DiscoveryInformation; + protected render(): TemplateResult { const step = this._curStep()!; @@ -87,6 +92,7 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) { ? html` ` diff --git a/src/onboarding/onboarding-restore-snapshot.ts b/src/onboarding/onboarding-restore-snapshot.ts index 32d604c7ac..ca1afc56eb 100644 --- a/src/onboarding/onboarding-restore-snapshot.ts +++ b/src/onboarding/onboarding-restore-snapshot.ts @@ -4,9 +4,12 @@ import { customElement, property } from "lit/decorators"; import "../../hassio/src/components/hassio-ansi-to-html"; import { showHassioSnapshotDialog } from "../../hassio/src/dialogs/snapshot/show-dialog-hassio-snapshot"; import { showSnapshotUploadDialog } from "../../hassio/src/dialogs/snapshot/show-dialog-snapshot-upload"; -import { navigate } from "../common/navigate"; import type { LocalizeFunc } from "../common/translations/localize"; import "../components/ha-card"; +import { + DiscoveryInformation, + fetchDiscoveryInformation, +} from "../data/discovery"; import { makeDialogManager } from "../dialogs/make-dialog-manager"; import { ProvideHassLitMixin } from "../mixins/provide-hass-lit-mixin"; import { haStyle } from "../resources/styles"; @@ -26,6 +29,9 @@ class OnboardingRestoreSnapshot extends ProvideHassLitMixin(LitElement) { @property({ type: Boolean }) public restoring = false; + @property({ attribute: false }) + public discoveryInformation?: DiscoveryInformation; + protected render(): TemplateResult { return this.restoring ? html` { if (this.restoring) { try { - const response = await fetch("/api/hassio/supervisor/info", { - method: "GET", - }); - if (response.status === 401) { - // If we get a unauthorized response, the restore is done - navigate("/", { replace: true }); - location.reload(); + const response = await fetchDiscoveryInformation(); + + if ( + !this.discoveryInformation || + this.discoveryInformation.uuid !== response.uuid + ) { + // When the UUID changes, the restore is complete + window.location.replace("/"); } } catch (err) { // We fully expected issues with fetching info untill restore is complete. @@ -76,6 +83,7 @@ class OnboardingRestoreSnapshot extends ProvideHassLitMixin(LitElement) { showHassioSnapshotDialog(this, { slug, onboarding: true, + localize: this.localize, }); } diff --git a/src/translations/en.json b/src/translations/en.json index 0a9ab32f6d..9977b10956 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3569,7 +3569,16 @@ "description": "Alternatively you can restore from a previous snapshot.", "in_progress": "Restore in progress", "show_log": "Show full log", - "hide_log": "Hide full log" + "hide_log": "Hide full log", + "full_snapshot": "[%key:supervisor::snapshot::full_snapshot%]", + "partial_snapshot": "[%key:supervisor::snapshot::partial_snapshot%]", + "type": "[%key:supervisor::snapshot::type%]", + "select_type": "[%key:supervisor::snapshot::select_type%]", + "folders": "[%key:supervisor::snapshot::folders%]", + "addons": "[%key:supervisor::snapshot::addons%]", + "password_protection": "[%key:supervisor::snapshot::password_protection%]", + "password": "[%key:supervisor::snapshot::password%]", + "confirm_password": "[%key:supervisor::snapshot::confirm_password%]" } }, "custom": { From 67be2343f8cc823afed2940b72742a1b3145c2c4 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 9 Jun 2021 00:48:19 +0000 Subject: [PATCH 16/73] Translation update --- translations/frontend/bg.json | 32 +++++++++++----------- translations/frontend/ca.json | 13 +++++++-- translations/frontend/de.json | 18 ++++++++++--- translations/frontend/en.json | 11 +++++++- translations/frontend/et.json | 51 ++++++++++++++++++++--------------- translations/frontend/nb.json | 2 ++ translations/frontend/nl.json | 24 +++++++++++++++-- 7 files changed, 106 insertions(+), 45 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index cf1bc4e394..6fb21f681d 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -130,12 +130,12 @@ "action_error": { "get_changelog": "Неуспешно получаване на списък с промени на добавката", "go_to_config": "Грешка при стартиране на добавката - неуспешна проверка на конфигурацията!", - "install": "Инсталирането на добавката не бе успешно", - "restart": "Рестартирането на добавката не бе успешно", - "start": "Стартирането на добавката не бе успешно", + "install": "Инсталирането на добавката не е успешно", + "restart": "Рестартирането на добавката не е успешно", + "start": "Стартирането на добавката не е успешно", "start_invalid_config": "Към конфигурацията", - "stop": "Спирането на добавката не бе успешно", - "uninstall": "Деинсталирането на добавката не бе успешно", + "stop": "Спирането на добавката не е успешно", + "uninstall": "Деинсталирането на добавката не е успешно", "validate_config": "Грешка при проверка на конфигурацията на добавката" }, "capability": { @@ -218,8 +218,8 @@ "documentation": { "get_documentation": "Неуспешно получаване на документация за добавката, {error}" }, - "failed_to_reset": "Нулирането на конфигурацията на добавката не бе успешно, {error}", - "failed_to_save": "Запазването на конфигурацията на добавката не бе успешно, {error}", + "failed_to_reset": "Нулирането на конфигурацията на добавката не е успешно, {error}", + "failed_to_save": "Запазването на конфигурацията на добавката не е успешно, {error}", "logs": { "get_logs": "Неуспешно получаване журнали на добавка, {грешка}" }, @@ -241,10 +241,10 @@ "description": "Описание", "error": { "unknown": "Неизвестна грешка", - "update_failed": "Актуализацията не бе успешна" + "update_failed": "Актуализацията не е успешна" }, - "failed_to_restart_name": "Рестартирането на {name} не бе успешно", - "failed_to_update_name": "Актуализирането на {name} не бе успешно", + "failed_to_restart_name": "Рестартирането на {name} не е успешно", + "failed_to_update_name": "Актуализирането на {name} не е успешно", "learn_more": "Научете повече", "new_version_available": "Налична е нова версия", "newest_version": "Последна версия", @@ -296,7 +296,7 @@ "dhcp": "DHCP", "disabled": "Деактивиран", "dns_servers": "DNS Сървъри", - "failed_to_change": "Промяната на мрежовите настройки не бе успешна", + "failed_to_change": "Промяната на мрежовите настройки не е успешна", "gateway": "Адрес на шлюза", "ip_netmask": "IP адрес/Мрежова маска", "open": "Отворена", @@ -311,8 +311,8 @@ "registries": { "add_new_registry": "Добавяне на нов регистър", "add_registry": "Добавяне на регистър", - "failed_to_add": "Добавянето на регистър не бе успешно", - "failed_to_remove": "Премахването на регистър не бе успешно", + "failed_to_add": "Добавянето на регистър не е успешно", + "failed_to_remove": "Премахването на регистър не е успешно", "no_registries": "Няма конфигурирани регистри", "password": "Парола", "registry": "Регистър", @@ -363,6 +363,7 @@ "delete_snapshot_title": "Изтриване на снапшота", "description": "Снапшотите ви позволяват лесно да архивирате и възстановявате всички данни от вашия екземпляр на Home Assistant.", "enter_password": "Моля, въведете парола.", + "failed_to_delete": "Изтриването не е успешно", "folder": { "addons/local": "Локални добавки", "homeassistant": "Конфигурация на Home Assistant", @@ -448,7 +449,7 @@ "unhealthy_reason": { "docker": "Средата на Docker не работи правилно", "privileged": "Supervisor не е привилегирован", - "setup": "Настройката на Supervisor не бе успешна", + "setup": "Настройката на Supervisor не е успешна", "supervisor": "Supervisor не успя да се актуализира", "untrusted": "Открито e ненадежден съдържание" }, @@ -1931,7 +1932,8 @@ "scripts": "Скриптове", "unknown_error": "Неизвестна грешка", "unnamed_device": "Устройство без име", - "update": "Актуализация" + "update": "Актуализация", + "update_device_error": "Актуализирането на устройството не е успешно" }, "entities": { "caption": "Обекти", diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index f00ce7e49e..e7b1e80755 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -322,7 +322,7 @@ "attributes": "Atributs", "device_path": "Ruta del dispositiu", "id": "ID", - "search": "Cercar maquinari", + "search": "Cerca maquinari", "subsystem": "Subsistema", "title": "Maquinari" }, @@ -3891,10 +3891,19 @@ "intro": "Estàs preparat donar vida pròpia a la teva llar, recuperar la teva privacitat i unir-te a una comunitat mundial de \"tinkerers\"?", "next": "Següent", "restore": { + "addons": "Complements", + "confirm_password": "Confirma la contrasenya de la instantània", "description": "També pots restaurar des d'una instantània anterior.", + "folders": "Carpetes", + "full_snapshot": "Instantània completa", "hide_log": "Amaga el registre complet", "in_progress": "Restauració en curs", - "show_log": "Mostra el registre complet" + "partial_snapshot": "Instantània parcial", + "password": "Contrasenya de la instantània", + "password_protection": "Protecció amb contrasenya", + "select_type": "Selecciona què vols restaurar", + "show_log": "Mostra el registre complet", + "type": "Tipus d'instantània" }, "user": { "create_account": "Crear compte", diff --git a/translations/frontend/de.json b/translations/frontend/de.json index abb367366c..a71fe5668f 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -314,10 +314,18 @@ "addon_new_version": "Neue Version verfügbar", "addon_running": "Add-on wird ausgeführt", "addon_stopped": "Add-on ist gestoppt", - "addons": "Add-ons", + "addons": "Installierte Add-ons", "no_addons": "Du hast noch keine Add-ons installiert. Gehe zum Add-on Store, um loszulegen!" }, "dialog": { + "hardware": { + "attributes": "Attribute", + "device_path": "Gerätepfad", + "id": "ID", + "search": "Hardware suchen", + "subsystem": "Subsystem", + "title": "Hardware" + }, "network": { "connected_to": "Verbunden mit {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Add-ons", "available_snapshots": "Verfügbare Datensicherungen", + "confirm_password": "Snapshot-Passwort bestätigen", "could_not_create": "Datensicherung konnte nicht erstellt werden", "create": "Erstellen", "create_blocked_not_running": "Das Erstellen eines Snapshots ist derzeit nicht möglich, da sich das System im Zustand {state} befindet.", @@ -403,16 +412,17 @@ }, "folders": "Ordner", "full_snapshot": "Vollständige Datensicherung", - "name": "Name", + "name": "Snapshot-Name", "no_snapshots": "Du hast bisher keine Datensicherungen erstellt.", "partial_snapshot": "Selektive Datensicherung", - "password": "Passwort", + "password": "Snapshot-Passwort", "password_protected": "Passwort geschützt", "password_protection": "Passwortschutz", + "passwords_not_matching": "Passwörter stimmen nicht überein", "security": "Sicherheit", "select_type": "Wähle aus, was wiederhergestellt werden soll", "selected": "{number} ausgewählt", - "type": "Typ", + "type": "Snapshot-Typ", "upload_snapshot": "Datensicherung hochladen" }, "store": { diff --git a/translations/frontend/en.json b/translations/frontend/en.json index f18b30e269..0aa0e488e5 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -3891,10 +3891,19 @@ "intro": "Are you ready to awaken your home, reclaim your privacy and join a worldwide community of tinkerers?", "next": "Next", "restore": { + "addons": "Add-ons", + "confirm_password": "Confirm Snapshot password", "description": "Alternatively you can restore from a previous snapshot.", + "folders": "Folders", + "full_snapshot": "Full snapshot", "hide_log": "Hide full log", "in_progress": "Restore in progress", - "show_log": "Show full log" + "partial_snapshot": "Partial snapshot", + "password": "Snapshot password", + "password_protection": "Password protection", + "select_type": "Select what to restore", + "show_log": "Show full log", + "type": "Snapshot type" }, "user": { "create_account": "Create Account", diff --git a/translations/frontend/et.json b/translations/frontend/et.json index 129e23b248..4ed9f8720d 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -366,9 +366,9 @@ "text": "Kas soovid lisandmooduli taaskäivitada rakendades muudatused?" }, "update": { - "create_snapshot": "Enne {name} värskendamist loo hetktõmmis", - "snapshot": "Hetktõmmis", - "snapshotting": "Üksuse {name} hetktõmmise loomine", + "create_snapshot": "Enne {name} värskendamist loo varukoopia", + "snapshot": "Varukoopia", + "snapshotting": "Üksuse {name} varukoopia loomine", "updating": "Üksuse {name} värskendamine versioonile {version}" } }, @@ -389,18 +389,18 @@ }, "snapshot": { "addons": "Lisandmoodulid", - "available_snapshots": "Saadaolevad hetktõmmised", - "confirm_password": "Hetktõmmise parooli kinnitamine", - "could_not_create": "Hetktõmmise loomine nurjus", + "available_snapshots": "Saadaolevad varukoopiad", + "confirm_password": "Varukoopia salasõna kinnitamine", + "could_not_create": "Varukoopia loomine nurjus", "create": "Loo", - "create_blocked_not_running": "Hetktõmmise loomine pole praegu võimalik kuna süsteem on olekus {state}.", - "create_snapshot": "Loo hetktõmmis", + "create_blocked_not_running": "Varukoopia loomine pole praegu võimalik kuna süsteem on olekus {state}.", + "create_snapshot": "Loo varukoopia", "created": "Loodud", - "delete_selected": "Kustuta valitud hetktõmmised", + "delete_selected": "Kustuta valitud varukoopiad", "delete_snapshot_confirm": "kustuta", - "delete_snapshot_text": "Kas kustutada {number} {number, plural,\n one {hetktõmmis}\n other {hetktõmmist}\n}?", - "delete_snapshot_title": "Kustuta hetktõmmis", - "description": "Hetktõmmised võimaldavad hõlpsalt varundada ja taastada kõik Home Assistanti andmed.", + "delete_snapshot_text": "Kas kustutada {number} {number, plural,\n one {varukoopia}\n other {varukoopiat}\n}?", + "delete_snapshot_title": "Kustuta varukoopia", + "description": "Varukoopiad võimaldavad hõlpsalt varundada ja taastada kõik Home Assistanti andmed.", "enter_password": "Sisesta salasõna.", "failed_to_delete": "Kustutamine nurjus", "folder": { @@ -411,19 +411,19 @@ "ssl": "SSL" }, "folders": "Kaustad", - "full_snapshot": "Täielik hetktõmmis", - "name": "Hetktõmmise nimi", - "no_snapshots": "Sul pole veel ühtegi hetktõmmist.", - "partial_snapshot": "Osaline hetktõmmis", - "password": "Hetktõmmise salasõna", + "full_snapshot": "Täielik varukoopia", + "name": "Varukoopia nimi", + "no_snapshots": "Sul pole veel ühtegi varukoopiat.", + "partial_snapshot": "Osaline varukoopia", + "password": "Varukoopia salasõna", "password_protected": "salasõnaha kaitstud", "password_protection": "Salasõnaga kaitstud", "passwords_not_matching": "Salasõnad ei ühti", "security": "Turvalisus", "select_type": "Vali mida taastada", "selected": "{number} valitud", - "type": "Hetktõmmise tüüp", - "upload_snapshot": "Hetktõmmise üleslaadimine" + "type": "Varukoopia tüüp", + "upload_snapshot": "Varukoopia üleslaadimine" }, "store": { "missing_addons": "Ei näe lisandmooduleid? Luba täpsem režiim oma kasutajaprofiili lehel", @@ -3891,10 +3891,19 @@ "intro": "Kas oled valmis oma kodu ellu äratama, oma privaatsust tagasi võitma ja ühinema ülemaailmse nokitsejate kogukonnaga?", "next": "Järgmine", "restore": { - "description": "Teise võimalusena saad taastada eelmise hetktõmmise.", + "addons": "Lisandmoodulid", + "confirm_password": "Kinnita salasõna", + "description": "Teise võimalusena saad taastada eelmise varukoopia.", + "folders": "Kaustad", + "full_snapshot": "Täielik varukoopia", "hide_log": "Peida täielik logi", "in_progress": "Toimub taastamine", - "show_log": "Kuva täielik logi" + "partial_snapshot": "Osaline varukoopia", + "password": "Salasõna", + "password_protection": "Salasõnaga kaitstud", + "select_type": "Vali andmestiku tüüp", + "show_log": "Kuva täielik logi", + "type": "Andmestiku tüüp" }, "user": { "create_account": "Loo konto", diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index eddfb6ab81..c33af17f50 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -390,6 +390,7 @@ "snapshot": { "addons": "Tillegg", "available_snapshots": "Tilgjengelige sikkerhetskopier", + "confirm_password": "Bekreft passord for øyeblikksbilde", "could_not_create": "Kunne ikke opprette sikkerhetskopi", "create": "Opprett", "create_blocked_not_running": "Å lage en sikkerhetskopi er ikke mulig akkurat nå fordi systemet er i {state} status", @@ -417,6 +418,7 @@ "password": "Passord for øyeblikksbilde", "password_protected": "Passordbeskyttet", "password_protection": "Passordbeskyttelse", + "passwords_not_matching": "Passordene samsvarer ikke", "security": "Sikkerhet", "select_type": "Velg hva du vil gjenopprette", "selected": "{number} valgt", diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index d3e4bd25c9..3db2f73e61 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -318,6 +318,14 @@ "no_addons": "Je hebt nog geen add-ons geïnstalleerd. Ga naar de add-on store om te beginnen!" }, "dialog": { + "hardware": { + "attributes": "Attributen", + "device_path": "Apparaatpad", + "id": "ID", + "search": "Zoek hardware", + "subsystem": "Subsysteem", + "title": "Hardware" + }, "network": { "connected_to": "Verbonden met {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Invoegtoepassingen", "available_snapshots": "Beschikbare snapshots", + "confirm_password": "Bevestig Snapshot-wachtwoord", "could_not_create": "Kon geen snapshot maken", "create": "Maak", "create_blocked_not_running": "Het maken van een snapshot is nu niet mogelijk omdat het systeem in {state} staat.", @@ -409,6 +418,7 @@ "password": "Snapshot wachtwoord", "password_protected": "beveiligd met wachtwoord", "password_protection": "Wachtwoord bescherming", + "passwords_not_matching": "De wachtwoorden komen niet overeen", "security": "Beveiliging", "select_type": "Selecteer wat u wilt herstellen", "selected": "{number} geselecteerd", @@ -972,7 +982,7 @@ }, "faq": "documentatie", "info_customize": "U kunt sommige attributen overschrijven in de {customize_link} sectie.", - "no_unique_id": "Deze entiteit (\" {entity_id} \") heeft geen unieke ID, daarom kunnen de instellingen ervan niet worden beheerd vanuit de gebruikersinterface. Zie de {faq_link} voor meer details.", + "no_unique_id": "Deze entiteit (\"{entity_id}\") heeft geen unieke ID, daarom kunnen de instellingen ervan niet worden beheerd vanuit de gebruikersinterface. Zie de {faq_link} voor meer details.", "related": "Gerelateerd", "settings": "instellingen" }, @@ -2212,6 +2222,7 @@ "depends_on_cloud": "Cloud afhankelijk", "device_unavailable": "Apparaat niet beschikbaar", "devices": "{count} {count, plural,\n one {apparaat}\n other {apparaten}\n}", + "disable_error": "In- of uitschakelen van de integratie mislukt", "disable_restart_confirm": "Start Home Assistant opnieuw op om het uitzetten van deze integratie te voltooien", "disable": { "disable_confirm": "Weet je zeker dat je deze configuratie wilt uitschakelen? Al diens apparaten en entiteiten zullen worden uitgeschakeld.", @@ -3880,10 +3891,19 @@ "intro": "Ben je klaar om je huis wakker te maken, je privacy terug te winnen en deel te nemen aan een wereldwijde gemeenschap van knutselaars?", "next": "Volgende", "restore": { + "addons": "Invoegtoepassingen", + "confirm_password": "Bevestig Snapshot-wachtwoord", "description": "Je kunt ook herstellen vanaf een eerdere snapshot.", + "folders": "Mappen", + "full_snapshot": "Volledige snapshot", "hide_log": "Verberg volledig logboek", "in_progress": "Herstel in uitvoering", - "show_log": "Volledig logboek weergeven" + "partial_snapshot": "Gedeeltelijke snapshot", + "password": "Snapshot wachtwoord", + "password_protection": "Wachtwoord bescherming", + "select_type": "Selecteer wat u wilt herstellen", + "show_log": "Volledig logboek weergeven", + "type": "Snapshot type" }, "user": { "create_account": "Account aanmaken", From 11a77253f4d998eeae6ee6f8097c6488919a1d23 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 10 Jun 2021 00:49:02 +0000 Subject: [PATCH 17/73] Translation update --- translations/frontend/bg.json | 11 +++- translations/frontend/cs.json | 11 +++- translations/frontend/es.json | 11 +++- translations/frontend/ru.json | 11 +++- translations/frontend/sk.json | 102 +++++++++++++++++++++++++++-- translations/frontend/zh-Hans.json | 21 +++++- translations/frontend/zh-Hant.json | 11 +++- 7 files changed, 167 insertions(+), 11 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index 6fb21f681d..e8bc9f9ae8 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -3363,10 +3363,19 @@ "intro": "Готови ли сте да събудите дома си, да отвоювате независимостта си и да се присъедините към световна общност от хора автоматизиращи домовете си?", "next": "Следващ", "restore": { + "addons": "Добавки", + "confirm_password": "Потвърдете паролата за снапшота", "description": "Като алтернатива можете да възстановите от предишен снапшот.", + "folders": "Папки", + "full_snapshot": "Пълен снапшот", "hide_log": "Скриване на пълния дневник", "in_progress": "Възстановяването е в ход", - "show_log": "Показване на пълния дневник" + "partial_snapshot": "Частичен снапшот", + "password": "Парола", + "password_protection": "Защита с парола", + "select_type": "Изберете какво да възстановите", + "show_log": "Показване на пълния дневник", + "type": "Тип" }, "user": { "create_account": "Създай акаунт", diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index c117b7aefb..7243339353 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -3886,10 +3886,19 @@ "intro": "Jste připraveni oživit svůj domov, zachovat si své soukromí a připojit se k celosvětové komunitě tvůrců?", "next": "Další", "restore": { + "addons": "Doplňky", + "confirm_password": "Potvrďte heslo zálohy", "description": "Případně můžete Home Assistant obnovit z poslední zálohy.", + "folders": "Složky", + "full_snapshot": "Úplná záloha", "hide_log": "Skrýt celý log", "in_progress": "Probíhá obnovení", - "show_log": "Zobrazit celý log" + "partial_snapshot": "Částečná záloha", + "password": "Heslo zálohy", + "password_protection": "Ochrana heslem", + "select_type": "Vyberte, co chcete obnovit", + "show_log": "Zobrazit celý log", + "type": "Typ zálohy" }, "user": { "create_account": "Vytvořit účet", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index c161b2a757..18bf376a08 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -3891,10 +3891,19 @@ "intro": "¿Estás listo para despertar tu casa, reclamar tu privacidad y unirte a una comunidad mundial de pensadores?", "next": "Siguiente", "restore": { + "addons": "Complementos", + "confirm_password": "Confirma la contraseña de la instantánea", "description": "Alternativamente, puedes restaurar desde una copia de seguridad anterior.", + "folders": "Carpetas", + "full_snapshot": "Instantánea completa", "hide_log": "Ocultar registro completo", "in_progress": "Restauración en curso", - "show_log": "Mostrar registro completo" + "partial_snapshot": "Instantánea parcial", + "password": "Contraseña de la instantánea", + "password_protection": "Protección con contraseña", + "select_type": "Selecciona qué restaurar", + "show_log": "Mostrar registro completo", + "type": "Tipo de instantánea" }, "user": { "create_account": "Crear una cuenta", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index c7c1eb240c..bd9b26f613 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -3891,10 +3891,19 @@ "intro": "Готовы ли Вы разбудить свой дом, вернуть свою конфиденциальность и присоединиться к всемирному сообществу?", "next": "Далее", "restore": { + "addons": "Дополнения", + "confirm_password": "Подтверждение пароля", "description": "Восстановить предыдущее состояние из снимка файловой системы (snapshot)", + "folders": "Папки", + "full_snapshot": "Все файлы", "hide_log": "Скрыть журнал", "in_progress": "Восстановление системы", - "show_log": "Показать журнал" + "partial_snapshot": "Выбрать из списка", + "password": "Пароль", + "password_protection": "Защита паролем", + "select_type": "Выберите что нужно восстановить из этого снимка файловой системы", + "show_log": "Показать журнал", + "type": "Выберите что должен включать в себя снимок файловой системы" }, "user": { "create_account": "Создать учётную запись", diff --git a/translations/frontend/sk.json b/translations/frontend/sk.json index a1ba3685ab..a88705568d 100644 --- a/translations/frontend/sk.json +++ b/translations/frontend/sk.json @@ -285,6 +285,13 @@ "no_addons": "Zatiaľ nemáte nainštalované žiadne doplnky. Choďte do obchodu s doplnkami, aby ste mohli začať!" }, "dialog": { + "hardware": { + "attributes": "Atribúty", + "id": "ID", + "search": "Vyhľadať zariadenia", + "subsystem": "Subsystém", + "title": "Hardvér" + }, "network": { "connected_to": "Pripojiť na {ssid}", "dhcp": "DHCP", @@ -346,12 +353,17 @@ "snapshot": { "addons": "Doplnky", "available_snapshots": "Dostupné zálohy", + "confirm_password": "Potvrdiť heslo zálohy", "could_not_create": "Nepodarilo sa vytvoriť zálohu", "create": "Vytvoriť", "create_blocked_not_running": "Nieje možné vytvoriť zálohu pretože systém je v stave {state}", "create_snapshot": "Vytvoriť zálohu", + "created": "Vytvorené", + "delete_snapshot_confirm": "odstrániť", + "delete_snapshot_title": "Vymazať zálohu", "description": "Snapshoty ti umožňujú ľahko zálohovať a obnoviť všetky dáta Home Assistant", "enter_password": "Prosím napíšte heslo.", + "failed_to_delete": "Nepodarilo sa odstrániť", "folder": { "addons/local": "Lokálne doplnky", "homeassistant": "konfigurácia Home Asistenta", @@ -367,6 +379,7 @@ "password": "Heslo", "password_protected": "chránené heslo", "password_protection": "Ochrana Heslom", + "passwords_not_matching": "Heslá sa nezhodujú", "security": "Zabezpečenie", "type": "Typ", "upload_snapshot": "Nahrať zálohu" @@ -425,6 +438,7 @@ "leave_beta_description": "Získajte aktualizácie stabilnej verzie pre Home Assistant, supervízora a hostiteľa", "ram_usage": "Využitie RAM supervízorom", "reload_supervisor": "Znova načítať supervízora", + "search": "Hľadať", "share_diagnostics": "Zdieľajte diagnostiku", "share_diagnostics_description": "Zdieľajte správy o zlyhaní a diagnostické informácie.", "share_diagonstics_description": "Chceli by ste automaticky zdieľať správy o zlyhaní a diagnostické informácie, keď sa Supervízor stretne s neočakávanými chybami? {line_break} Umožní nám to vyriešiť problémy, informácie sú prístupné iba tímu Home Assistant Core a nebudú sa zdieľať s ostatnými. {line_break} Údaje neobsahujú žiadne súkromné ani citlivé informácie, ktoré môžete kedykoľvek deaktivovať v nastaveniach.", @@ -522,6 +536,7 @@ }, "light": { "brightness": "Jas", + "color_brightness": "Jas farby", "color_temperature": "Teplota farby", "effect": "Efekt", "white_value": "Hodnota bielej" @@ -660,6 +675,9 @@ "no_match": "Nenašli sa žiadne zodpovedajúce oblasti", "show_areas": "Zobraziť oblasti" }, + "attributes": { + "expansion_header": "Atribúty" + }, "blueprint-picker": { "add_user": "Pridať používateľa", "remove_user": "Odstrániť používateľa", @@ -670,6 +688,9 @@ "today": "Dnes" }, "data-table": { + "clear": "Vyčistiť", + "filtering_by": "Filtrovanie podľa", + "hidden": "{number} skryté", "no-data": "Žiadne údaje", "search": "Hľadať" }, @@ -725,7 +746,8 @@ "was_plugged_in": "bol zapojený", "was_unlocked": "bol odomknutý", "was_unplugged": "bol odpojený" - } + }, + "show_trace": "Zobraziť cestu" }, "media-browser": { "audio_not_supported": "Váš prehliadač nepodporuje zvukový prvok.", @@ -1017,6 +1039,11 @@ "smtp": "Znova načítať notifikačné služby SMTP", "telegram": "Znova načítať notifikačné služby telegram", "zone": "Znova načítať zóny" + }, + "types": { + "navigation": "Navigovať", + "reload": "Znova načítať", + "server_control": "Server" } }, "filter_placeholder": "Filter entít" @@ -1053,6 +1080,9 @@ "zha_device_card": { "device_name_placeholder": "Zmeniť názov zariadenia" } + }, + "zha_reconfigure_device": { + "attribute": "Atribút" } }, "duration": { @@ -1101,7 +1131,8 @@ "caption": "Register oblastí", "data_table": { "area": "Oblasť", - "devices": "Zariadenia" + "devices": "Zariadenia", + "entities": "Entity" }, "delete": { "confirmation_text": "Všetky zariadenia v tejto oblasti ostanú nepriradené.", @@ -1113,6 +1144,7 @@ "create": "VYTVORIŤ", "default_name": "Nová oblasť", "delete": "VYMAZAŤ", + "linked_entities_caption": "Entity", "name": "Názov", "name_required": "Názov je povinný", "unknown_error": "Neznáma chyba", @@ -1172,10 +1204,14 @@ "device_id": { "action": "Akcia", "extra_fields": { + "brightness_pct": "Jas", "code": "Kód", + "humidity": "Vlhkosť", "message": "Správa", + "mode": "Režim", "position": "pozícia", - "title": "Názov" + "title": "Názov", + "value": "Hodnota" }, "label": "Zariadenie" }, @@ -1232,7 +1268,9 @@ "extra_fields": { "above": "Nad", "below": "Pod", - "for": "Trvanie" + "for": "Trvanie", + "hvac_mode": "Režim HVAC", + "preset_mode": "Vyber režim" }, "label": "Zariadenie" }, @@ -1309,6 +1347,7 @@ "move_down": "Posunúť dole", "move_up": "Posunúť hore", "save": "Uložiť", + "show_trace": "Zobraziť cestu", "triggers": { "add": "Pridať spúšťač", "delete": "Odstrániť", @@ -1411,6 +1450,8 @@ "add_automation": "Pridať automatizáciu", "delete_automation": "Odstrániť automatizáciu", "delete_confirm": "Naozaj chcete odstrániť túto automatizáciu?", + "dev_automation": "Automatizácia ladenia", + "dev_only_editable": "Sledovateľné sú iba automatizácie, ktoré majú priradené jedinečné ID.", "duplicate": "Duplikovať", "duplicate_automation": "Duplikovať automatizáciu", "edit_automation": "Upraviť automatizáciu", @@ -1476,6 +1517,7 @@ "title": "Alexa" }, "connected": "Pripojené", + "connecting": "Pripája sa", "connection_status": "Stav cloudového pripojenia", "fetching_subscription": "Načítava sa predplatné...", "google": { @@ -1497,10 +1539,15 @@ "remote": { "access_is_being_prepared": "Pripravuje sa vzdialený prístup. Budeme vás informovať, keď bude pripravený.", "certificate_info": "Informácie o certifikáte", + "connected": "Pripojené", "info": "Home Assistant Cloud poskytuje zabezpečené vzdialené pripojenie k vašej inštancií kým ste mimo domova.", "instance_is_available": "Vaša inštancia je k dispozícii na stránke", "instance_will_be_available": "Vaša inštancia bude k dispozícii na adrese", "link_learn_how_it_works": "Zistite, ako to funguje", + "not_connected": "Nepripojené", + "remote_enabled": { + "caption": "Automaticky pripojiť" + }, "title": "Diaľkové ovládanie" }, "sign_out": "Odhlásiť sa", @@ -1637,6 +1684,17 @@ "description": "Jednotkový systém, umiestnenie, časové pásmo a ďalšie všeobecné parametre", "section": { "core": { + "analytics": { + "header": "Analízy", + "preference": { + "base": { + "title": "Základné analýzy" + }, + "diagnostics": { + "title": "Diagnostiky" + } + } + }, "core_config": { "edit_requires_storage": "Editor je zablokovaný, pretože konfigurácia je uložená v configuration.yaml", "elevation": "Nadmorská výška", @@ -1842,6 +1900,7 @@ "license": "Publikované pod licenciou Apache 2.0", "path_configuration": "Cesta k configuration.yaml: {path}", "server": "server", + "setup_time": "Nastaviť čas", "source": "Zdroj:", "system_health_error": "Súčasť System Health nie je načítaná. Pridajte 'system_health:' do súboru configuration.yaml", "system_health": { @@ -1901,6 +1960,7 @@ }, "finish": "Dokončiť", "loading_first_time": "Počkajte, kým sa nainštaluje integrácia", + "next": "Ďalej", "not_all_required_fields": "Nie sú vyplnené všetky povinné polia.", "pick_flow_step": { "new_flow": "Nie, nastaviť inú inštanciu {integration}", @@ -1916,6 +1976,7 @@ "disable": { "disabled_integrations": "{number} deaktivované", "hide_disabled": "Skryť vypnuté integrácie", + "show": "Ukázať", "show_disabled": "Zobraziť vypnuté integrácie" }, "discovered": "Objavené", @@ -2165,6 +2226,7 @@ "add_scene": "Pridať scénu", "delete_confirm": "Naozaj chcete odstrániť túto scénu?", "delete_scene": "Odstrániť scénu", + "duplicate": "Duplikovať", "edit_scene": "Upraviť scénu", "header": "Editor scén", "headers": { @@ -2658,6 +2720,7 @@ "go_back": "Vrátiť sa späť", "supervisor": { "ask": "Požiadať o pomoc", + "observer": "Skontrolujte pozorovateľa", "reboot": "Skúsiť reštartovať hostiteľa", "system_health": "Overiť stav systému", "title": "Nepodarilo sa načítať panel supervízora!", @@ -3293,10 +3356,19 @@ }, "intro": "Ste pripravení prebudiť váš domov, získať vaše súkromie a pripojiť sa k celosvetovej komunite bastličov?", "restore": { + "addons": "Doplnky", + "confirm_password": "Potvrďte heslo zálohy", "description": "Prípadne môžete obnoviť z predchádzajúcej snímky.", + "folders": "Adresáre", + "full_snapshot": "Úplná záloha", "hide_log": "Skryť celý denník", "in_progress": "Prebieha obnovenie", - "show_log": "Zobraziť celý denník" + "partial_snapshot": "Čiastočná záloha", + "password": "Heslo zálohy", + "password_protection": "Ochrana heslom", + "select_type": "Vyberte, čo chcete obnoviť", + "show_log": "Zobraziť celý denník", + "type": "Typ zálohy" }, "user": { "create_account": "Vytvoriť účet", @@ -3382,6 +3454,18 @@ "enable": "Povoliť", "header": "Multifaktorové autentifikačné moduly" }, + "number_format": { + "description": "Vyberte spôsob formátovania čísiel.", + "dropdown_label": "Formát čísla", + "formats": { + "comma_decimal": "1,234,567.89", + "decimal_comma": "1.234.567,89", + "language": "Automaticky (použiť nastavenie jazyka)", + "none": "Žiadny", + "space_comma": "1 234 567,89" + }, + "header": "Formát čísla" + }, "push_notifications": { "description": "Posielať upozornenia na toto zariadenie.", "error_load_platform": "Konfigurujte upozornenia notify.html5.", @@ -3418,6 +3502,14 @@ "primary_color": "Primárna farba", "reset": "Reset" }, + "time_format": { + "dropdown_label": "Formát času", + "formats": { + "12": "12 hodín (AM / PM)", + "24": "24 hodín" + }, + "header": "Formát času" + }, "vibrate": { "description": "Pri ovládaní zariadení povoľte alebo zakážte vibrácie tohto zariadenia.", "header": "Vibrácie" diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index 55f5ee6d20..c78698ffc7 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -318,6 +318,14 @@ "no_addons": "您尚未安装任何加载项。去加载项商店看看吧!" }, "dialog": { + "hardware": { + "attributes": "属性", + "device_path": "设备路径", + "id": "ID", + "search": "搜索硬件", + "subsystem": "子系统", + "title": "硬件" + }, "network": { "connected_to": "已连接到 {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "加载项", "available_snapshots": "可用快照", + "confirm_password": "确认快照密码", "could_not_create": "未能创建快照", "create": "创建", "create_blocked_not_running": "现在无法创建快照,因为系统处于{state}状态。", @@ -409,6 +418,7 @@ "password": "密码", "password_protected": "密码保护", "password_protection": "密码保护", + "passwords_not_matching": "密码不匹配", "security": "安全性", "select_type": "请选择要还原的内容", "selected": "已选择 {number} 项", @@ -3881,10 +3891,19 @@ "intro": "准备好唤醒你的家、找回你的隐私,并加入世界级的极客社区了吗?", "next": "下一步", "restore": { + "addons": "加载项", + "confirm_password": "确认快照密码", "description": "或者,您也可以从以前的快照还原。", + "folders": "文件夹", + "full_snapshot": "完整快照", "hide_log": "隐藏完整日志", "in_progress": "正在还原", - "show_log": "显示完整日志" + "partial_snapshot": "部分快照", + "password": "密码", + "password_protection": "密码保护", + "select_type": "请选择要还原的内容", + "show_log": "显示完整日志", + "type": "类型" }, "user": { "create_account": "创建帐户", diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index 19be965c7e..f76637002b 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -3891,10 +3891,19 @@ "intro": "準備喚醒您的智慧型家庭、取得隱私自主權,並加入由全球愛好者共同維護的社群了嗎?", "next": "下一步", "restore": { + "addons": "附加元件", + "confirm_password": "確認系統備份密碼", "description": "或者可以自之前的 Snapshot 進行回復。", + "folders": "資料夾", + "full_snapshot": "全系統備份", "hide_log": "隱藏完整日誌", "in_progress": "回復進行中", - "show_log": "顯示完整日誌" + "partial_snapshot": "部分系統備份", + "password": "系統備份密碼", + "password_protection": "密碼保護", + "select_type": "選擇所要回復內容", + "show_log": "顯示完整日誌", + "type": "系統備份類型" }, "user": { "create_account": "創建帳號", From 194829f5b169be90a4d5c9ccafd6be46e8bff3cd Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 10 Jun 2021 14:22:44 +0200 Subject: [PATCH 18/73] Generalize map (#9331) * Generalize map * Fix path opacity * Add fitZones --- package.json | 2 - src/common/dom/setup-leaflet-map.ts | 7 +- src/components/map/ha-entity-marker.ts | 69 ++ src/components/map/ha-location-editor.ts | 299 -------- src/components/map/ha-locations-editor.ts | 236 +++---- src/components/map/ha-map.ts | 464 ++++++++----- src/data/zone.ts | 8 - .../more-info/controls/more-info-person.ts | 1 + src/onboarding/onboarding-core-config.ts | 27 +- src/panels/config/core/ha-config-core-form.ts | 47 +- src/panels/config/zone/dialog-zone-detail.ts | 69 +- src/panels/config/zone/ha-config-zone.ts | 24 +- src/panels/logbook/ha-panel-logbook.ts | 2 +- src/panels/lovelace/cards/hui-map-card.ts | 653 +++++------------- .../components/hui-input-list-editor.ts | 8 + .../config-elements/hui-map-card-editor.ts | 2 +- src/panels/map/ha-entity-marker.js | 88 --- src/panels/map/ha-panel-map.js | 263 ------- src/panels/map/ha-panel-map.ts | 103 +++ .../profile/ha-push-notifications-row.js | 1 - src/resources/ha-style.ts | 4 +- yarn.lock | 14 - 22 files changed, 878 insertions(+), 1513 deletions(-) create mode 100644 src/components/map/ha-entity-marker.ts delete mode 100644 src/components/map/ha-location-editor.ts delete mode 100644 src/panels/map/ha-entity-marker.js delete mode 100644 src/panels/map/ha-panel-map.js create mode 100644 src/panels/map/ha-panel-map.ts diff --git a/package.json b/package.json index e54c178377..5e99d75f81 100644 --- a/package.json +++ b/package.json @@ -66,9 +66,7 @@ "@polymer/iron-autogrow-textarea": "^3.0.1", "@polymer/iron-flex-layout": "^3.0.1", "@polymer/iron-icon": "^3.0.1", - "@polymer/iron-image": "^3.0.1", "@polymer/iron-input": "^3.0.1", - "@polymer/iron-label": "^3.0.1", "@polymer/iron-overlay-behavior": "^3.0.2", "@polymer/iron-resizable-behavior": "^3.0.1", "@polymer/paper-checkbox": "^3.1.0", diff --git a/src/common/dom/setup-leaflet-map.ts b/src/common/dom/setup-leaflet-map.ts index 50bc778402..8d0d658f5c 100644 --- a/src/common/dom/setup-leaflet-map.ts +++ b/src/common/dom/setup-leaflet-map.ts @@ -6,8 +6,7 @@ export type LeafletDrawModuleType = typeof import("leaflet-draw"); export const setupLeafletMap = async ( mapElement: HTMLElement, - darkMode?: boolean, - draw = false + darkMode?: boolean ): Promise<[Map, LeafletModuleType, TileLayer]> => { if (!mapElement.parentNode) { throw new Error("Cannot setup Leaflet map on disconnected element"); @@ -17,10 +16,6 @@ export const setupLeafletMap = async ( .default as LeafletModuleType; Leaflet.Icon.Default.imagePath = "/static/images/leaflet/images/"; - if (draw) { - await import("leaflet-draw"); - } - const map = Leaflet.map(mapElement); const style = document.createElement("link"); style.setAttribute("href", "/static/images/leaflet/leaflet.css"); diff --git a/src/components/map/ha-entity-marker.ts b/src/components/map/ha-entity-marker.ts new file mode 100644 index 0000000000..946c9597c7 --- /dev/null +++ b/src/components/map/ha-entity-marker.ts @@ -0,0 +1,69 @@ +import { LitElement, html, css } from "lit"; +import { property } from "lit/decorators"; +import { styleMap } from "lit/directives/style-map"; +import { fireEvent } from "../../common/dom/fire_event"; +import { HomeAssistant } from "../../types"; + +class HaEntityMarker extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: "entity-id" }) public entityId?: string; + + @property({ attribute: "entity-name" }) public entityName?: string; + + @property({ attribute: "entity-picture" }) public entityPicture?: string; + + @property({ attribute: "entity-color" }) public entityColor?: string; + + protected render() { + return html` +
+ ${this.entityPicture + ? html`
` + : this.entityName} +
+ `; + } + + private _badgeTap(ev: Event) { + ev.stopPropagation(); + if (this.entityId) { + fireEvent(this, "hass-more-info", { entityId: this.entityId }); + } + } + + static get styles() { + return css` + .marker { + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; + overflow: hidden; + width: 48px; + height: 48px; + font-size: var(--ha-marker-font-size, 1.5em); + border-radius: 50%; + border: 1px solid var(--ha-marker-color, var(--primary-color)); + color: var(--primary-text-color); + background-color: var(--card-background-color); + } + .entity-picture { + background-size: cover; + height: 100%; + width: 100%; + } + `; + } +} + +customElements.define("ha-entity-marker", HaEntityMarker); diff --git a/src/components/map/ha-location-editor.ts b/src/components/map/ha-location-editor.ts deleted file mode 100644 index 4ee130d52d..0000000000 --- a/src/components/map/ha-location-editor.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { - Circle, - DivIcon, - DragEndEvent, - LatLng, - LeafletMouseEvent, - Map, - Marker, - TileLayer, -} from "leaflet"; -import { - css, - CSSResultGroup, - html, - LitElement, - PropertyValues, - TemplateResult, -} from "lit"; -import { customElement, property } from "lit/decorators"; -import { fireEvent } from "../../common/dom/fire_event"; -import { - LeafletModuleType, - replaceTileLayer, - setupLeafletMap, -} from "../../common/dom/setup-leaflet-map"; -import { nextRender } from "../../common/util/render-status"; -import { defaultRadiusColor } from "../../data/zone"; -import { HomeAssistant } from "../../types"; - -@customElement("ha-location-editor") -class LocationEditor extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ type: Array }) public location?: [number, number]; - - @property({ type: Number }) public radius?: number; - - @property() public radiusColor?: string; - - @property() public icon?: string; - - @property({ type: Boolean }) public darkMode?: boolean; - - public fitZoom = 16; - - private _iconEl?: DivIcon; - - private _ignoreFitToMap?: [number, number]; - - // eslint-disable-next-line - private Leaflet?: LeafletModuleType; - - private _leafletMap?: Map; - - private _tileLayer?: TileLayer; - - private _locationMarker?: Marker | Circle; - - public fitMap(): void { - if (!this._leafletMap || !this.location) { - return; - } - if (this._locationMarker && "getBounds" in this._locationMarker) { - this._leafletMap.fitBounds(this._locationMarker.getBounds()); - } else { - this._leafletMap.setView(this.location, this.fitZoom); - } - this._ignoreFitToMap = this.location; - } - - protected render(): TemplateResult { - return html`
`; - } - - protected firstUpdated(changedProps: PropertyValues): void { - super.firstUpdated(changedProps); - this._initMap(); - } - - protected updated(changedProps: PropertyValues): void { - super.updated(changedProps); - - // Still loading. - if (!this.Leaflet) { - return; - } - - if (changedProps.has("location")) { - this._updateMarker(); - if ( - this.location && - (!this._ignoreFitToMap || - this._ignoreFitToMap[0] !== this.location[0] || - this._ignoreFitToMap[1] !== this.location[1]) - ) { - this.fitMap(); - } - } - if (changedProps.has("radius")) { - this._updateRadius(); - } - if (changedProps.has("radiusColor")) { - this._updateRadiusColor(); - } - if (changedProps.has("icon")) { - this._updateIcon(); - } - - if (changedProps.has("hass")) { - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes.darkMode === this.hass.themes.darkMode) { - return; - } - if (!this._leafletMap || !this._tileLayer) { - return; - } - this._tileLayer = replaceTileLayer( - this.Leaflet, - this._leafletMap, - this._tileLayer, - this.hass.themes.darkMode - ); - } - } - - private get _mapEl(): HTMLDivElement { - return this.shadowRoot!.querySelector("div")!; - } - - private async _initMap(): Promise { - [this._leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap( - this._mapEl, - this.darkMode ?? this.hass.themes.darkMode, - Boolean(this.radius) - ); - this._leafletMap.addEventListener( - "click", - // @ts-ignore - (ev: LeafletMouseEvent) => this._locationUpdated(ev.latlng) - ); - this._updateIcon(); - this._updateMarker(); - this.fitMap(); - this._leafletMap.invalidateSize(); - } - - private _locationUpdated(latlng: LatLng) { - let longitude = latlng.lng; - if (Math.abs(longitude) > 180.0) { - // Normalize longitude if map provides values beyond -180 to +180 degrees. - longitude = (((longitude % 360.0) + 540.0) % 360.0) - 180.0; - } - this.location = this._ignoreFitToMap = [latlng.lat, longitude]; - fireEvent(this, "change", undefined, { bubbles: false }); - } - - private _radiusUpdated() { - this._ignoreFitToMap = this.location; - this.radius = (this._locationMarker as Circle).getRadius(); - fireEvent(this, "change", undefined, { bubbles: false }); - } - - private _updateIcon() { - if (!this.icon) { - this._iconEl = undefined; - return; - } - - // create icon - let iconHTML = ""; - const el = document.createElement("ha-icon"); - el.setAttribute("icon", this.icon); - iconHTML = el.outerHTML; - - this._iconEl = this.Leaflet!.divIcon({ - html: iconHTML, - iconSize: [24, 24], - className: "light leaflet-edit-move", - }); - this._setIcon(); - } - - private _setIcon() { - if (!this._locationMarker || !this._iconEl) { - return; - } - - if (!this.radius) { - (this._locationMarker as Marker).setIcon(this._iconEl); - return; - } - - // @ts-ignore - const moveMarker = this._locationMarker.editing._moveMarker; - moveMarker.setIcon(this._iconEl); - } - - private _setupEdit() { - // @ts-ignore - this._locationMarker.editing.enable(); - // @ts-ignore - const moveMarker = this._locationMarker.editing._moveMarker; - // @ts-ignore - const resizeMarker = this._locationMarker.editing._resizeMarkers[0]; - this._setIcon(); - moveMarker.addEventListener( - "dragend", - // @ts-ignore - (ev: DragEndEvent) => this._locationUpdated(ev.target.getLatLng()) - ); - resizeMarker.addEventListener( - "dragend", - // @ts-ignore - (ev: DragEndEvent) => this._radiusUpdated(ev) - ); - } - - private async _updateMarker(): Promise { - if (!this.location) { - if (this._locationMarker) { - this._locationMarker.remove(); - this._locationMarker = undefined; - } - return; - } - - if (this._locationMarker) { - this._locationMarker.setLatLng(this.location); - if (this.radius) { - // @ts-ignore - this._locationMarker.editing.disable(); - await nextRender(); - this._setupEdit(); - } - return; - } - - if (!this.radius) { - this._locationMarker = this.Leaflet!.marker(this.location, { - draggable: true, - }); - this._setIcon(); - this._locationMarker.addEventListener( - "dragend", - // @ts-ignore - (ev: DragEndEvent) => this._locationUpdated(ev.target.getLatLng()) - ); - this._leafletMap!.addLayer(this._locationMarker); - } else { - this._locationMarker = this.Leaflet!.circle(this.location, { - color: this.radiusColor || defaultRadiusColor, - radius: this.radius, - }); - this._leafletMap!.addLayer(this._locationMarker); - this._setupEdit(); - } - } - - private _updateRadius(): void { - if (!this._locationMarker || !this.radius) { - return; - } - (this._locationMarker as Circle).setRadius(this.radius); - } - - private _updateRadiusColor(): void { - if (!this._locationMarker || !this.radius) { - return; - } - (this._locationMarker as Circle).setStyle({ color: this.radiusColor }); - } - - static get styles(): CSSResultGroup { - return css` - :host { - display: block; - height: 300px; - } - #map { - height: 100%; - background: inherit; - } - .leaflet-edit-move { - border-radius: 50%; - cursor: move !important; - } - .leaflet-edit-resize { - border-radius: 50%; - cursor: nesw-resize !important; - } - `; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-location-editor": LocationEditor; - } -} diff --git a/src/components/map/ha-locations-editor.ts b/src/components/map/ha-locations-editor.ts index b0b8008906..06959e9506 100644 --- a/src/components/map/ha-locations-editor.ts +++ b/src/components/map/ha-locations-editor.ts @@ -3,10 +3,8 @@ import { DivIcon, DragEndEvent, LatLng, - Map, Marker, MarkerOptions, - TileLayer, } from "leaflet"; import { css, @@ -16,15 +14,13 @@ import { PropertyValues, TemplateResult, } from "lit"; -import { customElement, property } from "lit/decorators"; +import { customElement, property, query, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; -import { - LeafletModuleType, - replaceTileLayer, - setupLeafletMap, -} from "../../common/dom/setup-leaflet-map"; -import { defaultRadiusColor } from "../../data/zone"; -import { HomeAssistant } from "../../types"; +import type { LeafletModuleType } from "../../common/dom/setup-leaflet-map"; +import type { HomeAssistant } from "../../types"; +import "./ha-map"; +import type { HaMap } from "./ha-map"; declare global { // for fire event @@ -51,38 +47,40 @@ export interface MarkerLocation { export class HaLocationsEditor extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public locations?: MarkerLocation[]; + @property({ attribute: false }) public locations?: MarkerLocation[]; - public fitZoom = 16; + @property({ type: Boolean }) public autoFit = false; + + @property({ type: Number }) public zoom = 16; + + @property({ type: Boolean }) public darkMode?: boolean; + + @state() private _locationMarkers?: Record; + + @state() private _circles: Record = {}; + + @query("ha-map", true) private map!: HaMap; - // eslint-disable-next-line private Leaflet?: LeafletModuleType; - // eslint-disable-next-line - private _leafletMap?: Map; + constructor() { + super(); - private _tileLayer?: TileLayer; - - private _locationMarkers?: { [key: string]: Marker | Circle }; - - private _circles: Record = {}; + import("leaflet").then((module) => { + import("leaflet-draw").then(() => { + this.Leaflet = module.default as LeafletModuleType; + this._updateMarkers(); + this.updateComplete.then(() => this.fitMap()); + }); + }); + } public fitMap(): void { - if ( - !this._leafletMap || - !this._locationMarkers || - !Object.keys(this._locationMarkers).length - ) { - return; - } - const bounds = this.Leaflet!.latLngBounds( - Object.values(this._locationMarkers).map((item) => item.getLatLng()) - ); - this._leafletMap.fitBounds(bounds.pad(0.5)); + this.map.fitMap(); } public fitMarker(id: string): void { - if (!this._leafletMap || !this._locationMarkers) { + if (!this.map.leafletMap || !this._locationMarkers) { return; } const marker = this._locationMarkers[id]; @@ -90,29 +88,44 @@ export class HaLocationsEditor extends LitElement { return; } if ("getBounds" in marker) { - this._leafletMap.fitBounds(marker.getBounds()); + this.map.leafletMap.fitBounds(marker.getBounds()); (marker as Circle).bringToFront(); } else { const circle = this._circles[id]; if (circle) { - this._leafletMap.fitBounds(circle.getBounds()); + this.map.leafletMap.fitBounds(circle.getBounds()); } else { - this._leafletMap.setView(marker.getLatLng(), this.fitZoom); + this.map.leafletMap.setView(marker.getLatLng(), this.zoom); } } } protected render(): TemplateResult { - return html`
`; + return html``; } - protected firstUpdated(changedProps: PropertyValues): void { - super.firstUpdated(changedProps); - this._initMap(); - } + private _getLayers = memoizeOne( + ( + circles: Record, + markers?: Record + ): Array => { + const layers: Array = []; + Array.prototype.push.apply(layers, Object.values(circles)); + if (markers) { + Array.prototype.push.apply(layers, Object.values(markers)); + } + return layers; + } + ); - protected updated(changedProps: PropertyValues): void { - super.updated(changedProps); + public willUpdate(changedProps: PropertyValues): void { + super.willUpdate(changedProps); // Still loading. if (!this.Leaflet) { @@ -122,37 +135,6 @@ export class HaLocationsEditor extends LitElement { if (changedProps.has("locations")) { this._updateMarkers(); } - - if (changedProps.has("hass")) { - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes.darkMode === this.hass.themes.darkMode) { - return; - } - if (!this._leafletMap || !this._tileLayer) { - return; - } - this._tileLayer = replaceTileLayer( - this.Leaflet, - this._leafletMap, - this._tileLayer, - this.hass.themes.darkMode - ); - } - } - - private get _mapEl(): HTMLDivElement { - return this.shadowRoot!.querySelector("div")!; - } - - private async _initMap(): Promise { - [this._leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap( - this._mapEl, - this.hass.themes.darkMode, - true - ); - this._updateMarkers(); - this.fitMap(); - this._leafletMap.invalidateSize(); } private _updateLocation(ev: DragEndEvent) { @@ -189,21 +171,18 @@ export class HaLocationsEditor extends LitElement { } private _updateMarkers(): void { - if (this._locationMarkers) { - Object.values(this._locationMarkers).forEach((marker) => { - marker.remove(); - }); - this._locationMarkers = undefined; - - Object.values(this._circles).forEach((circle) => circle.remove()); - this._circles = {}; - } - if (!this.locations || !this.locations.length) { + this._circles = {}; + this._locationMarkers = undefined; return; } - this._locationMarkers = {}; + const locationMarkers = {}; + const circles = {}; + + const defaultZoneRadiusColor = getComputedStyle(this).getPropertyValue( + "--accent-color" + ); this.locations.forEach((location: MarkerLocation) => { let icon: DivIcon | undefined; @@ -228,45 +207,46 @@ export class HaLocationsEditor extends LitElement { const circle = this.Leaflet!.circle( [location.latitude, location.longitude], { - color: location.radius_color || defaultRadiusColor, + color: location.radius_color || defaultZoneRadiusColor, radius: location.radius, } ); - circle.addTo(this._leafletMap!); if (location.radius_editable || location.location_editable) { // @ts-ignore circle.editing.enable(); - // @ts-ignore - const moveMarker = circle.editing._moveMarker; - // @ts-ignore - const resizeMarker = circle.editing._resizeMarkers[0]; - if (icon) { - moveMarker.setIcon(icon); - } - resizeMarker.id = moveMarker.id = location.id; - moveMarker - .addEventListener( - "dragend", - // @ts-ignore - (ev: DragEndEvent) => this._updateLocation(ev) - ) - .addEventListener( - "click", - // @ts-ignore - (ev: MouseEvent) => this._markerClicked(ev) - ); - if (location.radius_editable) { - resizeMarker.addEventListener( - "dragend", - // @ts-ignore - (ev: DragEndEvent) => this._updateRadius(ev) - ); - } else { - resizeMarker.remove(); - } - this._locationMarkers![location.id] = circle; + circle.addEventListener("add", () => { + // @ts-ignore + const moveMarker = circle.editing._moveMarker; + // @ts-ignore + const resizeMarker = circle.editing._resizeMarkers[0]; + if (icon) { + moveMarker.setIcon(icon); + } + resizeMarker.id = moveMarker.id = location.id; + moveMarker + .addEventListener( + "dragend", + // @ts-ignore + (ev: DragEndEvent) => this._updateLocation(ev) + ) + .addEventListener( + "click", + // @ts-ignore + (ev: MouseEvent) => this._markerClicked(ev) + ); + if (location.radius_editable) { + resizeMarker.addEventListener( + "dragend", + // @ts-ignore + (ev: DragEndEvent) => this._updateRadius(ev) + ); + } else { + resizeMarker.remove(); + } + }); + locationMarkers[location.id] = circle; } else { - this._circles[location.id] = circle; + circles[location.id] = circle; } } if ( @@ -275,6 +255,7 @@ export class HaLocationsEditor extends LitElement { ) { const options: MarkerOptions = { title: location.name, + draggable: location.location_editable, }; if (icon) { @@ -293,13 +274,14 @@ export class HaLocationsEditor extends LitElement { "click", // @ts-ignore (ev: MouseEvent) => this._markerClicked(ev) - ) - .addTo(this._leafletMap!); + ); (marker as any).id = location.id; - this._locationMarkers![location.id] = marker; + locationMarkers[location.id] = marker; } }); + this._circles = circles; + this._locationMarkers = locationMarkers; } static get styles(): CSSResultGroup { @@ -308,23 +290,9 @@ export class HaLocationsEditor extends LitElement { display: block; height: 300px; } - #map { + ha-map { height: 100%; } - .leaflet-marker-draggable { - cursor: move !important; - } - .leaflet-edit-resize { - border-radius: 50%; - cursor: nesw-resize !important; - } - .named-icon { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - text-align: center; - } `; } } diff --git a/src/components/map/ha-map.ts b/src/components/map/ha-map.ts index fd29d2a268..c34a819d51 100644 --- a/src/components/map/ha-map.ts +++ b/src/components/map/ha-map.ts @@ -1,13 +1,15 @@ -import { Circle, Layer, Map, Marker, TileLayer } from "leaflet"; import { - css, - CSSResultGroup, - html, - LitElement, - PropertyValues, - TemplateResult, -} from "lit"; -import { customElement, property } from "lit/decorators"; + Circle, + CircleMarker, + LatLngTuple, + Layer, + Map, + Marker, + Polyline, + TileLayer, +} from "leaflet"; +import { css, CSSResultGroup, PropertyValues, ReactiveElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { LeafletModuleType, replaceTileLayer, @@ -15,194 +17,324 @@ import { } from "../../common/dom/setup-leaflet-map"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { computeStateName } from "../../common/entity/compute_state_name"; -import { debounce } from "../../common/util/debounce"; -import "../../panels/map/ha-entity-marker"; +import "./ha-entity-marker"; import { HomeAssistant } from "../../types"; import "../ha-icon-button"; +import { installResizeObserver } from "../../panels/lovelace/common/install-resize-observer"; + +const getEntityId = (entity: string | HaMapEntity): string => + typeof entity === "string" ? entity : entity.entity_id; + +export interface HaMapPaths { + points: LatLngTuple[]; + color?: string; + gradualOpacity?: number; +} + +export interface HaMapEntity { + entity_id: string; + color: string; +} @customElement("ha-map") -class HaMap extends LitElement { +export class HaMap extends ReactiveElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public entities?: string[]; + @property({ attribute: false }) public entities?: string[] | HaMapEntity[]; - @property() public darkMode?: boolean; + @property({ attribute: false }) public paths?: HaMapPaths[]; - @property() public zoom?: number; + @property({ attribute: false }) public layers?: Layer[]; + + @property({ type: Boolean }) public autoFit = false; + + @property({ type: Boolean }) public fitZones?: boolean; + + @property({ type: Boolean }) public darkMode?: boolean; + + @property({ type: Number }) public zoom = 14; + + @state() private _loaded = false; + + public leafletMap?: Map; - // eslint-disable-next-line private Leaflet?: LeafletModuleType; - private _leafletMap?: Map; - private _tileLayer?: TileLayer; - // @ts-ignore private _resizeObserver?: ResizeObserver; - private _debouncedResizeListener = debounce( - () => { - if (!this._leafletMap) { - return; - } - this._leafletMap.invalidateSize(); - }, - 100, - false - ); - private _mapItems: Array = []; private _mapZones: Array = []; - private _connected = false; + private _mapPaths: Array = []; public connectedCallback(): void { super.connectedCallback(); - this._connected = true; - if (this.hasUpdated) { - this.loadMap(); - this._attachObserver(); - } + this._loadMap(); + this._attachObserver(); } public disconnectedCallback(): void { super.disconnectedCallback(); - this._connected = false; - - if (this._leafletMap) { - this._leafletMap.remove(); - this._leafletMap = undefined; + if (this.leafletMap) { + this.leafletMap.remove(); + this.leafletMap = undefined; this.Leaflet = undefined; } + this._loaded = false; + if (this._resizeObserver) { - this._resizeObserver.unobserve(this._mapEl); - } else { - window.removeEventListener("resize", this._debouncedResizeListener); + this._resizeObserver.unobserve(this); } } - protected render(): TemplateResult { - if (!this.entities) { - return html``; - } - return html`
`; - } + protected update(changedProps: PropertyValues) { + super.update(changedProps); - protected firstUpdated(changedProps: PropertyValues): void { - super.firstUpdated(changedProps); - this.loadMap(); - - if (this._connected) { - this._attachObserver(); - } - } - - protected shouldUpdate(changedProps) { - if (!changedProps.has("hass") || changedProps.size > 1) { - return true; - } - - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - - if (!oldHass || !this.entities) { - return true; - } - - // Check if any state has changed - for (const entity of this.entities) { - if (oldHass.states[entity] !== this.hass!.states[entity]) { - return true; - } - } - - return false; - } - - protected updated(changedProps: PropertyValues): void { - if (changedProps.has("hass")) { - this._drawEntities(); - this._fitMap(); - - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes.darkMode === this.hass.themes.darkMode) { - return; - } - if (!this.Leaflet || !this._leafletMap || !this._tileLayer) { - return; - } - this._tileLayer = replaceTileLayer( - this.Leaflet, - this._leafletMap, - this._tileLayer, - this.hass.themes.darkMode - ); - } - } - - private get _mapEl(): HTMLDivElement { - return this.shadowRoot!.getElementById("map") as HTMLDivElement; - } - - private async loadMap(): Promise { - [this._leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap( - this._mapEl, - this.darkMode ?? this.hass.themes.darkMode - ); - this._drawEntities(); - this._leafletMap.invalidateSize(); - this._fitMap(); - } - - private _fitMap(): void { - if (!this._leafletMap || !this.Leaflet || !this.hass) { + if (!this._loaded) { return; } - if (this._mapItems.length === 0) { - this._leafletMap.setView( + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + + if (changedProps.has("_loaded") || changedProps.has("entities")) { + this._drawEntities(); + } else if (this._loaded && oldHass && this.entities) { + // Check if any state has changed + for (const entity of this.entities) { + if ( + oldHass.states[getEntityId(entity)] !== + this.hass!.states[getEntityId(entity)] + ) { + this._drawEntities(); + break; + } + } + } + + if (changedProps.has("_loaded") || changedProps.has("paths")) { + this._drawPaths(); + } + + if (changedProps.has("_loaded") || changedProps.has("layers")) { + this._drawLayers(changedProps.get("layers") as Layer[] | undefined); + } + + if ( + changedProps.has("_loaded") || + ((changedProps.has("entities") || changedProps.has("layers")) && + this.autoFit) + ) { + this.fitMap(); + } + + if (changedProps.has("zoom")) { + this.leafletMap!.setZoom(this.zoom); + } + + if ( + !changedProps.has("darkMode") && + (!changedProps.has("hass") || + (oldHass && oldHass.themes.darkMode === this.hass.themes.darkMode)) + ) { + return; + } + const darkMode = this.darkMode ?? this.hass.themes.darkMode; + this._tileLayer = replaceTileLayer( + this.Leaflet!, + this.leafletMap!, + this._tileLayer!, + darkMode + ); + this.shadowRoot!.getElementById("map")!.classList.toggle("dark", darkMode); + } + + private async _loadMap(): Promise { + let map = this.shadowRoot!.getElementById("map"); + if (!map) { + map = document.createElement("div"); + map.id = "map"; + this.shadowRoot!.append(map); + } + const darkMode = this.darkMode ?? this.hass.themes.darkMode; + [this.leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap( + map, + darkMode + ); + this.shadowRoot!.getElementById("map")!.classList.toggle("dark", darkMode); + this._loaded = true; + } + + public fitMap(): void { + if (!this.leafletMap || !this.Leaflet || !this.hass) { + return; + } + + if (!this._mapItems.length && !this.layers?.length) { + this.leafletMap.setView( new this.Leaflet.LatLng( this.hass.config.latitude, this.hass.config.longitude ), - this.zoom || 14 + this.zoom ); return; } - const bounds = this.Leaflet.latLngBounds( + let bounds = this.Leaflet.latLngBounds( this._mapItems ? this._mapItems.map((item) => item.getLatLng()) : [] ); - this._leafletMap.fitBounds(bounds.pad(0.5)); - if (this.zoom && this._leafletMap.getZoom() > this.zoom) { - this._leafletMap.setZoom(this.zoom); + if (this.fitZones) { + this._mapZones?.forEach((zone) => { + bounds.extend( + "getBounds" in zone ? zone.getBounds() : zone.getLatLng() + ); + }); } + + this.layers?.forEach((layer: any) => { + bounds.extend( + "getBounds" in layer ? layer.getBounds() : layer.getLatLng() + ); + }); + + if (!this.layers) { + bounds = bounds.pad(0.5); + } + + this.leafletMap.fitBounds(bounds, { maxZoom: this.zoom }); + } + + private _drawLayers(prevLayers: Layer[] | undefined): void { + if (prevLayers) { + prevLayers.forEach((layer) => layer.remove()); + } + if (!this.layers) { + return; + } + const map = this.leafletMap!; + this.layers.forEach((layer) => { + map.addLayer(layer); + }); + } + + private _drawPaths(): void { + const hass = this.hass; + const map = this.leafletMap; + const Leaflet = this.Leaflet; + + if (!hass || !map || !Leaflet) { + return; + } + if (this._mapPaths.length) { + this._mapPaths.forEach((marker) => marker.remove()); + this._mapPaths = []; + } + if (!this.paths) { + return; + } + + const darkPrimaryColor = getComputedStyle(this).getPropertyValue( + "--dark-primary-color" + ); + + this.paths.forEach((path) => { + let opacityStep: number; + let baseOpacity: number; + if (path.gradualOpacity) { + opacityStep = path.gradualOpacity / (path.points.length - 2); + baseOpacity = 1 - path.gradualOpacity; + } + + for ( + let pointIndex = 0; + pointIndex < path.points.length - 1; + pointIndex++ + ) { + const opacity = path.gradualOpacity + ? baseOpacity! + pointIndex * opacityStep! + : undefined; + + // DRAW point + this._mapPaths.push( + Leaflet!.circleMarker(path.points[pointIndex], { + radius: 3, + color: path.color || darkPrimaryColor, + opacity, + fillOpacity: opacity, + interactive: false, + }) + ); + + // DRAW line between this and next point + this._mapPaths.push( + Leaflet!.polyline( + [path.points[pointIndex], path.points[pointIndex + 1]], + { + color: path.color || darkPrimaryColor, + opacity, + interactive: false, + } + ) + ); + } + const pointIndex = path.points.length - 1; + if (pointIndex >= 0) { + const opacity = path.gradualOpacity + ? baseOpacity! + pointIndex * opacityStep! + : undefined; + // DRAW end path point + this._mapPaths.push( + Leaflet!.circleMarker(path.points[pointIndex], { + radius: 3, + color: path.color || darkPrimaryColor, + opacity, + fillOpacity: opacity, + interactive: false, + }) + ); + } + this._mapPaths.forEach((marker) => map.addLayer(marker)); + }); } private _drawEntities(): void { const hass = this.hass; - const map = this._leafletMap; + const map = this.leafletMap; const Leaflet = this.Leaflet; + if (!hass || !map || !Leaflet) { return; } - if (this._mapItems) { + if (this._mapItems.length) { this._mapItems.forEach((marker) => marker.remove()); + this._mapItems = []; } - const mapItems: Layer[] = (this._mapItems = []); - if (this._mapZones) { + if (this._mapZones.length) { this._mapZones.forEach((marker) => marker.remove()); + this._mapZones = []; } - const mapZones: Layer[] = (this._mapZones = []); - const allEntities = this.entities!.concat(); + if (!this.entities) { + return; + } - for (const entity of allEntities) { - const entityId = entity; - const stateObj = hass.states[entityId]; + const computedStyles = getComputedStyle(this); + const zoneColor = computedStyles.getPropertyValue("--accent-color"); + const darkPrimaryColor = computedStyles.getPropertyValue( + "--dark-primary-color" + ); + + const className = + this.darkMode ?? this.hass.themes.darkMode ? "dark" : "light"; + + for (const entity of this.entities) { + const stateObj = hass.states[getEntityId(entity)]; if (!stateObj) { continue; } @@ -240,13 +372,12 @@ class HaMap extends LitElement { } // create marker with the icon - mapZones.push( + this._mapZones.push( Leaflet.marker([latitude, longitude], { icon: Leaflet.divIcon({ html: iconHTML, iconSize: [24, 24], - className: - this.darkMode ?? this.hass.themes.darkMode ? "dark" : "light", + className, }), interactive: false, title, @@ -254,10 +385,10 @@ class HaMap extends LitElement { ); // create circle around it - mapZones.push( + this._mapZones.push( Leaflet.circle([latitude, longitude], { interactive: false, - color: "#FF9800", + color: zoneColor, radius, }) ); @@ -273,17 +404,20 @@ class HaMap extends LitElement { .join("") .substr(0, 3); - // create market with the icon - mapItems.push( + // create marker with the icon + this._mapItems.push( Leaflet.marker([latitude, longitude], { icon: Leaflet.divIcon({ - // Leaflet clones this element before adding it to the map. This messes up - // our Polymer object and we can't pass data through. Thus we hack like this. html: ` `, iconSize: [48, 48], @@ -295,10 +429,10 @@ class HaMap extends LitElement { // create circle around if entity has accuracy if (gpsAccuracy) { - mapItems.push( + this._mapItems.push( Leaflet.circle([latitude, longitude], { interactive: false, - color: "#0288D1", + color: darkPrimaryColor, radius: gpsAccuracy, }) ); @@ -309,20 +443,14 @@ class HaMap extends LitElement { this._mapZones.forEach((marker) => map.addLayer(marker)); } - private _attachObserver(): void { - // Observe changes to map size and invalidate to prevent broken rendering - // Uses ResizeObserver in Chrome, otherwise window resize event - - // @ts-ignore - if (typeof ResizeObserver === "function") { - // @ts-ignore - this._resizeObserver = new ResizeObserver(() => - this._debouncedResizeListener() - ); - this._resizeObserver.observe(this._mapEl); - } else { - window.addEventListener("resize", this._debouncedResizeListener); + private async _attachObserver(): Promise { + if (!this._resizeObserver) { + await installResizeObserver(); + this._resizeObserver = new ResizeObserver(() => { + this.leafletMap?.invalidateSize({ debounceMoveend: true }); + }); } + this._resizeObserver.observe(this); } static get styles(): CSSResultGroup { @@ -337,13 +465,25 @@ class HaMap extends LitElement { #map.dark { background: #090909; } - + .light { + color: #000000; + } .dark { color: #ffffff; } - - .light { - color: #000000; + .leaflet-marker-draggable { + cursor: move !important; + } + .leaflet-edit-resize { + border-radius: 50%; + cursor: nesw-resize !important; + } + .named-icon { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + text-align: center; } `; } diff --git a/src/data/zone.ts b/src/data/zone.ts index 737ae07dd8..e1c630f020 100644 --- a/src/data/zone.ts +++ b/src/data/zone.ts @@ -1,14 +1,6 @@ import { navigate } from "../common/navigate"; -import { - DEFAULT_ACCENT_COLOR, - DEFAULT_PRIMARY_COLOR, -} from "../resources/ha-style"; import { HomeAssistant } from "../types"; -export const defaultRadiusColor = DEFAULT_ACCENT_COLOR; -export const homeRadiusColor = DEFAULT_PRIMARY_COLOR; -export const passiveRadiusColor = "#9b9b9b"; - export interface Zone { id: string; name: string; diff --git a/src/dialogs/more-info/controls/more-info-person.ts b/src/dialogs/more-info/controls/more-info-person.ts index ea7858de78..1b98b6501b 100644 --- a/src/dialogs/more-info/controls/more-info-person.ts +++ b/src/dialogs/more-info/controls/more-info-person.ts @@ -28,6 +28,7 @@ class MoreInfoPerson extends LitElement { ` : ""} diff --git a/src/onboarding/onboarding-core-config.ts b/src/onboarding/onboarding-core-config.ts index f1bc58a83d..cf330ea87d 100644 --- a/src/onboarding/onboarding-core-config.ts +++ b/src/onboarding/onboarding-core-config.ts @@ -5,9 +5,11 @@ import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import type { LocalizeFunc } from "../common/translations/localize"; -import "../components/map/ha-location-editor"; +import "../components/map/ha-locations-editor"; +import type { MarkerLocation } from "../components/map/ha-locations-editor"; import { createTimezoneListEl } from "../components/timezone-datalist"; import { ConfigUpdateValues, @@ -81,14 +83,14 @@ class OnboardingCoreConfig extends LitElement {
- + @location-updated=${this._locationChanged} + >
@@ -208,13 +210,24 @@ class OnboardingCoreConfig extends LitElement { return this._unitSystem !== undefined ? this._unitSystem : "metric"; } + private _markerLocation = memoizeOne( + (location: [number, number]): MarkerLocation[] => [ + { + id: "location", + latitude: location[0], + longitude: location[1], + location_editable: true, + }, + ] + ); + private _handleChange(ev: PolymerChangedEvent) { const target = ev.currentTarget as PaperInputElement; this[`_${target.name}`] = target.value; } private _locationChanged(ev) { - this._location = ev.currentTarget.location; + this._location = ev.detail.location; } private _unitSystemChanged( diff --git a/src/panels/config/core/ha-config-core-form.ts b/src/panels/config/core/ha-config-core-form.ts index 322c2697c1..2d26def4ce 100644 --- a/src/panels/config/core/ha-config-core-form.ts +++ b/src/panels/config/core/ha-config-core-form.ts @@ -8,7 +8,8 @@ import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { UNIT_C } from "../../../common/const"; import "../../../components/ha-card"; -import "../../../components/map/ha-location-editor"; +import "../../../components/map/ha-locations-editor"; +import type { MarkerLocation } from "../../../components/map/ha-locations-editor"; import { createTimezoneListEl } from "../../../components/timezone-datalist"; import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core"; import type { PolymerChangedEvent } from "../../../polymer-types"; @@ -20,13 +21,13 @@ class ConfigCoreForm extends LitElement { @state() private _working = false; - @state() private _location!: [number, number]; + @state() private _location?: [number, number]; - @state() private _elevation!: string; + @state() private _elevation?: string; - @state() private _unitSystem!: ConfigUpdateValues["unit_system"]; + @state() private _unitSystem?: ConfigUpdateValues["unit_system"]; - @state() private _timeZone!: string; + @state() private _timeZone?: string; protected render(): TemplateResult { const canEdit = ["storage", "default"].includes( @@ -52,16 +53,16 @@ class ConfigCoreForm extends LitElement { : ""}
- + @location-updated=${this._locationChanged} + >
@@ -162,8 +163,19 @@ class ConfigCoreForm extends LitElement { input.inputElement.appendChild(createTimezoneListEl()); } - private _locationValue = memoizeOne( - (location, lat, lng) => location || [Number(lat), Number(lng)] + private _markerLocation = memoizeOne( + ( + lat: number, + lng: number, + location?: [number, number] + ): MarkerLocation[] => [ + { + id: "location", + latitude: location ? location[0] : lat, + longitude: location ? location[1] : lng, + location_editable: true, + }, + ] ); private get _elevationValue() { @@ -192,7 +204,7 @@ class ConfigCoreForm extends LitElement { } private _locationChanged(ev) { - this._location = ev.currentTarget.location; + this._location = ev.detail.location; } private _unitSystemChanged( @@ -204,11 +216,10 @@ class ConfigCoreForm extends LitElement { private async _save() { this._working = true; try { - const location = this._locationValue( - this._location, + const location = this._location || [ this.hass.config.latitude, - this.hass.config.longitude - ); + this.hass.config.longitude, + ]; await saveCoreConfig(this.hass, { latitude: location[0], longitude: location[1], diff --git a/src/panels/config/zone/dialog-zone-detail.ts b/src/panels/config/zone/dialog-zone-detail.ts index ac4cedc32a..f49ab613e3 100644 --- a/src/panels/config/zone/dialog-zone-detail.ts +++ b/src/panels/config/zone/dialog-zone-detail.ts @@ -9,13 +9,9 @@ import { computeRTLDirection } from "../../../common/util/compute_rtl"; import { createCloseHeading } from "../../../components/ha-dialog"; import "../../../components/ha-formfield"; import "../../../components/ha-switch"; -import "../../../components/map/ha-location-editor"; -import { - defaultRadiusColor, - getZoneEditorInitData, - passiveRadiusColor, - ZoneMutableParams, -} from "../../../data/zone"; +import "../../../components/map/ha-locations-editor"; +import type { MarkerLocation } from "../../../components/map/ha-locations-editor"; +import { getZoneEditorInitData, ZoneMutableParams } from "../../../data/zone"; import { haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import { ZoneDetailDialogParams } from "./show-dialog-zone-detail"; @@ -132,17 +128,19 @@ class DialogZoneDetail extends LitElement { )}" .invalid=${iconValid} > - + .locations=${this._location( + this._latitude, + this._longitude, + this._radius, + this._passive, + this._icon + )} + @location-updated=${this._locationChanged} + @radius-updated=${this._radiusChanged} + >
[Number(lat), Number(lng)]); + private _location = memoizeOne( + ( + lat: number, + lng: number, + radius: number, + passive: boolean, + icon: string + ): MarkerLocation[] => { + const computedStyles = getComputedStyle(this); + const zoneRadiusColor = computedStyles.getPropertyValue("--accent-color"); + const passiveRadiusColor = computedStyles.getPropertyValue( + "--secondary-text-color" + ); + return [ + { + id: "location", + latitude: Number(lat), + longitude: Number(lng), + radius, + radius_color: passive ? passiveRadiusColor : zoneRadiusColor, + icon, + location_editable: true, + radius_editable: true, + }, + ]; + } + ); - private _locationChanged(ev) { - [this._latitude, this._longitude] = ev.currentTarget.location; - this._radius = ev.currentTarget.radius; + private _locationChanged(ev: CustomEvent) { + [this._latitude, this._longitude] = ev.detail.location; + } + + private _radiusChanged(ev: CustomEvent) { + this._radius = ev.detail.radius; } private _passiveChanged(ev) { @@ -292,7 +319,7 @@ class DialogZoneDetail extends LitElement { .location > *:last-child { margin-left: 4px; } - ha-location-editor { + ha-locations-editor { margin-top: 16px; } a { diff --git a/src/panels/config/zone/ha-config-zone.ts b/src/panels/config/zone/ha-config-zone.ts index e5f6883d20..ad1526f0bf 100644 --- a/src/panels/config/zone/ha-config-zone.ts +++ b/src/panels/config/zone/ha-config-zone.ts @@ -31,11 +31,8 @@ import { saveCoreConfig } from "../../../data/core"; import { subscribeEntityRegistry } from "../../../data/entity_registry"; import { createZone, - defaultRadiusColor, deleteZone, fetchZones, - homeRadiusColor, - passiveRadiusColor, updateZone, Zone, ZoneMutableParams, @@ -73,6 +70,15 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { private _getZones = memoizeOne( (storageItems: Zone[], stateItems: HassEntity[]): MarkerLocation[] => { + const computedStyles = getComputedStyle(this); + const zoneRadiusColor = computedStyles.getPropertyValue("--accent-color"); + const passiveRadiusColor = computedStyles.getPropertyValue( + "--secondary-text-color" + ); + const homeRadiusColor = computedStyles.getPropertyValue( + "--primary-color" + ); + const stateLocations: MarkerLocation[] = stateItems.map( (entityState) => ({ id: entityState.entity_id, @@ -86,7 +92,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ? homeRadiusColor : entityState.attributes.passive ? passiveRadiusColor - : defaultRadiusColor, + : zoneRadiusColor, location_editable: entityState.entity_id === "zone.home" && this._canEditCore, radius_editable: false, @@ -94,7 +100,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ); const storageLocations: MarkerLocation[] = storageItems.map((zone) => ({ ...zone, - radius_color: zone.passive ? passiveRadiusColor : defaultRadiusColor, + radius_color: zone.passive ? passiveRadiusColor : zoneRadiusColor, location_editable: true, radius_editable: true, })); @@ -274,7 +280,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { } } - protected updated(changedProps: PropertyValues) { + public willUpdate(changedProps: PropertyValues) { super.updated(changedProps); const oldHass = changedProps.get("hass") as HomeAssistant | undefined; if (oldHass && this._stateItems) { @@ -410,8 +416,9 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { if (this.narrow) { return; } - await this.updateComplete; this._activeEntry = created.id; + await this.updateComplete; + await this._map?.updateComplete; this._map?.fitMarker(created.id); } @@ -427,8 +434,9 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { if (this.narrow || !fitMap) { return; } - await this.updateComplete; this._activeEntry = entry.id; + await this.updateComplete; + await this._map?.updateComplete; this._map?.fitMarker(entry.id); } diff --git a/src/panels/logbook/ha-panel-logbook.ts b/src/panels/logbook/ha-panel-logbook.ts index 9c93f077ee..5a6b89ee92 100644 --- a/src/panels/logbook/ha-panel-logbook.ts +++ b/src/panels/logbook/ha-panel-logbook.ts @@ -1,4 +1,5 @@ import { mdiRefresh } from "@mdi/js"; +import "@material/mwc-icon-button"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import { css, html, LitElement, PropertyValues } from "lit"; @@ -9,7 +10,6 @@ import "../../components/entity/ha-entity-picker"; import "../../components/ha-circular-progress"; import "../../components/ha-date-range-picker"; import type { DateRangePickerRanges } from "../../components/ha-date-range-picker"; -import "../../components/ha-icon-button"; import "../../components/ha-menu-button"; import { clearLogbookCache, diff --git a/src/panels/lovelace/cards/hui-map-card.ts b/src/panels/lovelace/cards/hui-map-card.ts index 493ee46823..e6c825d9b9 100644 --- a/src/panels/lovelace/cards/hui-map-card.ts +++ b/src/panels/lovelace/cards/hui-map-card.ts @@ -1,14 +1,5 @@ -import { HassEntity } from "home-assistant-js-websocket"; -import { - Circle, - CircleMarker, - LatLngTuple, - Layer, - Map, - Marker, - Polyline, - TileLayer, -} from "leaflet"; +import { HassEntities, HassEntity } from "home-assistant-js-websocket"; +import { LatLngTuple } from "leaflet"; import { css, CSSResultGroup, @@ -17,32 +8,106 @@ import { PropertyValues, TemplateResult, } from "lit"; -import { customElement, property } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; -import { - LeafletModuleType, - replaceTileLayer, - setupLeafletMap, -} from "../../../common/dom/setup-leaflet-map"; +import { customElement, property, query, state } from "lit/decorators"; import { computeDomain } from "../../../common/entity/compute_domain"; -import { computeStateDomain } from "../../../common/entity/compute_state_domain"; -import { computeStateName } from "../../../common/entity/compute_state_name"; -import { debounce } from "../../../common/util/debounce"; import parseAspectRatio from "../../../common/util/parse-aspect-ratio"; import "../../../components/ha-card"; import "../../../components/ha-icon-button"; import { fetchRecent } from "../../../data/history"; import { HomeAssistant } from "../../../types"; -import "../../map/ha-entity-marker"; +import "../../../components/map/ha-entity-marker"; import { findEntities } from "../common/find-entities"; -import { installResizeObserver } from "../common/install-resize-observer"; import { processConfigEntities } from "../common/process-config-entities"; import { EntityConfig } from "../entity-rows/types"; import { LovelaceCard } from "../types"; import { MapCardConfig } from "./types"; +import "../../../components/map/ha-map"; +import { mdiImageFilterCenterFocus } from "@mdi/js"; +import type { HaMap, HaMapPaths } from "../../../components/map/ha-map"; +import memoizeOne from "memoize-one"; +const MINUTE = 60000; + +const COLORS = [ + "#0288D1", + "#00AA00", + "#984ea3", + "#00d2d5", + "#ff7f00", + "#af8d00", + "#7f80cd", + "#b3e900", + "#c42e60", + "#a65628", + "#f781bf", + "#8dd3c7", +]; @customElement("hui-map-card") class HuiMapCard extends LitElement implements LovelaceCard { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ type: Boolean, reflect: true }) + public isPanel = false; + + @state() + private _history?: HassEntity[][]; + + @state() + private _config?: MapCardConfig; + + @query("ha-map") + private _map?: HaMap; + + private _date?: Date; + + private _configEntities?: string[]; + + private _colorDict: Record = {}; + + private _colorIndex = 0; + + public setConfig(config: MapCardConfig): void { + if (!config) { + throw new Error("Error in card configuration."); + } + + if (!config.entities?.length && !config.geo_location_sources) { + throw new Error( + "Either entities or geo_location_sources must be specified" + ); + } + if (config.entities && !Array.isArray(config.entities)) { + throw new Error("Entities need to be an array"); + } + if ( + config.geo_location_sources && + !Array.isArray(config.geo_location_sources) + ) { + throw new Error("Geo_location_sources needs to be an array"); + } + + this._config = config; + this._configEntities = (config.entities + ? processConfigEntities(config.entities) + : [] + ).map((entity) => entity.entity); + + this._cleanupHistory(); + } + + public getCardSize(): number { + if (!this._config?.aspect_ratio) { + return 7; + } + + const ratio = parseAspectRatio(this._config.aspect_ratio); + const ar = + ratio && ratio.w > 0 && ratio.h > 0 + ? `${((100 * ratio.h) / ratio.w).toFixed(2)}` + : "100"; + return 1 + Math.floor(Number(ar) / 25) || 3; + } + public static async getConfigElement() { await import("../editor/config-elements/hui-map-card-editor"); return document.createElement("hui-map-card-editor"); @@ -66,129 +131,6 @@ class HuiMapCard extends LitElement implements LovelaceCard { return { type: "map", entities: foundEntities }; } - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ type: Boolean, reflect: true }) - public isPanel = false; - - @property() - private _history?: HassEntity[][]; - - private _date?: Date; - - @property() - private _config?: MapCardConfig; - - private _configEntities?: EntityConfig[]; - - // eslint-disable-next-line - private Leaflet?: LeafletModuleType; - - private _leafletMap?: Map; - - private _tileLayer?: TileLayer; - - private _resizeObserver?: ResizeObserver; - - private _debouncedResizeListener = debounce( - () => { - if (!this.isConnected || !this._leafletMap) { - return; - } - this._leafletMap.invalidateSize(); - }, - 250, - false - ); - - private _mapItems: Array = []; - - private _mapZones: Array = []; - - private _mapPaths: Array = []; - - private _colorDict: Record = {}; - - private _colorIndex = 0; - - private _colors: string[] = [ - "#0288D1", - "#00AA00", - "#984ea3", - "#00d2d5", - "#ff7f00", - "#af8d00", - "#7f80cd", - "#b3e900", - "#c42e60", - "#a65628", - "#f781bf", - "#8dd3c7", - ]; - - public setConfig(config: MapCardConfig): void { - if (!config) { - throw new Error("Error in card configuration."); - } - - if (!config.entities?.length && !config.geo_location_sources) { - throw new Error( - "Either entities or geo_location_sources must be specified" - ); - } - if (config.entities && !Array.isArray(config.entities)) { - throw new Error("Entities need to be an array"); - } - if ( - config.geo_location_sources && - !Array.isArray(config.geo_location_sources) - ) { - throw new Error("Geo_location_sources needs to be an array"); - } - - this._config = config; - this._configEntities = config.entities - ? processConfigEntities(config.entities) - : []; - - this._cleanupHistory(); - } - - public getCardSize(): number { - if (!this._config?.aspect_ratio) { - return 7; - } - - const ratio = parseAspectRatio(this._config.aspect_ratio); - const ar = - ratio && ratio.w > 0 && ratio.h > 0 - ? `${((100 * ratio.h) / ratio.w).toFixed(2)}` - : "100"; - return 1 + Math.floor(Number(ar) / 25) || 3; - } - - public connectedCallback(): void { - super.connectedCallback(); - this._attachObserver(); - if (this.hasUpdated) { - this.loadMap(); - } - } - - public disconnectedCallback(): void { - super.disconnectedCallback(); - - if (this._leafletMap) { - this._leafletMap.remove(); - this._leafletMap = undefined; - this.Leaflet = undefined; - } - - if (this._resizeObserver) { - this._resizeObserver.unobserve(this._mapEl); - } - } - protected render(): TemplateResult { if (!this._config) { return html``; @@ -196,22 +138,29 @@ class HuiMapCard extends LitElement implements LovelaceCard { return html`
-
- + + > + +
`; } - protected shouldUpdate(changedProps) { + protected shouldUpdate(changedProps: PropertyValues) { if (!changedProps.has("hass") || changedProps.size > 1) { return true; } @@ -228,7 +177,7 @@ class HuiMapCard extends LitElement implements LovelaceCard { // Check if any state has changed for (const entity of this._configEntities) { - if (oldHass.states[entity.entity] !== this.hass!.states[entity.entity]) { + if (oldHass.states[entity] !== this.hass!.states[entity]) { return true; } } @@ -238,17 +187,12 @@ class HuiMapCard extends LitElement implements LovelaceCard { protected firstUpdated(changedProps: PropertyValues): void { super.firstUpdated(changedProps); - if (this.isConnected) { - this.loadMap(); - } const root = this.shadowRoot!.getElementById("root"); if (!this._config || this.isPanel || !root) { return; } - this._attachObserver(); - if (!this._config.aspect_ratio) { root.style.paddingBottom = "100%"; return; @@ -263,172 +207,86 @@ class HuiMapCard extends LitElement implements LovelaceCard { } protected updated(changedProps: PropertyValues): void { - if (changedProps.has("hass") || changedProps.has("_history")) { - this._drawEntities(); - this._fitMap(); - } - if (changedProps.has("hass")) { - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (oldHass && oldHass.themes.darkMode !== this.hass.themes.darkMode) { - this._replaceTileLayer(); - } - } - if ( - changedProps.has("_config") && - changedProps.get("_config") !== undefined - ) { - this.updateMap(changedProps.get("_config") as MapCardConfig); - } - if (this._config?.hours_to_show && this._configEntities?.length) { - const minute = 60000; if (changedProps.has("_config")) { this._getHistory(); - } else if (Date.now() - this._date!.getTime() >= minute) { + } else if (Date.now() - this._date!.getTime() >= MINUTE) { this._getHistory(); } } } - private get _mapEl(): HTMLDivElement { - return this.shadowRoot!.getElementById("map") as HTMLDivElement; + private _fitMap() { + this._map?.fitMap(); } - private async loadMap(): Promise { - [this._leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap( - this._mapEl, - this._config!.dark_mode ?? this.hass.themes.darkMode - ); - this._drawEntities(); - this._leafletMap.invalidateSize(); - this._fitMap(); - } - - private _replaceTileLayer() { - const map = this._leafletMap; - const config = this._config; - const Leaflet = this.Leaflet; - if (!map || !config || !Leaflet || !this._tileLayer) { - return; - } - this._tileLayer = replaceTileLayer( - Leaflet, - map, - this._tileLayer, - this._config!.dark_mode ?? this.hass.themes.darkMode - ); - } - - private updateMap(oldConfig: MapCardConfig): void { - const map = this._leafletMap; - const config = this._config; - const Leaflet = this.Leaflet; - if (!map || !config || !Leaflet || !this._tileLayer) { - return; - } - if (this._config!.dark_mode !== oldConfig.dark_mode) { - this._replaceTileLayer(); - } - if ( - config.entities !== oldConfig.entities || - config.geo_location_sources !== oldConfig.geo_location_sources - ) { - this._drawEntities(); - } - map.invalidateSize(); - this._fitMap(); - } - - private _fitMap(): void { - if (!this._leafletMap || !this.Leaflet || !this._config || !this.hass) { - return; - } - const zoom = this._config.default_zoom; - if (this._mapItems.length === 0) { - this._leafletMap.setView( - new this.Leaflet.LatLng( - this.hass.config.latitude, - this.hass.config.longitude - ), - zoom || 14 - ); - return; - } - - const bounds = this.Leaflet.featureGroup(this._mapItems).getBounds(); - this._leafletMap.fitBounds(bounds.pad(0.5)); - - if (zoom && this._leafletMap.getZoom() > zoom) { - this._leafletMap.setZoom(zoom); - } - } - - private _getColor(entityId: string) { - let color; - if (this._colorDict[entityId]) { - color = this._colorDict[entityId]; - } else { - color = this._colors[this._colorIndex]; - this._colorIndex = (this._colorIndex + 1) % this._colors.length; - this._colorDict[entityId] = color; + private _getColor(entityId: string): string { + let color = this._colorDict[entityId]; + if (color) { + return color; } + color = COLORS[this._colorIndex % COLORS.length]; + this._colorIndex++; + this._colorDict[entityId] = color; return color; } - private _drawEntities(): void { - const hass = this.hass; - const map = this._leafletMap; - const config = this._config; - const Leaflet = this.Leaflet; - if (!hass || !map || !config || !Leaflet) { - return; - } - - if (this._mapItems) { - this._mapItems.forEach((marker) => marker.remove()); - } - const mapItems: Layer[] = (this._mapItems = []); - - if (this._mapZones) { - this._mapZones.forEach((marker) => marker.remove()); - } - const mapZones: Layer[] = (this._mapZones = []); - - if (this._mapPaths) { - this._mapPaths.forEach((marker) => marker.remove()); - } - const mapPaths: Layer[] = (this._mapPaths = []); - - const allEntities = this._configEntities!.concat(); - - // Calculate visible geo location sources - if (config.geo_location_sources) { - const includesAll = config.geo_location_sources.includes("all"); - for (const entityId of Object.keys(hass.states)) { - const stateObj = hass.states[entityId]; - if ( - computeDomain(entityId) === "geo_location" && - (includesAll || - config.geo_location_sources.includes(stateObj.attributes.source)) - ) { - allEntities.push({ entity: entityId }); - } + private _getEntities = memoizeOne( + ( + states: HassEntities, + config: MapCardConfig, + configEntities?: string[] + ) => { + if (!states || !config) { + return undefined; } - } - // DRAW history - if (this._config!.hours_to_show && this._history) { - for (const entityStates of this._history) { + let entities = configEntities || []; + + if (config.geo_location_sources) { + const geoEntities: string[] = []; + // Calculate visible geo location sources + const includesAll = config.geo_location_sources.includes("all"); + for (const stateObj of Object.values(states)) { + if ( + computeDomain(stateObj.entity_id) === "geo_location" && + (includesAll || + config.geo_location_sources.includes(stateObj.attributes.source)) + ) { + geoEntities.push(stateObj.entity_id); + } + } + + entities = [...entities, ...geoEntities]; + } + + return entities.map((entity) => ({ + entity_id: entity, + color: this._getColor(entity), + })); + } + ); + + private _getHistoryPaths = memoizeOne( + ( + config: MapCardConfig, + history?: HassEntity[][] + ): HaMapPaths[] | undefined => { + if (!config.hours_to_show || !history) { + return undefined; + } + + const paths: HaMapPaths[] = []; + + for (const entityStates of history) { if (entityStates?.length <= 1) { continue; } - const entityId = entityStates[0].entity_id; - // filter location data from states and remove all invalid locations - const path = entityStates.reduce( - (accumulator: LatLngTuple[], state) => { - const latitude = state.attributes.latitude; - const longitude = state.attributes.longitude; + const points = entityStates.reduce( + (accumulator: LatLngTuple[], entityState) => { + const latitude = entityState.attributes.latitude; + const longitude = entityState.attributes.longitude; if (latitude && longitude) { accumulator.push([latitude, longitude] as LatLngTuple); } @@ -437,162 +295,15 @@ class HuiMapCard extends LitElement implements LovelaceCard { [] ) as LatLngTuple[]; - // DRAW HISTORY - for ( - let markerIndex = 0; - markerIndex < path.length - 1; - markerIndex++ - ) { - const opacityStep = 0.8 / (path.length - 2); - const opacity = 0.2 + markerIndex * opacityStep; - - // DRAW history path dots - mapPaths.push( - Leaflet.circleMarker(path[markerIndex], { - radius: 3, - color: this._getColor(entityId), - opacity, - interactive: false, - }) - ); - - // DRAW history path lines - const line = [path[markerIndex], path[markerIndex + 1]]; - mapPaths.push( - Leaflet.polyline(line, { - color: this._getColor(entityId), - opacity, - interactive: false, - }) - ); - } + paths.push({ + points, + color: this._getColor(entityStates[0].entity_id), + gradualOpacity: 0.8, + }); } + return paths; } - - // DRAW entities - for (const entity of allEntities) { - const entityId = entity.entity; - const stateObj = hass.states[entityId]; - if (!stateObj) { - continue; - } - const title = computeStateName(stateObj); - const { - latitude, - longitude, - passive, - icon, - radius, - entity_picture: entityPicture, - gps_accuracy: gpsAccuracy, - } = stateObj.attributes; - - if (!(latitude && longitude)) { - continue; - } - - if (computeStateDomain(stateObj) === "zone") { - // DRAW ZONE - if (passive) { - continue; - } - - // create icon - let iconHTML = ""; - if (icon) { - const el = document.createElement("ha-icon"); - el.setAttribute("icon", icon); - iconHTML = el.outerHTML; - } else { - const el = document.createElement("span"); - el.innerHTML = title; - iconHTML = el.outerHTML; - } - - // create marker with the icon - mapZones.push( - Leaflet.marker([latitude, longitude], { - icon: Leaflet.divIcon({ - html: iconHTML, - iconSize: [24, 24], - className: this._config!.dark_mode - ? "dark" - : this._config!.dark_mode === false - ? "light" - : "", - }), - interactive: false, - title, - }) - ); - - // create circle around it - mapZones.push( - Leaflet.circle([latitude, longitude], { - interactive: false, - color: "#FF9800", - radius, - }) - ); - - continue; - } - - // DRAW ENTITY - // create icon - const entityName = title - .split(" ") - .map((part) => part[0]) - .join("") - .substr(0, 3); - - // create market with the icon - mapItems.push( - Leaflet.marker([latitude, longitude], { - icon: Leaflet.divIcon({ - // Leaflet clones this element before adding it to the map. This messes up - // our Polymer object and we can't pass data through. Thus we hack like this. - html: ` - - `, - iconSize: [48, 48], - className: "", - }), - title: computeStateName(stateObj), - }) - ); - - // create circle around if entity has accuracy - if (gpsAccuracy) { - mapItems.push( - Leaflet.circle([latitude, longitude], { - interactive: false, - color: this._getColor(entityId), - radius: gpsAccuracy, - }) - ); - } - } - - this._mapItems.forEach((marker) => map.addLayer(marker)); - this._mapZones.forEach((marker) => map.addLayer(marker)); - this._mapPaths.forEach((marker) => map.addLayer(marker)); - } - - private async _attachObserver(): Promise { - // Observe changes to map size and invalidate to prevent broken rendering - - if (!this._resizeObserver) { - await installResizeObserver(); - this._resizeObserver = new ResizeObserver(this._debouncedResizeListener); - } - this._resizeObserver.observe(this); - } + ); private async _getHistory(): Promise { this._date = new Date(); @@ -601,9 +312,7 @@ class HuiMapCard extends LitElement implements LovelaceCard { return; } - const entityIds = this._configEntities!.map((entity) => entity.entity).join( - "," - ); + const entityIds = this._configEntities!.join(","); const endTime = new Date(); const startTime = new Date(); startTime.setHours(endTime.getHours() - this._config!.hours_to_show!); @@ -624,7 +333,6 @@ class HuiMapCard extends LitElement implements LovelaceCard { if (stateHistory.length < 1) { return; } - this._history = stateHistory; } @@ -636,13 +344,10 @@ class HuiMapCard extends LitElement implements LovelaceCard { this._history = undefined; } else { // remove unused entities - const configEntityIds = this._configEntities?.map( - (configEntity) => configEntity.entity - ); this._history = this._history!.reduce( (accumulator: HassEntity[][], entityStates) => { const entityId = entityStates[0].entity_id; - if (configEntityIds?.includes(entityId)) { + if (this._configEntities?.includes(entityId)) { accumulator.push(entityStates); } return accumulator; @@ -660,7 +365,7 @@ class HuiMapCard extends LitElement implements LovelaceCard { height: 100%; } - #map { + ha-map { z-index: 0; border: none; position: absolute; @@ -671,7 +376,7 @@ class HuiMapCard extends LitElement implements LovelaceCard { background: inherit; } - ha-icon-button { + mwc-icon-button { position: absolute; top: 75px; left: 3px; @@ -685,14 +390,6 @@ class HuiMapCard extends LitElement implements LovelaceCard { :host([ispanel]) #root { height: 100%; } - - .dark { - color: #ffffff; - } - - .light { - color: #000000; - } `; } } diff --git a/src/panels/lovelace/components/hui-input-list-editor.ts b/src/panels/lovelace/components/hui-input-list-editor.ts index ae64dea7b7..ea92b47553 100644 --- a/src/panels/lovelace/components/hui-input-list-editor.ts +++ b/src/panels/lovelace/components/hui-input-list-editor.ts @@ -29,6 +29,7 @@ export class HuiInputListEditor extends LitElement { .index=${index} @value-changed=${this._valueChanged} @blur=${this._consolidateEntries} + @keydown=${this._handleKeyDown} > - - -
- - -
- `; - } - - static get properties() { - return { - hass: { - type: Object, - }, - - entityId: { - type: String, - value: "", - }, - - entityName: { - type: String, - value: null, - }, - - entityPicture: { - type: String, - value: null, - }, - - entityColor: { - type: String, - value: null, - }, - }; - } - - ready() { - super.ready(); - this.addEventListener("click", (ev) => this.badgeTap(ev)); - } - - badgeTap(ev) { - ev.stopPropagation(); - if (this.entityId) { - this.fire("hass-more-info", { entityId: this.entityId }); - } - } -} - -customElements.define("ha-entity-marker", HaEntityMarker); diff --git a/src/panels/map/ha-panel-map.js b/src/panels/map/ha-panel-map.js deleted file mode 100644 index 108c984765..0000000000 --- a/src/panels/map/ha-panel-map.js +++ /dev/null @@ -1,263 +0,0 @@ -import "@polymer/app-layout/app-toolbar/app-toolbar"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { - replaceTileLayer, - setupLeafletMap, -} from "../../common/dom/setup-leaflet-map"; -import { computeStateDomain } from "../../common/entity/compute_state_domain"; -import { computeStateName } from "../../common/entity/compute_state_name"; -import { navigate } from "../../common/navigate"; -import "../../components/ha-icon"; -import "../../components/ha-menu-button"; -import { defaultRadiusColor } from "../../data/zone"; -import "../../layouts/ha-app-layout"; -import LocalizeMixin from "../../mixins/localize-mixin"; -import "../../styles/polymer-ha-style"; -import "./ha-entity-marker"; - -/* - * @appliesMixin LocalizeMixin - */ -class HaPanelMap extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - - - - - - -
[[localize('panel.map')]]
- -
-
-
-
- `; - } - - static get properties() { - return { - hass: { - type: Object, - observer: "drawEntities", - }, - narrow: Boolean, - }; - } - - connectedCallback() { - super.connectedCallback(); - this.loadMap(); - } - - async loadMap() { - this._darkMode = this.hass.themes.darkMode; - [this._map, this.Leaflet, this._tileLayer] = await setupLeafletMap( - this.$.map, - this._darkMode - ); - this.drawEntities(this.hass); - this._map.invalidateSize(); - this.fitMap(); - } - - disconnectedCallback() { - if (this._map) { - this._map.remove(); - } - } - - computeShowEditZone(hass) { - return !__DEMO__ && hass.user.is_admin; - } - - openZonesEditor() { - navigate("/config/zone"); - } - - fitMap() { - let bounds; - - if (this._mapItems.length === 0) { - this._map.setView( - new this.Leaflet.LatLng( - this.hass.config.latitude, - this.hass.config.longitude - ), - 14 - ); - } else { - bounds = new this.Leaflet.latLngBounds( - this._mapItems.map((item) => item.getLatLng()) - ); - this._map.fitBounds(bounds.pad(0.5)); - } - } - - drawEntities(hass) { - /* eslint-disable vars-on-top */ - const map = this._map; - if (!map) return; - - if (this._darkMode !== this.hass.themes.darkMode) { - this._darkMode = this.hass.themes.darkMode; - this._tileLayer = replaceTileLayer( - this.Leaflet, - map, - this._tileLayer, - this.hass.themes.darkMode - ); - } - - if (this._mapItems) { - this._mapItems.forEach(function (marker) { - marker.remove(); - }); - } - const mapItems = (this._mapItems = []); - - if (this._mapZones) { - this._mapZones.forEach(function (marker) { - marker.remove(); - }); - } - const mapZones = (this._mapZones = []); - - Object.keys(hass.states).forEach((entityId) => { - const entity = hass.states[entityId]; - - if ( - entity.state === "home" || - !("latitude" in entity.attributes) || - !("longitude" in entity.attributes) - ) { - return; - } - - const title = computeStateName(entity); - let icon; - - if (computeStateDomain(entity) === "zone") { - // DRAW ZONE - if (entity.attributes.passive) return; - - // create icon - let iconHTML = ""; - if (entity.attributes.icon) { - const el = document.createElement("ha-icon"); - el.setAttribute("icon", entity.attributes.icon); - iconHTML = el.outerHTML; - } else { - const el = document.createElement("span"); - el.innerHTML = title; - iconHTML = el.outerHTML; - } - - icon = this.Leaflet.divIcon({ - html: iconHTML, - iconSize: [24, 24], - className: "icon", - }); - - // create marker with the icon - mapZones.push( - this.Leaflet.marker( - [entity.attributes.latitude, entity.attributes.longitude], - { - icon: icon, - interactive: false, - title: title, - } - ).addTo(map) - ); - - // create circle around it - mapZones.push( - this.Leaflet.circle( - [entity.attributes.latitude, entity.attributes.longitude], - { - interactive: false, - color: defaultRadiusColor, - radius: entity.attributes.radius, - } - ).addTo(map) - ); - - return; - } - - // DRAW ENTITY - // create icon - const entityPicture = entity.attributes.entity_picture || ""; - const entityName = title - .split(" ") - .map(function (part) { - return part.substr(0, 1); - }) - .join(""); - /* Leaflet clones this element before adding it to the map. This messes up - our Polymer object and we can't pass data through. Thus we hack like this. */ - icon = this.Leaflet.divIcon({ - html: - "", - iconSize: [45, 45], - className: "", - }); - - // create market with the icon - mapItems.push( - this.Leaflet.marker( - [entity.attributes.latitude, entity.attributes.longitude], - { - icon: icon, - title: computeStateName(entity), - } - ).addTo(map) - ); - - // create circle around if entity has accuracy - if (entity.attributes.gps_accuracy) { - mapItems.push( - this.Leaflet.circle( - [entity.attributes.latitude, entity.attributes.longitude], - { - interactive: false, - color: "#0288D1", - radius: entity.attributes.gps_accuracy, - } - ).addTo(map) - ); - } - }); - } -} - -customElements.define("ha-panel-map", HaPanelMap); diff --git a/src/panels/map/ha-panel-map.ts b/src/panels/map/ha-panel-map.ts new file mode 100644 index 0000000000..d391668c9d --- /dev/null +++ b/src/panels/map/ha-panel-map.ts @@ -0,0 +1,103 @@ +import { mdiPencil } from "@mdi/js"; +import "@material/mwc-icon-button"; +import "@polymer/app-layout/app-toolbar/app-toolbar"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { property } from "lit/decorators"; +import { computeStateDomain } from "../../common/entity/compute_state_domain"; +import { navigate } from "../../common/navigate"; +import "../../components/ha-svg-icon"; +import "../../components/ha-menu-button"; +import "../../layouts/ha-app-layout"; +import { HomeAssistant } from "../../types"; +import "../../components/map/ha-map"; +import { haStyle } from "../../resources/styles"; + +class HaPanelMap extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ type: Boolean }) public narrow!: boolean; + + private _entities: string[] = []; + + protected render() { + return html` + + + + +
${this.hass.localize("panel.map")}
+ ${!__DEMO__ && this.hass.user?.is_admin + ? html`` + : ""} +
+
+ +
+ `; + } + + private _openZonesEditor() { + navigate("/config/zone"); + } + + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); + if (!changedProps.has("hass")) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + this._getStates(oldHass); + } + + private _getStates(oldHass?: HomeAssistant) { + let changed = false; + const personSources = new Set(); + const locationEntities: string[] = []; + Object.values(this.hass!.states).forEach((entity) => { + if ( + entity.state === "home" || + !("latitude" in entity.attributes) || + !("longitude" in entity.attributes) + ) { + return; + } + locationEntities.push(entity.entity_id); + if (computeStateDomain(entity) === "person" && entity.attributes.source) { + personSources.add(entity.attributes.source); + } + if (oldHass?.states[entity.entity_id] !== entity) { + changed = true; + } + }); + + if (changed) { + this._entities = locationEntities.filter( + (entity) => !personSources.has(entity) + ); + } + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + css` + ha-map { + height: calc(100vh - var(--header-height)); + } + `, + ]; + } +} + +customElements.define("ha-panel-map", HaPanelMap); + +declare global { + interface HTMLElementTagNameMap { + "ha-panel-map": HaPanelMap; + } +} diff --git a/src/panels/profile/ha-push-notifications-row.js b/src/panels/profile/ha-push-notifications-row.js index 429173ffd2..69f2e54246 100644 --- a/src/panels/profile/ha-push-notifications-row.js +++ b/src/panels/profile/ha-push-notifications-row.js @@ -1,5 +1,4 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import "@polymer/iron-label/iron-label"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts index f3e9dcb757..82439c105e 100644 --- a/src/resources/ha-style.ts +++ b/src/resources/ha-style.ts @@ -29,10 +29,10 @@ documentContainer.innerHTML = ` --disabled-text-color: #bdbdbd; /* main interface colors */ - --primary-color: #03a9f4; + --primary-color: ${DEFAULT_PRIMARY_COLOR}; --dark-primary-color: #0288d1; --light-primary-color: #b3e5fC; - --accent-color: #ff9800; + --accent-color: ${DEFAULT_ACCENT_COLOR}; --divider-color: rgba(0, 0, 0, .12); --scrollbar-thumb-color: rgb(194, 194, 194); diff --git a/yarn.lock b/yarn.lock index 8fd9b8db50..eae3bc00de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2104,13 +2104,6 @@ "@polymer/iron-meta" "^3.0.0-pre.26" "@polymer/polymer" "^3.0.0" -"@polymer/iron-image@^3.0.1": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@polymer/iron-image/-/iron-image-3.0.2.tgz#425ee6269634e024dbea726a91a61724ae4402b6" - integrity sha512-VyYtnewGozDb5sUeoLR1OvKzlt5WAL6b8Od7fPpio5oYL+9t061/nTV8+ZMrpMgF2WgB0zqM/3K53o3pbK5v8Q== - dependencies: - "@polymer/polymer" "^3.0.0" - "@polymer/iron-input@^3.0.0-pre.26", "@polymer/iron-input@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@polymer/iron-input/-/iron-input-3.0.1.tgz#dc866a25107f9b38d9ca4512dd9a3e51b78b4915" @@ -2120,13 +2113,6 @@ "@polymer/iron-validatable-behavior" "^3.0.0-pre.26" "@polymer/polymer" "^3.0.0" -"@polymer/iron-label@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@polymer/iron-label/-/iron-label-3.0.1.tgz#170247dc50d63f4e2ae6c80711dbf5b64fa953d6" - integrity sha512-MkIZ1WfOy10pnIxRwTVPfsoDZYlqMkUp0hmimMj0pGRHmrc9n5phuJUY1pC+S7WoKP1/98iH2qnXQukPGTzoVA== - dependencies: - "@polymer/polymer" "^3.0.0" - "@polymer/iron-list@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@polymer/iron-list/-/iron-list-3.0.2.tgz#9e6b80e503328dc29217dbe26f94faa47adb4124" From 3d6674325c01b5a9ad7aafa6bd156370a8136221 Mon Sep 17 00:00:00 2001 From: Shane Qi Date: Thu, 10 Jun 2021 07:51:24 -0500 Subject: [PATCH 19/73] Fix the issue that logbook card doesn't translate `context.user_id` to name if it's a user's id. (#9383) Co-authored-by: Bram Kragten --- src/dialogs/more-info/ha-more-info-logbook.ts | 32 +++++++++-- src/panels/logbook/ha-panel-logbook.ts | 32 +++++------ src/panels/lovelace/cards/hui-logbook-card.ts | 56 +++++++++++++------ 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index 3a307e9370..4f3e89b3a9 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -5,6 +5,7 @@ import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { throttle } from "../../common/util/throttle"; import "../../components/ha-circular-progress"; import "../../components/state-history-charts"; +import { fetchUsers } from "../../data/user"; import { getLogbookData, LogbookEntry } from "../../data/logbook"; import { loadTraceContexts, TraceContexts } from "../../data/trace"; import "../../panels/logbook/ha-logbook"; @@ -22,10 +23,12 @@ export class MoreInfoLogbook extends LitElement { @state() private _traceContexts?: TraceContexts; - @state() private _persons = {}; + @state() private _userIdToName = {}; private _lastLogbookDate?: Date; + private _fetchUserPromise?: Promise; + private _throttleGetLogbookEntries = throttle(() => { this._getLogBookData(); }, 10000); @@ -59,7 +62,7 @@ export class MoreInfoLogbook extends LitElement { .hass=${this.hass} .entries=${this._logbookEntries} .traceContexts=${this._traceContexts} - .userIdToName=${this._persons} + .userIdToName=${this._userIdToName} > ` : html`
@@ -70,7 +73,7 @@ export class MoreInfoLogbook extends LitElement { } protected firstUpdated(): void { - this._fetchPersonNames(); + this._fetchUserPromise = this._fetchUserNames(); this.addEventListener("click", (ev) => { if ((ev.composedPath()[0] as HTMLElement).tagName === "A") { setTimeout(() => closeDialog("ha-more-info-dialog"), 500); @@ -125,6 +128,7 @@ export class MoreInfoLogbook extends LitElement { true ), loadTraceContexts(this.hass), + this._fetchUserPromise, ]); this._logbookEntries = this._logbookEntries ? [...newEntries, ...this._logbookEntries] @@ -133,16 +137,34 @@ export class MoreInfoLogbook extends LitElement { this._traceContexts = traceContexts; } - private _fetchPersonNames() { + private async _fetchUserNames() { + const userIdToName = {}; + + // Start loading users + const userProm = this.hass.user?.is_admin && fetchUsers(this.hass); + + // Process persons Object.values(this.hass.states).forEach((entity) => { if ( entity.attributes.user_id && computeStateDomain(entity) === "person" ) { - this._persons[entity.attributes.user_id] = + this._userIdToName[entity.attributes.user_id] = entity.attributes.friendly_name; } }); + + // Process users + if (userProm) { + const users = await userProm; + for (const user of users) { + if (!(user.id in userIdToName)) { + userIdToName[user.id] = user.name; + } + } + } + + this._userIdToName = userIdToName; } static get styles() { diff --git a/src/panels/logbook/ha-panel-logbook.ts b/src/panels/logbook/ha-panel-logbook.ts index 5a6b89ee92..aa5aab7245 100644 --- a/src/panels/logbook/ha-panel-logbook.ts +++ b/src/panels/logbook/ha-panel-logbook.ts @@ -5,6 +5,7 @@ import "@polymer/app-layout/app-toolbar/app-toolbar"; import { css, html, LitElement, PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; +import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { computeRTL } from "../../common/util/compute_rtl"; import "../../components/entity/ha-entity-picker"; import "../../components/ha-circular-progress"; @@ -16,7 +17,6 @@ import { getLogbookData, LogbookEntry, } from "../../data/logbook"; -import { fetchPersons } from "../../data/person"; import { loadTraceContexts, TraceContexts } from "../../data/trace"; import { fetchUsers } from "../../data/user"; import "../../layouts/ha-app-layout"; @@ -44,7 +44,7 @@ export class HaPanelLogbook extends LitElement { @state() private _ranges?: DateRangePickerRanges; - private _fetchUserDone?: Promise; + private _fetchUserPromise?: Promise; @state() private _userIdToName = {}; @@ -136,7 +136,7 @@ export class HaPanelLogbook extends LitElement { super.firstUpdated(changedProps); this.hass.loadBackendTranslation("title"); - this._fetchUserDone = this._fetchUserNames(); + this._fetchUserPromise = this._fetchUserNames(); const today = new Date(); today.setHours(0, 0, 0, 0); @@ -198,23 +198,19 @@ export class HaPanelLogbook extends LitElement { private async _fetchUserNames() { const userIdToName = {}; - // Start loading all the data - const personProm = fetchPersons(this.hass); - const userProm = this.hass.user!.is_admin && fetchUsers(this.hass); + // Start loading users + const userProm = this.hass.user?.is_admin && fetchUsers(this.hass); // Process persons - const persons = await personProm; - - for (const person of persons.storage) { - if (person.user_id) { - userIdToName[person.user_id] = person.name; + Object.values(this.hass.states).forEach((entity) => { + if ( + entity.attributes.user_id && + computeStateDomain(entity) === "person" + ) { + this._userIdToName[entity.attributes.user_id] = + entity.attributes.friendly_name; } - } - for (const person of persons.config) { - if (person.user_id) { - userIdToName[person.user_id] = person.name; - } - } + }); // Process users if (userProm) { @@ -262,7 +258,7 @@ export class HaPanelLogbook extends LitElement { this._entityId ), isComponentLoaded(this.hass, "trace") ? loadTraceContexts(this.hass) : {}, - this._fetchUserDone, + this._fetchUserPromise, ]); this._entries = entries; diff --git a/src/panels/lovelace/cards/hui-logbook-card.ts b/src/panels/lovelace/cards/hui-logbook-card.ts index 5681ce47f6..a500e99fc1 100644 --- a/src/panels/lovelace/cards/hui-logbook-card.ts +++ b/src/panels/lovelace/cards/hui-logbook-card.ts @@ -9,11 +9,12 @@ import { import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; -import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { throttle } from "../../../common/util/throttle"; import "../../../components/ha-card"; import "../../../components/ha-circular-progress"; +import { fetchUsers } from "../../../data/user"; import { getLogbookData, LogbookEntry } from "../../../data/logbook"; import type { HomeAssistant } from "../../../types"; import "../../logbook/ha-logbook"; @@ -51,18 +52,20 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard { }; } - @property({ attribute: false }) public hass?: HomeAssistant; + @property({ attribute: false }) public hass!: HomeAssistant; @state() private _config?: LogbookCardConfig; @state() private _logbookEntries?: LogbookEntry[]; - @state() private _persons = {}; - @state() private _configEntities?: EntityConfig[]; + @state() private _userIdToName = {}; + private _lastLogbookDate?: Date; + private _fetchUserPromise?: Promise; + private _throttleGetLogbookEntries = throttle(() => { this._getLogBookData(); }, 10000); @@ -114,7 +117,7 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard { } protected firstUpdated(): void { - this._fetchPersonNames(); + this._fetchUserPromise = this._fetchUserNames(); } protected updated(changedProperties: PropertyValues) { @@ -199,7 +202,7 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard { virtualize .hass=${this.hass} .entries=${this._logbookEntries} - .userIdToName=${this._persons} + .userIdToName=${this._userIdToName} > ` : html` @@ -229,13 +232,16 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard { const lastDate = this._lastLogbookDate || hoursToShowDate; const now = new Date(); - const newEntries = await getLogbookData( - this.hass, - lastDate.toISOString(), - now.toISOString(), - this._configEntities!.map((entity) => entity.entity).toString(), - true - ); + const [newEntries] = await Promise.all([ + getLogbookData( + this.hass, + lastDate.toISOString(), + now.toISOString(), + this._configEntities!.map((entity) => entity.entity).toString(), + true + ), + this._fetchUserPromise, + ]); const logbookEntries = this._logbookEntries ? [...newEntries, ...this._logbookEntries] @@ -248,20 +254,34 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard { this._lastLogbookDate = now; } - private _fetchPersonNames() { - if (!this.hass) { - return; - } + private async _fetchUserNames() { + const userIdToName = {}; + // Start loading users + const userProm = this.hass.user?.is_admin && fetchUsers(this.hass); + + // Process persons Object.values(this.hass!.states).forEach((entity) => { if ( entity.attributes.user_id && computeStateDomain(entity) === "person" ) { - this._persons[entity.attributes.user_id] = + this._userIdToName[entity.attributes.user_id] = entity.attributes.friendly_name; } }); + + // Process users + if (userProm) { + const users = await userProm; + for (const user of users) { + if (!(user.id in userIdToName)) { + userIdToName[user.id] = user.name; + } + } + } + + this._userIdToName = userIdToName; } static get styles(): CSSResultGroup { From ddfc4bd98e233930bde68de240786b745c0d9300 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 12 Jun 2021 00:48:12 +0000 Subject: [PATCH 20/73] Translation update --- translations/frontend/nb.json | 29 +++++++++++++++++++---------- translations/frontend/nl.json | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index c33af17f50..109a6f4ade 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -1140,7 +1140,7 @@ "zone": "Soner" }, "reload": { - "automation": "Automatisering", + "automation": "Automasjoner", "command_line": "Kommandolinjeenheter", "core": "Plassering og tilpasninger", "filesize": "Enheter for filstørrelse", @@ -1448,7 +1448,7 @@ "delete_confirm": "Er du sikker på at du vil slette dette?", "duplicate": "Dupliser", "header": "Betingelser", - "introduction": "Betingelsene er valgfrie og vil hindre at automatiseringen kjøres med mindre alle betingelsene er oppfylt.", + "introduction": "Betingelsene er valgfrie og vil hindre at automasjonen kjøres med mindre alle betingelsene er oppfylt.", "learn_more": "Lær mer om betingelser", "name": "Betingelse", "type_select": "Betingelse", @@ -1529,7 +1529,7 @@ "edit_ui": "Rediger i visuell editor", "edit_yaml": "Rediger i YAML", "enable_disable": "Aktivere/deaktivere automasjon", - "introduction": "Bruk automatisering for å bringe hjemmet ditt til live.", + "introduction": "Bruk automasjoner for å bringe hjemmet ditt til live.", "load_error_not_editable": "Kun automasjoner i automations.yaml kan redigeres", "load_error_unknown": "Feil ved lasting av automasjon ({err_no}).", "max": { @@ -1657,8 +1657,8 @@ "add_automation": "Legg til automasjon", "delete_automation": "Slett automasjon", "delete_confirm": "Er du sikker på at du vil slette denne automasjonen?", - "dev_automation": "Feilsøk automatisering", - "dev_only_editable": "Bare automatisering som har en unik ID tildelt, kan feilsøkes.", + "dev_automation": "Feilsøk automasjon", + "dev_only_editable": "Bare automasjoner som har en unik ID tildelt, kan feilsøkes.", "duplicate": "Dupliser", "duplicate_automation": "Dupliser automasjon", "edit_automation": "Rediger automasjon", @@ -1668,7 +1668,7 @@ }, "introduction": "Automasjonsredigeringen lar deg lage og redigere automasjoner. Følg lenken under for å forsikre deg om at du har konfigurert Home Assistant riktig.", "learn_more": "Lær mer om automasjoner", - "no_automations": "Vi fant ingen automatiseringer", + "no_automations": "Vi kunne ikke finne noen automasjoner", "only_editable": "Bare automasjoner definert i automations.yaml kan redigeres.", "pick_automation": "Velg automasjon for å redigere", "show_info_automation": "Vis informasjon om automasjon" @@ -1799,7 +1799,7 @@ "target_browser": "Nettleser" }, "female": "Kvinne", - "info": "Ta med personlighet hjem ved å få den til å snakke med deg ved å bruke våre tekst-til-tale-tjenester. Du kan bruke dette i automatiseringer og skript ved hjelp av tjenesten {service}.", + "info": "Ta med personlighet hjem ved å få den til å snakke med deg ved å bruke våre tekst-til-tale-tjenester. Du kan bruke dette i automasjoner og skript ved hjelp av tjenesten {service}.", "male": "Mann", "title": "Tekst til tale", "try": "Prøve" @@ -2152,7 +2152,7 @@ "header": "Konfigurer Home Assistant", "helpers": { "caption": "Hjelpere", - "description": "Elementer som hjelper med å bygge automatiseringer", + "description": "Elementer som hjelper med å bygge automasjoner", "dialog": { "add_helper": "Legg hjelper", "add_platform": "Legg til {platform}", @@ -2686,7 +2686,7 @@ "description": "Start på nytt og stopp Home Assistant-serveren", "section": { "reloading": { - "automation": "Automatisering", + "automation": "Automasjoner", "command_line": "Kommandolinjeenheter", "core": "Plassering og tilpasninger", "filesize": "Enheter for filstørrelse", @@ -3891,10 +3891,19 @@ "intro": "Er du klar til å ta kontroll over hjemmet ditt, gjenvinne ditt privatliv og bli med i et verdensomspennende samfunn av entusiaster?", "next": "Neste", "restore": { + "addons": "Tillegg", + "confirm_password": "Bekreft passord for øyeblikksbilde", "description": "Alternativt kan du gjenopprette fra et forrige snapshot.", + "folders": "Mapper", + "full_snapshot": "Full sikkerhetskopi", "hide_log": "Skjul full logg", "in_progress": "Gjenoppretting pågår", - "show_log": "Vis full logg" + "partial_snapshot": "Delvis sikkerhetskopi", + "password": "Passord for øyeblikksbilde", + "password_protection": "Passordbeskyttelse", + "select_type": "Velg hva du vil gjenopprette", + "show_log": "Vis full logg", + "type": "Type øyeblikksbilde" }, "user": { "create_account": "Opprett konto", diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 3db2f73e61..4a7bf66ba8 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -941,7 +941,7 @@ }, "dialogs": { "config_entry_system_options": { - "enable_new_entities_description": "Indien uitgeschakeld, worden nieuwe entiteiten van {integration} niet automatisch aan Home Assistant toegevoegd.", + "enable_new_entities_description": "Of nieuw ontdekte apparaten voor {integratie} automatisch moeten worden toegevoegd.", "enable_new_entities_label": "Voeg nieuwe entiteiten automatisch toe", "enable_polling_description": "Of Home Assistant automatisch moet pollen voor updates voor {integration} entiteiten", "enable_polling_label": "Schakel polling voor updates in.", From d6df8bddeab21fcf2094e910b2b185a4ffa8e4bd Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 13 Jun 2021 00:48:28 +0000 Subject: [PATCH 21/73] Translation update --- translations/frontend/bg.json | 34 ++++++++++++- translations/frontend/da.json | 31 +++++++++++- translations/frontend/he.json | 13 ++++- translations/frontend/ko.json | 11 +++- translations/frontend/sv.json | 95 ++++++++++++++++++++++++++++++++--- 5 files changed, 169 insertions(+), 15 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index e8bc9f9ae8..b6f16f7751 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -260,6 +260,7 @@ "save": "Запис", "show_more": "Показване на повече информация за това", "update": "Актуализиране", + "update_available": "{count}{count, plural,\n one {обновление изчаква}\n other {{count} обновления изчакват}\n}", "version": "Версия", "yes": "Да" }, @@ -287,8 +288,10 @@ "dialog": { "hardware": { "attributes": "Атрибути", + "device_path": "Път до устройството", "id": "ID", "search": "Търсене на хардуер", + "subsystem": "Подсистема", "title": "Хардуер" }, "network": { @@ -340,6 +343,8 @@ "my": { "error": "Възникна неизвестна грешка", "error_addon_not_found": "Не е намерена добавка", + "error_addon_not_installed": "Исканата добавка не е инсталирана. Моля, първо я инсталирайте", + "error_addon_not_started": "Заявените добавки не е стартирана. Моля, първо я стартирайте", "faq_link": "My Home Assistant ЧЗВ", "not_supported": "Тази препратка не се поддържа от вашата Home Assistant инсталация. Последвайте {link} за поддържани препратки както и версиите при тяхното пускане." }, @@ -360,6 +365,7 @@ "created": "Създаден", "delete_selected": "Изтриване на избраните снапшоти", "delete_snapshot_confirm": "Изтрий", + "delete_snapshot_text": "Искате ли да изтриете {number} {number, plural,\n one {резервно копие}\n other {резервни копия}\n}?", "delete_snapshot_title": "Изтриване на снапшота", "description": "Снапшотите ви позволяват лесно да архивирате и възстановявате всички данни от вашия екземпляр на Home Assistant.", "enter_password": "Моля, въведете парола.", @@ -888,6 +894,8 @@ "config_entry_system_options": { "enable_new_entities_description": "Ако е изключено, новооткритите обекти за {integration} няма да бъдат автоматично добавяни в Home Assistant", "enable_new_entities_label": "Активирай новодобавените обекти.", + "enable_polling_description": "Дали Home Assistant трябва да обновява автоматично обектите от {integration}.", + "enable_polling_label": "Включи автоматично опресняване", "restart_home_assistant": "Трябва да рестартирате Home Assistant, за да влязат в сила промените.", "title": "Системни опции за {integration}", "update": "Актуализация" @@ -1136,6 +1144,7 @@ "cluster_header": "Клъстер", "configuration_complete": "Преконфигурирането на устройството завърши.", "configuration_failed": "Преконфигурирането на устройството не бе успешно. Допълнителна информация може да бъде налична в дневниците.", + "configuring_alt": "Конфигуриране", "heading": "Преконфигуриране на устройство", "in_progress": "Устройството се преконфигурира. Това може да отнеме известно време.", "min_max_change": "мин/макс/промяна", @@ -2045,6 +2054,7 @@ "depends_on_cloud": "Зависи от облака", "device_unavailable": "Устройството е недостъпно", "devices": "{count} {count, plural,\n one {устройство}\n other {устройства}\n}", + "disable_error": "Активирането или деактивирането на интеграцията не бе успешно", "disable_restart_confirm": "Рестартирайте Home Assistant за да завършите деактивирането на тази интеграция", "disable": { "disable_confirm": "Наистина ли искате да забраните този конфигурационен запис? Устройствата и обекти му ще бъдат деактивирани.", @@ -2056,6 +2066,7 @@ }, "disabled_cause": "Деактивирано от {cause}" }, + "disabled_polling": "Автоматичното обновяване за данни е забранено", "documentation": "Документация", "enable_restart_confirm": "Рестартирайте Home Assistant за да завършите активирането на тази интеграция", "entities": "{count} {count, plural,\n one {обект}\n other {обекта}\n}", @@ -2257,7 +2268,8 @@ "product_manual": "Ръководство за продукта" }, "node_query_stages": { - "associations": "Обновяване на свързаните групи и членства" + "associations": "Обновяване на свързаните групи и членства", + "complete": "Разпита приключи" }, "node": { "button": "Детайли за възела", @@ -2273,6 +2285,7 @@ }, "refresh_node": { "button": "Обнови възела", + "description": "Това ще накара OpenZWave да разпита дадено устройство и да актуализира командните му класове, възможностите и стойностите му.", "node_status": "Състояние на възела", "refreshing_description": "Опресняване на информацията за възела...", "step": "Стъпка" @@ -2342,6 +2355,8 @@ "add_scene": "Добавяне на сцена", "delete_confirm": "Сигурни ли сте, че искате да изтриете тази сцена?", "delete_scene": "Изтриване на сцената", + "duplicate": "Дублиране", + "duplicate_scene": "Дублиране на сцената", "edit_scene": "Редактиране на сцената", "header": "Редактор на сцени", "headers": { @@ -2545,8 +2560,10 @@ "CONFIGURED_status_text": "Инициализация", "INITIALIZED": "Инициализацията завърши", "INITIALIZED_status_text": "Устройството е готово за употреба", + "INTERVIEW_COMPLETE": "Разпита приключи", "INTERVIEW_COMPLETE_status_text": "Конфигуриране", - "PAIRED": "Намерено устройство" + "PAIRED": "Намерено устройство", + "PAIRED_status_text": "Започване на разпит" }, "groups": { "add_group": "Добавяне на група", @@ -2602,6 +2619,8 @@ "zwave_js": { "add_node": { "inclusion_failed": "Възелът не може да бъде добавен. Моля, проверете журналите за повече информация.", + "interview_failed": "Разпита на устройството не бе успешен. Допълнителна информация може да е налична в логовете.", + "interview_started": "Устройството се разпитва. Това може да отнеме известно време.", "title": "Добавяне на Z-Wave възел" }, "button": "Конфигуриране", @@ -2645,6 +2664,16 @@ "node_status": { "unknown": "Неизвестен" }, + "reinterview_node": { + "battery_device_warning": "Ще трябва да събудите устройствата, захранвани с батерии, преди да започнете повторното интервю. Вижте ръководството на вашето устройство за инструкции как да го събудите.", + "in_progress": "Устройството се разпитва. Това може да отнеме известно време.", + "interview_complete": "Разпита на устройството приключи.", + "interview_failed": "Разпита на устройството не бе успешен. Допълнителна информация може да е налична в логовете.", + "introduction": "Повторно разпитване на устройство във вашата Z-Wave мрежа. Използвайте тази функция, ако устройството има липсваща или неправилна функционалност.", + "run_in_background": "Можете да затворите този диалогов прозорец и разпита ще продължи във фонов режим.", + "start_reinterview": "Започване на нов разпит", + "title": "Повторен разпит на Z-Wave устройство" + }, "remove_node": { "exclusion_failed": "Възелът не може да бъде премахнат. Моля, проверете журналите за повече информация.", "title": "Премахване на Z-Wave възел" @@ -2695,6 +2724,7 @@ "node_protection": "Защита на възела", "nodes": "Възли", "nodes_in_group": "Други възли в тази група:", + "pooling_intensity": "Честота на опресняване", "protection": "Защита", "remove_from_group": "Премахване от групата" }, diff --git a/translations/frontend/da.json b/translations/frontend/da.json index ccd8b05d22..4bf3348140 100644 --- a/translations/frontend/da.json +++ b/translations/frontend/da.json @@ -318,6 +318,14 @@ "no_addons": "Du har endnu ikke installeret nogen tilføjelsesprogrammer. Gå over til butikken for tilføjelsesprogrammer for at komme i gang!" }, "dialog": { + "hardware": { + "attributes": "Attributter", + "device_path": "Enhedssti", + "id": "Identifikationsnummer", + "search": "Søg efter hardware", + "subsystem": "Delsystem", + "title": "Hardware" + }, "network": { "connected_to": "Forbundet til {ssid}", "dhcp": "DHCP", @@ -368,6 +376,8 @@ "error": "Der opstod en ukendt fejl", "error_addon_no_ingress": "Tilføjelsesprogrammet understøtter ikke ingress", "error_addon_not_found": "Tilføjelsesprogrammet blev ikke fundet", + "error_addon_not_installed": "Tilføjelsesprogrammet er ikke installeret venligst installer det først", + "error_addon_not_started": "Tilføjelsesprogrammet kører ikke venligst start det først", "faq_link": "Ofte stillede spørgsmål om Home Assistant", "not_supported": "Denne omdirigering understøttes ikke af din Home Assistant installation. Kontroller {link} for de understøttede omdirigeringer og den version, de blev introduceret i." }, @@ -380,6 +390,7 @@ "snapshot": { "addons": "Tilføjelsesprogrammer", "available_snapshots": "Tilgængelige snapshots", + "confirm_password": "Bekræft snapshot kodeord", "could_not_create": "Kunne ikke oprette snapshot", "create": "Opret", "create_blocked_not_running": "Det er ikke muligt at oprette et snapshot lige nu, fordi systemet er i tilstanden {state}.", @@ -407,6 +418,7 @@ "password": "Kodeord", "password_protected": "beskyttet med kodeord", "password_protection": "Kodeordsbeskyttelse", + "passwords_not_matching": "Kodeordene er forskellige", "security": "Sikkerhed", "select_type": "Vælg, hvad der skal gendannes", "selected": "{number} valgt", @@ -931,6 +943,9 @@ "config_entry_system_options": { "enable_new_entities_description": "Hvis deaktiveret, tilføjes nyligt opdagede entiteter fra {integration} ikke automatisk til Home Assistant.", "enable_new_entities_label": "Aktivér nyligt tilføjede entiteter.", + "enable_polling_description": "Hvis Home Assistant automatisk skal hente {integration} enheder for opdateringer.", + "enable_polling_label": "Aktiver automatisk henting af opdateringer", + "restart_home_assistant": "Du skal genstarte Home Assistant før dine ændringer aktiveres", "title": "Systemindstillinger for {integration}", "update": "Opdater" }, @@ -2073,7 +2088,8 @@ "scripts": "Scripts", "unknown_error": "Ukendt fejl", "unnamed_device": "Enhed uden navn", - "update": "Opdater" + "update": "Opdater", + "update_device_error": "Enhedsopdateringen fejlede" }, "entities": { "caption": "Entiteter", @@ -2206,6 +2222,7 @@ "depends_on_cloud": "Afhængig af Cloud tjenester", "device_unavailable": "Enheden er utilgængelig", "devices": "{count} {count, plural,\n one {enhed}\n other {enheder}\n}", + "disable_error": "Aktivering eller deaktivering af integrationen fejlede", "disable_restart_confirm": "Genstart Home Assistant for at fuldføre deaktivering af denne integration", "disable": { "disable_confirm": "Er du sikker på, at du vil deaktivere denne integration? Integrationens enheder og entiteter vil blive deaktiveret.", @@ -2217,6 +2234,7 @@ }, "disabled_cause": "Deaktiveret af {cause}" }, + "disabled_polling": "Den automatiske hentning af opdateret data er frakoblet", "documentation": "Dokumentation", "enable_restart_confirm": "Genstart Home Assistant for at fuldføre aktivering af denne integration", "entities": "{count} {count, plural,\n one {entitet}\n other {entiteter}\n}", @@ -3873,10 +3891,19 @@ "intro": "Er du klar til at vække dit hjem til live, genvinde dit privatliv og blive medlem af et verdensomspændende fællesskab af tinkerers?", "next": "Næste", "restore": { + "addons": "Tilføjelse", + "confirm_password": "Bekræft Snapshot kodeord", "description": "Alternativt kan du gendanne fra et tidligere snapshot.", + "folders": "Mappe", + "full_snapshot": "Fuld snapshot", "hide_log": "Skjul fuld log", "in_progress": "Gendannelse er i gang", - "show_log": "Vis den fulde log" + "partial_snapshot": "Delvis snapshot", + "password": "Snapshot kodeord", + "password_protection": "Kodeordsbeskyttelse", + "select_type": "Vælg det der skal genetableres", + "show_log": "Vis den fulde log", + "type": "Snapshot type" }, "user": { "create_account": "Opret konto", diff --git a/translations/frontend/he.json b/translations/frontend/he.json index e6bbeb6be8..11f2f3a5a8 100644 --- a/translations/frontend/he.json +++ b/translations/frontend/he.json @@ -3607,7 +3607,7 @@ "menu": { "manage_dashboards": "נהל לוחות מחוונים", "manage_resources": "נהל משאבים", - "open": "פתיחת את תפריט ממשק המשתמש Lovelace", + "open": "פתיחת תפריט ממשק המשתמש Lovelace", "raw_editor": "עורך תצורה גולמית" }, "migrate": { @@ -3891,10 +3891,19 @@ "intro": "האם אתה רוצה לקחת שליטה על הבית שלך ולהצטרף לקהילה הגדולה שלנו?", "next": "הבא", "restore": { + "addons": "תוספים", + "confirm_password": "אישור סיסמת גיבוי", "description": "לחלופין, באפשרותך לשחזר מגיבוי קודם.", + "folders": "תיקיות", + "full_snapshot": "גיבוי מלא", "hide_log": "הסתר יומן מלא", "in_progress": "שחזור מתבצע", - "show_log": "הצג יומן מלא" + "partial_snapshot": "גיבוי חלקי", + "password": "סיסמה", + "password_protection": "הגנה באמצעות סיסמה", + "select_type": "בחר מה לשחזר", + "show_log": "הצג יומן מלא", + "type": "סוג נקודת גיבוי" }, "user": { "create_account": "צור חשבון", diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index c769c47971..9887dc0e6e 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -3891,10 +3891,19 @@ "intro": "잠들어 있는 집을 깨우고 개인정보를 보호하며 전세계의 공돌이 커뮤니티에 가입 할 준비가 되셨나요?", "next": "다음", "restore": { + "addons": "애드온", + "confirm_password": "스냅샷 비밀번호 확인", "description": "이전 스냅숏에서 복원할 수 있습니다.", + "folders": "폴더", + "full_snapshot": "전체 스냅샷", "hide_log": "전체 로그 숨기기", "in_progress": "복원 중", - "show_log": "전체 로그 표시하기" + "partial_snapshot": "부분 스냅샷", + "password": "스냅샷 비밀번호", + "password_protection": "비밀번호 보호", + "select_type": "무엇을 복원할지 선택하세요", + "show_log": "전체 로그 표시하기", + "type": "스냅샷 종류" }, "user": { "create_account": "계정 만들기", diff --git a/translations/frontend/sv.json b/translations/frontend/sv.json index 39c7792d77..ac225ba1c4 100644 --- a/translations/frontend/sv.json +++ b/translations/frontend/sv.json @@ -131,6 +131,12 @@ "uninstall": "Kunde inte avinstallera tillägg" }, "capability": { + "auth_api": { + "title": "Home Assistant-autentisering" + }, + "label": { + "hardware": "hårdvara" + }, "rating": { "title": "Tilläggets säkerhetsrating" }, @@ -142,6 +148,7 @@ "manager": "föreståndare" } }, + "changelog": "Ändringslogg", "cpu_usage": "Tillägg CPU-användning", "hostname": "Värdnamn", "install": "installera", @@ -174,6 +181,7 @@ "title": "Varning: Skyddsläge är inaktiverat!" }, "ram_usage": "Tillägg RAM-användning", + "rebuild": "Bygg om", "restart": "omstart", "start": "starta", "stop": "stoppa", @@ -188,6 +196,11 @@ "documentation": "Dokumentation", "info": "Info", "log": "Logg" + }, + "state": { + "installed": "Add-on är installerad", + "not_available": "Add-on är inte tillgänglig på ditt system", + "not_installed": "Add-on är inte installerad" } }, "common": { @@ -201,7 +214,7 @@ "failed_to_update_name": "Kunde inte uppdatera {name}", "learn_more": "Läs mer", "new_version_available": "Ny version tillgänglig", - "newest_version": "Nyaste version", + "newest_version": "Senaste version", "refresh": "Uppdatera", "reload": "Ladda om", "reset_defaults": "Nollställ till standard", @@ -228,6 +241,11 @@ "title": "Uppdatera {name}" } }, + "dashboard": { + "addon_new_version": "Ny version tillgänglig", + "addon_running": "Add-on körs", + "addons": "Installerade add-ons" + }, "dialog": { "network": { "connected_to": "Ansluten till {ssid}", @@ -276,8 +294,11 @@ "my": { "error": "Ett okänt fel inträffade", "error_addon_not_found": "Tillägget hittades inte", - "faq_link": "Min Home Assistant FAQ", - "not_supported": "Denna omdirigering stöds inte av din Home Assistant-instans. Kontroller {link} för vilka omdirigeringar som stöds och i vilken version de introducerades." + "faq_link": "Mitt Home Assistant FAQ", + "not_supported": "Denna omdirigering stöds inte av din Home Assistant-instans. Kontrollera {link} för vilka omdirigeringar som stöds och i vilken version de introducerades." + }, + "panel": { + "system": "System" }, "snapshot": { "addons": "Tillägg", @@ -303,6 +324,7 @@ "password_protected": "lösenordskyddad", "password_protection": "Lösenordsskydd", "security": "Säkerhet", + "select_type": "Välj vad som ska återställas", "type": "Typ", "upload_snapshot": "Ladda upp avbild" }, @@ -351,6 +373,7 @@ "leave_beta_description": "Få stabila uppdateringar för Home Assistant, Supervisor och värd", "ram_usage": "Supervisor RAM-användning", "reload_supervisor": "Ladda om Supervisor", + "search": "Sök", "share_diagnostics": "Dela diagnostik", "share_diagnostics_description": "Dela kraschrapporter och diagnostisk information.", "share_diagonstics_title": "Hjälp till att förbättra Home Assistant", @@ -564,6 +587,19 @@ "yes": "Ja" }, "components": { + "addon-picker": { + "addon": "Add-on", + "error": { + "fetch_addons": { + "description": "Hämtning av Add-ons gav ett fel.", + "title": "Fel vid hämtning av Add-ons" + }, + "no_supervisor": { + "description": "Ingen Supervisor hittades, Add-on kunde inte laddas.", + "title": "Ingen Supervisor" + } + } + }, "area-picker": { "add_dialog": { "add": "Lägg till", @@ -738,6 +774,11 @@ "week": "{count} {count, plural,\n one {vecka}\n other {veckor}\n} sedan" } }, + "service-control": { + "required": "Det här fältet krävs", + "target": "Mål", + "target_description": "Vad ska denna tjänst använda som målområden, enheter eller entiteter?" + }, "service-picker": { "service": "Tjänst" }, @@ -1872,7 +1913,8 @@ }, "filtering": { "clear": "Rensa", - "filtering_by": "Filtrera efter" + "filtering_by": "Filtrera efter", + "show": "Visa" }, "hassio": { "button": "Konfigurera" @@ -1977,8 +2019,10 @@ "config_flow": { "aborted": "Avbruten", "close": "Stäng", + "could_not_load": "Konfigurationsflödet kunde inte laddas", "created_config": "Skapad konfiguration för {name}.", "dismiss": "Avfärda dialogrutan", + "error": "Fel", "error_saving_area": "Fel vid sparande av område: {error}", "external_step": { "description": "Det här steget kräver att du besöker en extern webbplats för att slutföra.", @@ -1987,15 +2031,21 @@ "finish": "Slutför", "loading_first_time": "Vänligen vänta medan integrationen installeras", "not_all_required_fields": "Alla obligatoriska fält har inte fyllts i.", + "pick_flow_step": { + "new_flow": "Nej, skapa en annan instans av {integration}", + "title": "Vi upptäckte dessa, vill du konfigurera dem?" + }, "submit": "Spara" }, "configure": "Konfigurera", "configured": "Konfigurerad", + "confirm_new": "Vill du konfigurera {integration}?", "description": "Hantera integrationer med tjänster, enheter, ...", "details": "Integrationsdetaljer", "disable": { "disabled_integrations": "{number} inaktiverad(e)", - "hide_disabled": "Dölj inaktiverade integrationer" + "hide_disabled": "Dölj inaktiverade integrationer", + "show_disabled": "Visa inaktiverade integrationer" }, "discovered": "Upptäckt", "home_assistant_website": "Home Assistants hemsida", @@ -2814,13 +2864,17 @@ "type": "Händelsetyp" }, "services": { + "all_parameters": "Alla tillgängliga parametrar", "call_service": "Anropa tjänst", "column_description": "Beskrivning", "column_example": "Exempel", "column_parameter": "Parameter", "description": "Utvecklarverktyget för tjänster låter dig anropa alla tillgängliga tjänster i Home Assistant.", "fill_example_data": "Fyll på exempeldata", - "title": "Tjänster" + "title": "Tjänster", + "ui_mode": "Gå till UI-läge", + "yaml_mode": "Gå till YAML-läge", + "yaml_parameters": "Parametrar endast tillgängliga i YAML-läge" }, "states": { "alert_entity_field": "Enhet är ett obligatoriskt fält", @@ -3359,7 +3413,12 @@ "playback_title": "Meddelandeuppspelning" }, "my": { - "not_supported": "Denna omdirigering stöds inte av din Home Assistant-instans. Kolla {link} för vilka omdirigeringar som stöds och i vilken version de introducerades." + "component_not_loaded": "Denna omdirigering stöds inte av din Home Assistant-instans. Du behöver integrationen {integration} att använda denna omdirigering.", + "documentation": "dokumentation", + "error": "Ett okänt fel inträffade", + "faq_link": "Mitt Home Assistant FAQ", + "no_supervisor": "Denna omdirigering stöds inte av din Home Assistant-installation. Den behöver antingen operativsystemet Home Assistant operativsystem eller Home Assistant Supervised. Mer information finns i {docs_link} .", + "not_supported": "Denna omdirigering stöds inte av din Home Assistant-instans. Kontrollera {link} för vilka omdirigeringar som stöds och i vilken version de introducerades." }, "page-authorize": { "abort_intro": "Inloggning avbruten", @@ -3457,7 +3516,7 @@ "working": "Vänligen vänta" }, "initializing": "Initierar", - "logging_in_to_with": "Loggar in på ** {locationName} ** med ** {authProviderName} **.", + "logging_in_to_with": "Loggar in på **{locationName}** med **{authProviderName}**.", "logging_in_with": "Loggar in med **{authProviderName}**.", "pick_auth_provider": "Eller logga in med" }, @@ -3615,6 +3674,15 @@ "enable": "Aktivera", "header": "Tvåfaktorsautentiseringsmoduler" }, + "number_format": { + "description": "Välj hur siffror utformas.", + "dropdown_label": "Sifferformat", + "formats": { + "language": "Auto (använd språkinställning)", + "none": "Inget" + }, + "header": "Sifferformat" + }, "push_notifications": { "add_device_prompt": { "input_label": "Enhetsnamn", @@ -3656,6 +3724,17 @@ "primary_color": "Primär färg", "reset": "Återställ" }, + "time_format": { + "description": "Välj hur tid utformas.", + "dropdown_label": "Tidsformat", + "formats": { + "12": "12-timmars (FM / EM)", + "24": "24-timmarsklocka", + "language": "Auto (använd språkinställning)", + "system": "Använd systemets språk" + }, + "header": "Tidsformat" + }, "vibrate": { "description": "Aktivera eller inaktivera vibration på den här enheten när du styr enheter.", "header": "Vibrera" From 38640c99e3509570db8a1b7f29882d22259abc77 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 14 Jun 2021 00:48:26 +0000 Subject: [PATCH 22/73] Translation update --- translations/frontend/de.json | 11 ++++++++++- translations/frontend/it.json | 21 ++++++++++++++++++++- translations/frontend/pl.json | 21 ++++++++++++++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/translations/frontend/de.json b/translations/frontend/de.json index a71fe5668f..ff674635c9 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -3891,10 +3891,19 @@ "intro": "Sind Sie bereit, dein Zuhause zu wecken, Ihre Privatsphäre zurückzugewinnen und einer weltweiten Gemeinschaft von Tüftlern beizutreten?", "next": "Weiter", "restore": { + "addons": "Add-ons", + "confirm_password": "Snapshot-Passwort bestätigen", "description": "Alternativ kannst du von einem vorherigen Snapshot wiederherstellen.", + "folders": "Ordner", + "full_snapshot": "Vollständige Datensicherung", "hide_log": "Vollständiges Protokoll ausblenden", "in_progress": "Wiederherstellung im Gange", - "show_log": "Vollständiges Protokoll anzeigen" + "partial_snapshot": "Selektive Datensicherung", + "password": "Snapshot-Passwort", + "password_protection": "Passwortschutz", + "select_type": "Wähle aus, was wiederhergestellt werden soll", + "show_log": "Vollständiges Protokoll anzeigen", + "type": "Snapshot-Typ" }, "user": { "create_account": "Benutzerkonto anlegen", diff --git a/translations/frontend/it.json b/translations/frontend/it.json index ab08f71ffb..349aee0be3 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -318,6 +318,14 @@ "no_addons": "Non hai ancora installato alcun componente aggiuntivo. Vai al negozio di componenti aggiuntivi per iniziare!" }, "dialog": { + "hardware": { + "attributes": "Attributi", + "device_path": "Percorso del dispositivo", + "id": "ID", + "search": "Cerca hardware", + "subsystem": "Sottosistema", + "title": "Hardware" + }, "network": { "connected_to": "Connesso a {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Componenti aggiuntivi", "available_snapshots": "Istantanee disponibili", + "confirm_password": "Conferma la password dell'istantanea", "could_not_create": "Impossibile creare l'istantanea", "create": "Crea", "create_blocked_not_running": "La creazione di un'istantanea non è al momento possibile perché il sistema è nello stato {state}.", @@ -409,6 +418,7 @@ "password": "Password dell'istantanea", "password_protected": "protetto da password", "password_protection": "Protezione con password", + "passwords_not_matching": "Le password non corrispondono", "security": "Sicurezza", "select_type": "Seleziona cosa ripristinare", "selected": "{number} selezionato/i", @@ -3881,10 +3891,19 @@ "intro": "Sei pronto per risvegliare la tua casa, reclamare la tua privacy e far parte di una comunità mondiale di smanettoni?", "next": "Avanti", "restore": { + "addons": "Componenti aggiuntivi", + "confirm_password": "Conferma la password dell'istantanea", "description": "In alternativa è possibile ripristinare da un'istantanea precedente.", + "folders": "Cartelle", + "full_snapshot": "Istantanea completa", "hide_log": "Nascondi il registro completo", "in_progress": "Ripristino in corso", - "show_log": "Mostra il registro completo" + "partial_snapshot": "Istantanea parziale", + "password": "Password dell'istantanea", + "password_protection": "Protezione con password", + "select_type": "Seleziona cosa ripristinare", + "show_log": "Mostra il registro completo", + "type": "Tipo di istantanea" }, "user": { "create_account": "Crea un Account", diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index 73cf60fb11..8b393e69c6 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -318,6 +318,14 @@ "no_addons": "Nie masz jeszcze zainstalowanych żadnych dodatków. Przejdź do sklepu z dodatkami, aby rozpocząć!" }, "dialog": { + "hardware": { + "attributes": "Atrybuty", + "device_path": "Ścieżka urządzenia", + "id": "Identyfikator", + "search": "Wyszukaj sprzęt", + "subsystem": "Podsystem", + "title": "Sprzęt" + }, "network": { "connected_to": "Połączono z {ssid}", "dhcp": "DHCP", @@ -382,6 +390,7 @@ "snapshot": { "addons": "Dodatki", "available_snapshots": "Dostępne snapshoty", + "confirm_password": "Potwierdź hasło snapshota", "could_not_create": "Nie udało się utworzyć snapshota", "create": "Utwórz", "create_blocked_not_running": "Tworzenie snapshota nie jest teraz możliwe, ponieważ system jest w {state}.", @@ -409,6 +418,7 @@ "password": "Hasło snapshota", "password_protected": "chroniony hasłem", "password_protection": "Ochrona hasłem", + "passwords_not_matching": "Hasła nie są takie same", "security": "Bezpieczeństwo", "select_type": "Wybierz, co przywrócić", "selected": "wybrano {number}", @@ -3881,10 +3891,19 @@ "intro": "Czy jesteś gotowy, aby ożywić swój dom, odzyskać prywatność i dołączyć do światowej społeczności majsterkowiczów?", "next": "Dalej", "restore": { + "addons": "Dodatki", + "confirm_password": "Potwierdź hasło snapshota", "description": "Alternatywnie możesz przywrócić z poprzedniej migawki.", + "folders": "Foldery", + "full_snapshot": "Pełny snapshot", "hide_log": "Ukryj cały log", "in_progress": "Trwa przywracanie", - "show_log": "Pokaż cały log" + "partial_snapshot": "Częściowy snapshot", + "password": "Hasło snapshota", + "password_protection": "Ochrona hasłem", + "select_type": "Wybierz, co przywrócić", + "show_log": "Pokaż cały log", + "type": "Typ snapshota" }, "user": { "create_account": "Utwórz konto", From 22253a3385bc6dfab2424ec032cbb3638ec81413 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 15 Jun 2021 01:10:24 +0200 Subject: [PATCH 23/73] Add header and description to progress options flow (#9423) --- .../config-flow/show-dialog-options-flow.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/dialogs/config-flow/show-dialog-options-flow.ts b/src/dialogs/config-flow/show-dialog-options-flow.ts index c138272920..536ead8026 100644 --- a/src/dialogs/config-flow/show-dialog-options-flow.ts +++ b/src/dialogs/config-flow/show-dialog-options-flow.ts @@ -108,12 +108,28 @@ export const showOptionsFlowDialog = ( `; }, - renderShowFormProgressHeader(_hass, _step) { - return ""; + renderShowFormProgressHeader(hass, step) { + return ( + hass.localize( + `component.${configEntry.domain}.options.step.${step.step_id}.title` + ) || hass.localize(`component.${configEntry.domain}.title`) + ); }, - renderShowFormProgressDescription(_hass, _step) { - return ""; + renderShowFormProgressDescription(hass, step) { + const description = hass.localize( + `component.${configEntry.domain}.options.progress.${step.progress_action}`, + step.description_placeholders + ); + return description + ? html` + + ` + : ""; }, } ); From d911fe6a0ba8e58fdc0f05f2ce47efa6fc390cc2 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 15 Jun 2021 00:48:36 +0000 Subject: [PATCH 24/73] Translation update --- translations/frontend/bg.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index b6f16f7751..d3f1555f7d 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -1138,6 +1138,7 @@ }, "zha_reconfigure_device": { "attribute": "Атрибут", + "battery_device_warning": "Ще трябва да събудите устройствата, захранвани с батерии, преди да започнете процеса на преконфигуриране. Вижте ръководствата на вашите устройства за инструкции как да ги събудите.", "bind_header": "Обвързване", "button_hide": "Скрийте детайлите", "button_show": "Покажи детайли", @@ -1147,6 +1148,7 @@ "configuring_alt": "Конфигуриране", "heading": "Преконфигуриране на устройство", "in_progress": "Устройството се преконфигурира. Това може да отнеме известно време.", + "introduction": "Преконфигуриране на устройство във вашата Zigbee мрежа. Използвайте тази функция, ако устройството ви не функционира правилно.", "min_max_change": "мин/макс/промяна", "reporting_header": "Отчитане", "run_in_background": "Можете да затворите този диалогов прозорец и преконфигурирането ще продължи във фонов режим.", @@ -2658,6 +2660,7 @@ "header": "Z-Wave конфигурация на устройството", "introduction": "Управление и настройване на специфични конфигурационни параметри на подбраното устройството (възел, node)", "parameter_is_read_only": "Този параметър е само за четене.", + "set_param_accepted": "Параметърът е актуализиран.", "set_param_error": "Възникна грешка.", "zwave_js_device_database": "Z-Wave JS база данни с устройства" }, From 1b1676cecc855895d683d3a4d6efa4589a1bcd67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Tue, 15 Jun 2021 15:34:15 +0200 Subject: [PATCH 25/73] Use poll for webpack for WSL (#9425) --- build-scripts/gulp/webpack.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build-scripts/gulp/webpack.js b/build-scripts/gulp/webpack.js index 2db685721f..6f0c450fac 100644 --- a/build-scripts/gulp/webpack.js +++ b/build-scripts/gulp/webpack.js @@ -1,4 +1,5 @@ // Tasks to run webpack. +const fs = require("fs"); const gulp = require("gulp"); const webpack = require("webpack"); const WebpackDevServer = require("webpack-dev-server"); @@ -18,6 +19,11 @@ const bothBuilds = (createConfigFunc, params) => [ createConfigFunc({ ...params, latestBuild: false }), ]; +const isWsl = fs + .readFileSync("/proc/version", "utf-8") + .toLocaleLowerCase() + .includes("microsoft"); + /** * @param {{ * compiler: import("webpack").Compiler, @@ -79,7 +85,7 @@ const prodBuild = (conf) => gulp.task("webpack-watch-app", () => { // This command will run forever because we don't close compiler webpack(createAppConfig({ isProdBuild: false, latestBuild: true })).watch( - { ignored: /build-translations/ }, + { ignored: /build-translations/, poll: isWsl }, doneHandler() ); gulp.watch( @@ -137,7 +143,7 @@ gulp.task("webpack-watch-hassio", () => { isProdBuild: false, latestBuild: true, }) - ).watch({ ignored: /build-translations/ }, doneHandler()); + ).watch({ ignored: /build-translations/, poll: isWsl }, doneHandler()); gulp.watch( path.join(paths.translations_src, "en.json"), From 0e3eed0563bef5e2247ccd8d9895e71aff5a0e86 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 15 Jun 2021 15:38:14 +0200 Subject: [PATCH 26/73] Fix supervisor text "error_addon_not_started" (#9412) --- src/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/en.json b/src/translations/en.json index 9977b10956..31d829f9e2 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3822,7 +3822,7 @@ "faq_link": "[%key:ui::panel::my::faq_link%]", "error": "[%key:ui::panel::my::error%]", "error_addon_not_found": "Add-on not found", - "error_addon_not_started": "The requested add-on are not running. Please start it first", + "error_addon_not_started": "The requested add-on is not running. Please start it first", "error_addon_not_installed": "The requested add-on is not installed. Please install it first", "error_addon_no_ingress": "The requested add-on does not support ingress" }, From 6e50d1166a2c66c48afdccfdc4b9ae5fe0fcc3eb Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 15 Jun 2021 16:38:37 +0200 Subject: [PATCH 27/73] Only attempt to get "trace/contexts" if admin (#9378) * Only attempt to get "trace/contexts" if admin * Changes from review --- src/dialogs/more-info/ha-more-info-logbook.ts | 2 +- src/panels/logbook/ha-panel-logbook.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index 4f3e89b3a9..08ddc48734 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -127,7 +127,7 @@ export class MoreInfoLogbook extends LitElement { this.entityId, true ), - loadTraceContexts(this.hass), + this.hass.user?.is_admin ? loadTraceContexts(this.hass) : {}, this._fetchUserPromise, ]); this._logbookEntries = this._logbookEntries diff --git a/src/panels/logbook/ha-panel-logbook.ts b/src/panels/logbook/ha-panel-logbook.ts index aa5aab7245..aa465e51c5 100644 --- a/src/panels/logbook/ha-panel-logbook.ts +++ b/src/panels/logbook/ha-panel-logbook.ts @@ -257,7 +257,9 @@ export class HaPanelLogbook extends LitElement { this._endDate.toISOString(), this._entityId ), - isComponentLoaded(this.hass, "trace") ? loadTraceContexts(this.hass) : {}, + isComponentLoaded(this.hass, "trace") && this.hass.user?.is_admin + ? loadTraceContexts(this.hass) + : {}, this._fetchUserPromise, ]); From 30d6c5eaf3a6480d71b03362efc14b0849208de5 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 15 Jun 2021 19:54:18 +0200 Subject: [PATCH 28/73] Gracefully handle logbook retrieval errors (#9377) --- src/dialogs/more-info/ha-more-info-logbook.ts | 40 +++++++++++++------ src/panels/logbook/ha-panel-logbook.ts | 35 ++++++++++------ src/panels/lovelace/cards/hui-logbook-card.ts | 37 ++++++++++++----- src/translations/en.json | 1 + 4 files changed, 78 insertions(+), 35 deletions(-) diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index 08ddc48734..90d01e75a9 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -29,6 +29,8 @@ export class MoreInfoLogbook extends LitElement { private _fetchUserPromise?: Promise; + private _error?: string; + private _throttleGetLogbookEntries = throttle(() => { this._getLogBookData(); }, 10000); @@ -45,7 +47,13 @@ export class MoreInfoLogbook extends LitElement { return html` ${isComponentLoaded(this.hass, "logbook") - ? !this._logbookEntries + ? this._error + ? html`
+ ${`${this.hass.localize( + "ui.components.logbook.retrieval_error" + )}: ${this._error}`} +
` + : !this._logbookEntries ? html` ; + private _error?: string; + private _throttleGetLogbookEntries = throttle(() => { this._getLogBookData(); }, 10000); @@ -187,7 +189,15 @@ export class HuiLogbookCard extends LitElement implements LovelaceCard { class=${classMap({ "no-header": !this._config!.title })} >
- ${!this._logbookEntries + ${this._error + ? html` +
+ ${`${this.hass.localize( + "ui.components.logbook.retrieval_error" + )}: ${this._error}`} +
+ ` + : !this._logbookEntries ? html` entity.entity).toString(), - true - ), - this._fetchUserPromise, - ]); + try { + newEntries = await Promise.all([ + getLogbookData( + this.hass, + lastDate.toISOString(), + now.toISOString(), + this._configEntities!.map((entity) => entity.entity).toString(), + true + ), + this._fetchUserPromise, + ]); + } catch (err) { + this._error = err.message; + } const logbookEntries = this._logbookEntries ? [...newEntries, ...this._logbookEntries] diff --git a/src/translations/en.json b/src/translations/en.json index 31d829f9e2..030742b168 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -304,6 +304,7 @@ "by": "by", "by_service": "by service", "show_trace": "Show trace", + "retrieval_error": "Error during logbook entry retrieval", "messages": { "was_away": "was detected away", "was_at_state": "was detected at {state}", From 915c46f14404247f9a152bc3beb06adcb7dbc4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Tue, 15 Jun 2021 21:00:28 +0200 Subject: [PATCH 29/73] Fix add-on configuration validation (#9424) --- hassio/src/addon-view/config/hassio-addon-config.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hassio/src/addon-view/config/hassio-addon-config.ts b/hassio/src/addon-view/config/hassio-addon-config.ts index 273bca178b..199a5f8af2 100644 --- a/hassio/src/addon-view/config/hassio-addon-config.ts +++ b/hassio/src/addon-view/config/hassio-addon-config.ts @@ -269,6 +269,9 @@ class HassioAddonConfig extends LitElement { private async _saveTapped(ev: CustomEvent): Promise { const button = ev.currentTarget as any; + const options: Record = this._yamlMode + ? this._editor?.value + : this._options; const eventdata = { success: true, response: undefined, @@ -282,13 +285,13 @@ class HassioAddonConfig extends LitElement { const validation = await validateHassioAddonOption( this.hass, this.addon.slug, - this._editor?.value + options ); if (!validation.valid) { throw Error(validation.message); } await setHassioAddonOption(this.hass, this.addon.slug, { - options: this._yamlMode ? this._editor?.value : this._options, + options, }); this._configHasChanged = false; From 5deb570fdf68de733d5aa81380c2a90813609886 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Tue, 15 Jun 2021 18:02:40 -0400 Subject: [PATCH 30/73] Add button to download logs from zwave_js logs page (#9395) --- .../zwave_js/zwave_js-logs.ts | 18 ++++++++++++++++++ translations/frontend/en.json | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts index 37a984666e..41d0e7172e 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts @@ -1,5 +1,6 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-listbox/paper-listbox"; +import { mdiDownload } from "@mdi/js"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, CSSResultArray, html, LitElement } from "lit"; import { customElement, property, state, query } from "lit/decorators"; @@ -13,6 +14,7 @@ import "../../../../../layouts/hass-tabs-subpage"; import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin"; import { haStyle } from "../../../../../resources/styles"; import { HomeAssistant, Route } from "../../../../../types"; +import { fileDownload } from "../../../../../util/file_download"; import { configTabs } from "./zwave_js-config-router"; @customElement("zwave_js-logs") @@ -92,6 +94,14 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) { ` : ""}
+ + +
@@ -114,6 +124,14 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) { ); } + private _downloadLogs() { + fileDownload( + this, + `data:text/plain;charset=utf-8,${encodeURI(this._textarea!.value)}`, + `zwave_js.log` + ); + } + private _dropdownSelected(ev) { if (ev.target === undefined || this._logConfig === undefined) { return; diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 0aa0e488e5..69b5939af7 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -2990,7 +2990,8 @@ "log_level": "Log Level", "log_level_changed": "Log Level changed to: {level}", "subscribed_to_logs": "Subscribed to Z-Wave JS Log Messages...", - "title": "Z-Wave JS Logs" + "title": "Z-Wave JS Logs", + "download_logs": "Download Logs" }, "navigation": { "logs": "Logs", From e02e61384e7b924e21e7f01e52e638246c4f43c3 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 16 Jun 2021 00:48:25 +0000 Subject: [PATCH 31/73] Translation update --- translations/frontend/bg.json | 2 ++ translations/frontend/ca.json | 1 + translations/frontend/cs.json | 1 + translations/frontend/en.json | 6 +++--- translations/frontend/es.json | 1 + translations/frontend/ru.json | 5 +++-- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index d3f1555f7d..12895a2040 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -1052,6 +1052,7 @@ "areas": "Области", "automation": "Автоматизации", "blueprint": "Планове", + "core": "Общи", "customize": "Персонализации", "devices": "Устройства", "entities": "Обекти", @@ -2945,6 +2946,7 @@ "tilt-position": "Наклон" }, "show_header_toggle": "Показване на превключване на заглавка?", + "special_row": "специален ред", "toggle": "Превключване на обекти." }, "entity-filter": { diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index e7b1e80755..d4a80333ba 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -820,6 +820,7 @@ "was_unplugged": "s'ha desendollat", "was_unsafe": "és insegur" }, + "retrieval_error": "Error durant l'obtenció de l'entrada del diari de registre", "show_trace": "Mostra la traça" }, "media-browser": { diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index 7243339353..771f43d5b5 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -820,6 +820,7 @@ "was_unplugged": "bylo odpojeno", "was_unsafe": "bylo v nebezpečí" }, + "retrieval_error": "Chyba při načítání záznamu", "show_trace": "Zobrazit trasu" }, "media-browser": { diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 69b5939af7..17b1da1b4d 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -377,7 +377,7 @@ "error_addon_no_ingress": "The requested add-on does not support ingress", "error_addon_not_found": "Add-on not found", "error_addon_not_installed": "The requested add-on is not installed. Please install it first", - "error_addon_not_started": "The requested add-on are not running. Please start it first", + "error_addon_not_started": "The requested add-on is not running. Please start it first", "faq_link": "My Home Assistant FAQ", "not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced." }, @@ -820,6 +820,7 @@ "was_unplugged": "was unplugged", "was_unsafe": "was unsafe" }, + "retrieval_error": "Error during logbook entry retrieval", "show_trace": "Show trace" }, "media-browser": { @@ -2990,8 +2991,7 @@ "log_level": "Log Level", "log_level_changed": "Log Level changed to: {level}", "subscribed_to_logs": "Subscribed to Z-Wave JS Log Messages...", - "title": "Z-Wave JS Logs", - "download_logs": "Download Logs" + "title": "Z-Wave JS Logs" }, "navigation": { "logs": "Logs", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index 18bf376a08..f898948e66 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -820,6 +820,7 @@ "was_unplugged": "se desenchufó", "was_unsafe": "era inseguro" }, + "retrieval_error": "Error durante la recuperación de la entrada del libro de registro", "show_trace": "Mostrar traza" }, "media-browser": { diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index bd9b26f613..83db274258 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -820,6 +820,7 @@ "was_unplugged": "отключается", "was_unsafe": "не регистрирует безопасность" }, + "retrieval_error": "Ошибка при получении записи в журнале событий", "show_trace": "Показать трассировку" }, "media-browser": { @@ -1263,7 +1264,7 @@ "no_type_provided": "Тип не указан." }, "supervisor": { - "ask": "Обратиться за помощью", + "ask": "Обратитесь за помощью", "observer": "Проверьте Observer", "reboot": "Попробуйте перезагрузить хост", "system_health": "Проверьте статус системы", @@ -3216,7 +3217,7 @@ "error": { "go_back": "Вернуться", "supervisor": { - "ask": "Обратиться за помощью", + "ask": "Обратитесь за помощью", "observer": "Проверить Observer", "reboot": "Попробуйте перезагрузить хост", "system_health": "Проверить статус системы", From 446a9b5c0257d71e4ad714f3a42d7c9397100ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Wed, 16 Jun 2021 11:13:30 +0200 Subject: [PATCH 32/73] Don't clear action on expected error (#9428) --- hassio/src/dialogs/update/dialog-supervisor-update.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/src/dialogs/update/dialog-supervisor-update.ts b/hassio/src/dialogs/update/dialog-supervisor-update.ts index e017c9d2f9..4e27303681 100644 --- a/hassio/src/dialogs/update/dialog-supervisor-update.ts +++ b/hassio/src/dialogs/update/dialog-supervisor-update.ts @@ -158,8 +158,8 @@ class DialogSupervisorUpdate extends LitElement { } catch (err) { if (this.hass.connection.connected && !ignoreSupervisorError(err)) { this._error = extractApiErrorMessage(err); + this._action = null; } - this._action = null; return; } From 7e507b40c4dc05216d8eeb14c79bd7e41899e7da Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 17 Jun 2021 00:48:10 +0000 Subject: [PATCH 33/73] Translation update --- translations/frontend/bg.json | 15 +++++++++++++-- translations/frontend/de.json | 8 ++++---- translations/frontend/et.json | 1 + translations/frontend/he.json | 7 ++++--- translations/frontend/it.json | 3 ++- translations/frontend/ko.json | 1 + translations/frontend/nb.json | 1 + translations/frontend/pl.json | 1 + translations/frontend/ru.json | 16 ++++++++-------- translations/frontend/zh-Hans.json | 1 + translations/frontend/zh-Hant.json | 1 + 11 files changed, 37 insertions(+), 18 deletions(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index 12895a2040..a04a0754f6 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -344,7 +344,7 @@ "error": "Възникна неизвестна грешка", "error_addon_not_found": "Не е намерена добавка", "error_addon_not_installed": "Исканата добавка не е инсталирана. Моля, първо я инсталирайте", - "error_addon_not_started": "Заявените добавки не е стартирана. Моля, първо я стартирайте", + "error_addon_not_started": "Заявената добавка не е стартирана. Моля, първо я стартирайте", "faq_link": "My Home Assistant ЧЗВ", "not_supported": "Тази препратка не се поддържа от вашата Home Assistant инсталация. Последвайте {link} за поддържани препратки както и версиите при тяхното пускане." }, @@ -1085,6 +1085,7 @@ "rpi_gpio": "Raspberry Pi GPIO обекти", "scene": "Презареждане на сцените", "script": "Презареждане на скриптовете", + "smtp": "SMTP услуги за уведомяване", "telegram": "Презареждане на Telegram услугите за нотификация", "zone": "Презареждане на зоните" }, @@ -1216,6 +1217,7 @@ }, "description": "Групирайте устройствата и обектите в области", "editor": { + "area_id": "ID на област", "create": "Създаване", "default_name": "Нова област", "delete": "Изтриване", @@ -2240,6 +2242,7 @@ "common": { "controller": "Контролер", "network": "Мрежа", + "node_id": "ID на възел", "query_stage": "Етап на заявка", "wakeup_instructions": "Инструкции за събуждане", "zwave": "Z-Wave" @@ -2247,6 +2250,7 @@ "navigation": { "network": "Мрежа", "node": { + "config": "Конфигуриране", "dashboard": "Табло" }, "nodes": "Възли" @@ -2267,6 +2271,9 @@ "network": { "node_count": "{count} възли" }, + "node_config": { + "header": "Конфигурация на възел" + }, "node_metadata": { "product_manual": "Ръководство за продукта" }, @@ -2291,7 +2298,8 @@ "description": "Това ще накара OpenZWave да разпита дадено устройство и да актуализира командните му класове, възможностите и стойностите му.", "node_status": "Състояние на възела", "refreshing_description": "Опресняване на информацията за възела...", - "step": "Стъпка" + "step": "Стъпка", + "wakeup_header": "Инструкции за събуждане за" }, "select_instance": { "none_found": "Не можахме да намерим OpenZWave инстанция. Ако смятате че не е вярно, проверете Вашите OpenZWare и MQTT и се уверете. че Home Assistant може да комуникира със MQTT брокера." @@ -2327,6 +2335,7 @@ "learn_more": "Научете повече за хората", "no_persons_created_yet": "Изглежда все още не сте добавили хора.", "note_about_persons_configured_in_yaml": "Забележка: хората, конфигурирани чрез configuration.yaml, не могат да бъдат редактирани чрез потребителския интерфейс.", + "person_not_found": "Не успяхме да открием лицето, което се опитвате да редактирате.", "person_not_found_title": "Не е намерено лице" }, "scene": { @@ -2622,6 +2631,7 @@ "zwave_js": { "add_node": { "inclusion_failed": "Възелът не може да бъде добавен. Моля, проверете журналите за повече информация.", + "inclusion_finished": "Възелът е добавен.", "interview_failed": "Разпита на устройството не бе успешен. Допълнителна информация може да е налична в логовете.", "interview_started": "Устройството се разпитва. Това може да отнеме известно време.", "title": "Добавяне на Z-Wave възел" @@ -3062,6 +3072,7 @@ "cardpicker": { "by_card": "По карта", "by_entity": "По обект", + "custom_card": "Персонализирана", "domain": "Домейн", "entity": "Обект", "no_description": "Няма налично описание." diff --git a/translations/frontend/de.json b/translations/frontend/de.json index ff674635c9..1ac790a99c 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -200,7 +200,7 @@ "manager": "Manager" }, "stage": { - "description": "Add-ons können sich in einer von drei Phasen befinden:\n\n{icon_stable} **Stable**: Dies sind Add-ons, die bereits vollständig sind und Updates erhalten.\n\n{icon_experimental} **Experimentell**: Diese können Fehler enthalten und unvollendet sein.\n\n{icon_deprecated} **Veraltet**: Diese Add-ons erhalten keine Updates mehr.", + "description": "Add-ons können sich in einer von drei Phasen befinden:\n\n{icon_stable} **Stabil**: Dies sind Add-ons, die bereits vollständig sind und Updates erhalten.\n\n{icon_experimental} **Experimentell**: Diese können Fehler enthalten und unvollendet sein.\n\n{icon_deprecated} **Veraltet**: Diese Add-ons erhalten keine Updates mehr.", "title": "Add-on Phase" } }, @@ -235,7 +235,7 @@ } }, "protection_mode": { - "content": "Der Schutzmodus für dieses Add-on ist deaktiviert! Dadurch erhält das Add-on vollen Zugriff auf das gesamte System, was Sicherheitsrisiken mit sich bringt und dein System bei unsachgemäßer Verwendung beschädigen kann. Deaktiviere den Schutzmodus nur, wenn du die Quelle dieses Add-ons kennst, dieses benötigst UND vertraust.", + "content": "Der Schutzmodus für dieses Add-on ist deaktiviert! Dadurch erhält das Add-on vollen Zugriff auf das gesamte System, was Sicherheitsrisiken mit sich bringt und dein System bei unsachgemäßer Verwendung beschädigen kann. Deaktiviere den Schutzmodus nur, wenn du dieses Add-on benötigst und die Quelle dieses Add-ons kennst UND ihr vertraust.", "enable": "Gesicherten Modus einschalten", "title": "Warnung: Der gesicherte Modus ist deaktiviert!" }, @@ -477,7 +477,7 @@ "join_beta_description": "Erhalte Beta-Updates für Home Assistant (RCs), Supervisor und Host", "leave_beta_action": "Beta-Kanal verlassen", "leave_beta_description": "Erhalte stabile Updates für Home Assistant, Supervisor und Host", - "ram_usage": "Arbeitsspeicherbedarf von Supervisor", + "ram_usage": "Arbeitsspeicherbedarf des Supervisors", "reload_supervisor": "Supervisor neu laden", "search": "Suche", "share_diagnostics": "Diagnose teilen", @@ -941,7 +941,7 @@ }, "dialogs": { "config_entry_system_options": { - "enable_new_entities_description": "Wenn deaktiviert werden neu erkannte Entitäten für {integration} nicht automatisch zu Home Assistant hinzugefügt.", + "enable_new_entities_description": "Wenn aktiviert werden neu erkannte Entitäten für {integration} automatisch zu Home Assistant hinzugefügt.", "enable_new_entities_label": "Neu hinzugefügte Entitäten aktivieren.", "enable_polling_description": "Ob Home Assistant automatisch {integration} Entitäten nach Updates abfragen soll.", "enable_polling_label": "Aktiviere Polling für Updates.", diff --git a/translations/frontend/et.json b/translations/frontend/et.json index 4ed9f8720d..912eddb469 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -820,6 +820,7 @@ "was_unplugged": "eemaldati", "was_unsafe": "oli turvamata" }, + "retrieval_error": "Viga logiraamatu sissekande otsimisel", "show_trace": "Kuva täitmise samme" }, "media-browser": { diff --git a/translations/frontend/he.json b/translations/frontend/he.json index 11f2f3a5a8..995c0e25a3 100644 --- a/translations/frontend/he.json +++ b/translations/frontend/he.json @@ -172,8 +172,8 @@ "title": "מרחב שמות של תהליכי מארח" }, "ingress": { - "description": "תוסף זה משתמש ב-Ingress כדי להטמיע את הממשק שלו בצורה מאובטחת ב-Home Assistant.", - "title": "חדירה" + "description": "תוסף זה משתמש בכניסה כדי להטמיע את הממשק שלו בצורה מאובטחת ב-Home Assistant.", + "title": "כניסה" }, "label": { "apparmor": "apparmor", @@ -377,7 +377,7 @@ "error_addon_no_ingress": "ההרחבה המבוקשת אינו תומכת בכניסה", "error_addon_not_found": "התוסף לא נמצא", "error_addon_not_installed": "התוסף המבוקש אינו מותקן. אנא התקן אותו תחילה", - "error_addon_not_started": "התוסף המבוקש אינו פועל. אנא הפעל אותו תחילה", + "error_addon_not_started": "ההרחבה המבוקשת אינה פועלת. נא הפעל אותו תחילה", "faq_link": "שאלות נפוצות על Home Assistant שלי", "not_supported": "הפניה זו אינה נתמכת על ידי מופע ה-Home Assistant שלך. בדוק ב-{link} את ההפניות הנתמכות ואת הגרסה שהוצגה." }, @@ -820,6 +820,7 @@ "was_unplugged": "היה מנותק", "was_unsafe": "היה לא בטוח" }, + "retrieval_error": "שגיאה במהלך אחזור ערך יומן רישום", "show_trace": "הצג מעקב" }, "media-browser": { diff --git a/translations/frontend/it.json b/translations/frontend/it.json index 349aee0be3..ee8c41af03 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -377,7 +377,7 @@ "error_addon_no_ingress": "Il componente aggiuntivo richiesto non supporta l'ingresso", "error_addon_not_found": "Componente aggiuntivo non trovato", "error_addon_not_installed": "Il componente aggiuntivo richiesto non è installato. Si prega di installarlo prima di proseguire", - "error_addon_not_started": "Il componente aggiuntivo non è in esecuzione. Si prega di avviarlo prima di proseguire", + "error_addon_not_started": "Il componente aggiuntivo richiesto non è in esecuzione. Per favore, avvialo prima", "faq_link": "My Home Assistant FAQ", "not_supported": "Questo reindirizzamento non è supportato dall'istanza di Home Assistant. Controlla il {link} per i reindirizzamenti supportati e la versione in cui sono stati introdotti." }, @@ -820,6 +820,7 @@ "was_unplugged": "è stato scollegato", "was_unsafe": "non era sicuro" }, + "retrieval_error": "Errore durante il recupero della voce del registro", "show_trace": "Mostra la traccia" }, "media-browser": { diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index 9887dc0e6e..819ce983e3 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -820,6 +820,7 @@ "was_unplugged": "의 플러그가 뽑혔습니다.", "was_unsafe": "이(가) 안전하지 않은 상태가 되었습니다." }, + "retrieval_error": "로그북 항목 검색 중 오류", "show_trace": "추적 표시하기" }, "media-browser": { diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index 109a6f4ade..ca09cccc72 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -820,6 +820,7 @@ "was_unplugged": "ble frakoblet", "was_unsafe": "var utrygt" }, + "retrieval_error": "Feil under henting av loggbokoppføring", "show_trace": "Vis spor" }, "media-browser": { diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index 8b393e69c6..56f387bf39 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -820,6 +820,7 @@ "was_unplugged": "nastąpiło odłączenie", "was_unsafe": "wykryto zagrożenie" }, + "retrieval_error": "Błąd podczas pobierania wpisów z dziennika", "show_trace": "Pokaż ślad" }, "media-browser": { diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 83db274258..6254ed7396 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -411,18 +411,18 @@ "ssl": "SSL" }, "folders": "Папки", - "full_snapshot": "Все файлы", + "full_snapshot": "Полный снимок", "name": "Название", "no_snapshots": "Не найдено ни одного снимка", - "partial_snapshot": "Выбрать из списка", + "partial_snapshot": "Частичный снимок", "password": "Пароль", "password_protected": "защищено паролем", "password_protection": "Защита паролем", "passwords_not_matching": "Пароли не совпадают", "security": "Безопасность", - "select_type": "Выберите что нужно восстановить из этого снимка файловой системы", + "select_type": "Выберите что нужно восстановить:", "selected": "Выбрано: {number}", - "type": "Выберите что должен включать в себя снимок файловой системы", + "type": "Тип снимка файловой системы:", "upload_snapshot": "Загрузить снимок на сервер" }, "store": { @@ -3896,15 +3896,15 @@ "confirm_password": "Подтверждение пароля", "description": "Восстановить предыдущее состояние из снимка файловой системы (snapshot)", "folders": "Папки", - "full_snapshot": "Все файлы", + "full_snapshot": "Полный снимок", "hide_log": "Скрыть журнал", "in_progress": "Восстановление системы", - "partial_snapshot": "Выбрать из списка", + "partial_snapshot": "Частичный снимок", "password": "Пароль", "password_protection": "Защита паролем", - "select_type": "Выберите что нужно восстановить из этого снимка файловой системы", + "select_type": "Выберите что нужно восстановить:", "show_log": "Показать журнал", - "type": "Выберите что должен включать в себя снимок файловой системы" + "type": "Тип снимка файловой системы:" }, "user": { "create_account": "Создать учётную запись", diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index c78698ffc7..a2d807aa69 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -820,6 +820,7 @@ "was_unplugged": "已拔出", "was_unsafe": "[%key_id:6884523%]" }, + "retrieval_error": "获取日志条目时出错", "show_trace": "显示轨迹" }, "media-browser": { diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index f76637002b..ff4f4f9cfb 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -820,6 +820,7 @@ "was_unplugged": "狀態為拔下", "was_unsafe": "狀態為不安全" }, + "retrieval_error": "日誌登錄檢索出現錯誤", "show_trace": "顯示紀錄" }, "media-browser": { From 5ad95cad9020d242c6d09a0debd5d33d50845cfd Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 17 Jun 2021 15:23:08 +0200 Subject: [PATCH 34/73] Support white color mode (#9386) --- src/data/light.ts | 1 + .../more-info/controls/more-info-light.ts | 46 ++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/data/light.ts b/src/data/light.ts index 9ef41c284f..d9c68e5d44 100644 --- a/src/data/light.ts +++ b/src/data/light.ts @@ -8,6 +8,7 @@ export enum LightColorModes { ONOFF = "onoff", BRIGHTNESS = "brightness", COLOR_TEMP = "color_temp", + WHITE = "white", HS = "hs", XY = "xy", RGB = "rgb", diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts index 3ac4d2e143..b232bc7c3c 100644 --- a/src/dialogs/more-info/controls/more-info-light.ts +++ b/src/dialogs/more-info/controls/more-info-light.ts @@ -9,6 +9,7 @@ import { TemplateResult, } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-attributes"; import "../../../components/ha-button-toggle-group"; @@ -28,11 +29,6 @@ import { } from "../../../data/light"; import type { HomeAssistant } from "../../../types"; -const toggleButtons = [ - { label: "Color", value: "color" }, - { label: "Temperature", value: LightColorModes.COLOR_TEMP }, -]; - @customElement("more-info-light") class MoreInfoLight extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -59,7 +55,7 @@ class MoreInfoLight extends LitElement { @state() private _colorPickerColor?: [number, number, number]; - @state() private _mode?: "color" | LightColorModes.COLOR_TEMP; + @state() private _mode?: "color" | LightColorModes; protected render(): TemplateResult { if (!this.hass || !this.stateObj) { @@ -71,6 +67,11 @@ class MoreInfoLight extends LitElement { LightColorModes.COLOR_TEMP ); + const supportsWhite = lightSupportsColorMode( + this.stateObj, + LightColorModes.WHITE + ); + const supportsRgbww = lightSupportsColorMode( this.stateObj, LightColorModes.RGBWW @@ -101,16 +102,17 @@ class MoreInfoLight extends LitElement { ${this.stateObj.state === "on" ? html` ${supportsTemp || supportsColor ? html`
` : ""} - ${supportsTemp && supportsColor + ${supportsColor && (supportsTemp || supportsWhite) ? html`` : ""} ${supportsTemp && - (!supportsColor || this._mode === LightColorModes.COLOR_TEMP) + ((!supportsColor && !supportsWhite) || + this._mode === LightColorModes.COLOR_TEMP) ? html` ` : ""} - ${supportsColor && (!supportsTemp || this._mode === "color") + ${supportsColor && + ((!supportsTemp && !supportsWhite) || this._mode === "color") ? html`
{ + const modes = [{ label: "Color", value: "color" }]; + if (supportsTemp) { + modes.push({ label: "Temperature", value: LightColorModes.COLOR_TEMP }); + } + if (supportsWhite) { + modes.push({ label: "White", value: LightColorModes.WHITE }); + } + return modes; + } + ); + private _modeChanged(ev: CustomEvent) { this._mode = ev.detail.value; } @@ -326,6 +342,14 @@ class MoreInfoLight extends LitElement { this._brightnessSliderValue = bri; + if (this._mode === LightColorModes.WHITE) { + this.hass.callService("light", "turn_on", { + entity_id: this.stateObj!.entity_id, + white: Math.min(255, Math.round((bri * 255) / 100)), + }); + return; + } + if (this._brightnessAdjusted) { const rgb = this.stateObj!.attributes.rgb_color || From 9fbd594f37581f75e8c6a93914b36e30d15e1f04 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 17 Jun 2021 15:23:20 +0200 Subject: [PATCH 35/73] Check if `/proc/version` exists (#9438) --- build-scripts/gulp/webpack.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/build-scripts/gulp/webpack.js b/build-scripts/gulp/webpack.js index 6f0c450fac..e7083cd578 100644 --- a/build-scripts/gulp/webpack.js +++ b/build-scripts/gulp/webpack.js @@ -19,10 +19,12 @@ const bothBuilds = (createConfigFunc, params) => [ createConfigFunc({ ...params, latestBuild: false }), ]; -const isWsl = fs - .readFileSync("/proc/version", "utf-8") - .toLocaleLowerCase() - .includes("microsoft"); +const isWsl = + fs.existsSync("/proc/version") && + fs + .readFileSync("/proc/version", "utf-8") + .toLocaleLowerCase() + .includes("microsoft"); /** * @param {{ From ce3c8f264d69335f51268bef91ced8d73a3d1eec Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Thu, 17 Jun 2021 11:19:18 -0400 Subject: [PATCH 36/73] Update zwave_js log subscription to handle core changes (#9262) --- src/data/zwave_js.ts | 18 +++++++++++++++--- .../zwave_js/zwave_js-logs.ts | 15 +++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/data/zwave_js.ts b/src/data/zwave_js.ts index a8389c2c26..6a112b7060 100644 --- a/src/data/zwave_js.ts +++ b/src/data/zwave_js.ts @@ -193,6 +193,18 @@ export const getIdentifiersFromDevice = ( }; }; +export type ZWaveJSLogUpdate = ZWaveJSLogMessageUpdate | ZWaveJSLogConfigUpdate; + +interface ZWaveJSLogMessageUpdate { + type: "log_message"; + log_message: ZWaveJSLogMessage; +} + +interface ZWaveJSLogConfigUpdate { + type: "log_config"; + log_config: ZWaveJSLogConfig; +} + export interface ZWaveJSLogMessage { timestamp: string; level: string; @@ -203,10 +215,10 @@ export interface ZWaveJSLogMessage { export const subscribeZWaveJSLogs = ( hass: HomeAssistant, entry_id: string, - callback: (message: ZWaveJSLogMessage) => void + callback: (update: ZWaveJSLogUpdate) => void ) => - hass.connection.subscribeMessage(callback, { - type: "zwave_js/subscribe_logs", + hass.connection.subscribeMessage(callback, { + type: "zwave_js/subscribe_log_updates", entry_id, }); diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts index 41d0e7172e..0e380a18b3 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts @@ -33,16 +33,20 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) { public hassSubscribe(): Array> { return [ - subscribeZWaveJSLogs(this.hass, this.configEntryId, (log) => { + subscribeZWaveJSLogs(this.hass, this.configEntryId, (update) => { if (!this.hasUpdated) { return; } - if (Array.isArray(log.message)) { - for (const line of log.message) { - this._textarea!.value += `${line}\n`; + if (update.type === "log_message") { + if (Array.isArray(update.log_message.message)) { + for (const line of update.log_message.message) { + this._textarea!.value += `${line}\n`; + } + } else { + this._textarea!.value += `${update.log_message.message}\n`; } } else { - this._textarea!.value += `${log.message}\n`; + this._logConfig = update.log_config; } }).then((unsub) => { this._textarea!.value += `${this.hass.localize( @@ -141,7 +145,6 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) { return; } setZWaveJSLogLevel(this.hass!, this.configEntryId, selected); - this._logConfig.level = selected; this._textarea!.value += `${this.hass.localize( "ui.panel.config.zwave_js.logs.log_level_changed", { level: selected.charAt(0).toUpperCase() + selected.slice(1) } From f88e238d4152c7b47c7caf94022b7f483bb76387 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 18 Jun 2021 00:48:41 +0000 Subject: [PATCH 37/73] Translation update --- translations/frontend/nl.json | 5 ++-- translations/frontend/sl.json | 43 +++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 4a7bf66ba8..149728e21e 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -820,6 +820,7 @@ "was_unplugged": "is niet aangesloten", "was_unsafe": "was onveilig" }, + "retrieval_error": "Fout tijdens het ophalen van de logboekregel", "show_trace": "Tracering weergeven" }, "media-browser": { @@ -2089,7 +2090,7 @@ "unknown_error": "Onbekende fout", "unnamed_device": "Naamloos apparaat", "update": "Bijwerken", - "update_device_error": "Updaten van het apparaat mislukt" + "update_device_error": "Bijwerken van het apparaat mislukt" }, "entities": { "caption": "Entiteiten", @@ -3147,7 +3148,7 @@ "available_events": "Beschikbare gebeurtenissen", "count_listeners": " ({count} luisteraars)", "data": "Gebeurtenis data (YAML, optioneel)", - "description": "Start een evenement op de Home Assistant-gebeurtenisbus", + "description": "Vermeld een gebeurtenis in de gebeurtenisbus.", "documentation": "Gebeurtenissen documentatie", "event_fired": "Gebeurtenis {name} uitgevoerd", "fire_event": "Gebeurtenis uitvoeren", diff --git a/translations/frontend/sl.json b/translations/frontend/sl.json index ed306ac1d9..b78bcbcbb5 100644 --- a/translations/frontend/sl.json +++ b/translations/frontend/sl.json @@ -102,6 +102,25 @@ "unknown": "Neznano" } }, + "supervisor": { + "dialog": { + "hardware": { + "attributes": "Lastnosti", + "id": "ID", + "search": "Iskanje naprav", + "subsystem": "Podsistem", + "title": "Strojna oprema" + } + }, + "snapshot": { + "created": "Ustvarjeno" + }, + "system": { + "supervisor": { + "search": "Iskanje" + } + } + }, "ui": { "auth_store": { "ask": "Ali želite ostati prijavljeni?", @@ -309,6 +328,9 @@ "no_match": "Ni ustreznih območji", "show_areas": "Prikaži območja" }, + "attributes": { + "expansion_header": "Lastnosti" + }, "blueprint-picker": { "add_user": "Dodaj uporabnika", "remove_user": "Odstrani uporabnika", @@ -746,6 +768,10 @@ "zha_device_card": { "device_name_placeholder": "Spremenite ime naprave" } + }, + "zha_reconfigure_device": { + "attribute": "Atribut", + "button_show": "Pokaži podrobnosti" } }, "duration": { @@ -791,7 +817,8 @@ "caption": "Območja", "data_table": { "area": "Območje", - "devices": "Naprave" + "devices": "Naprave", + "entities": "Entitete" }, "delete": { "confirmation_text": "Vse naprave na tem območju bodo postale nedodeljene.", @@ -803,6 +830,7 @@ "create": "Ustvari", "default_name": "Novo območje", "delete": "Izbriši", + "linked_entities_caption": "Entitete", "name": "Ime", "name_required": "Ime je obvezno", "unknown_error": "Neznana napaka", @@ -1214,6 +1242,7 @@ "title": "Alexa" }, "connected": "Povezan", + "connecting": "Povezovanje...", "connection_status": "Stanje povezave v oblaku", "fetching_subscription": "Pridobivam naročnino...", "google": { @@ -1242,6 +1271,7 @@ "remote": { "access_is_being_prepared": "Oddaljeni dostop se pripravlja. Obvestili vas bomo, ko bo pripravljen.", "certificate_info": "Informacije o potrdilu", + "connected": "Povezan", "info": "Home Assistant Cloud zagotavlja varno oddaljeno povezavo do vašega primerka, medtem ko ste zunaj doma.", "instance_is_available": "Vaš primerek je na voljo na", "instance_will_be_available": "Vaš primerek bo na voljo na", @@ -1512,7 +1542,8 @@ "scripts": "Skripte", "unknown_error": "Neznana napaka", "unnamed_device": "Neimenovana naprava", - "update": "Posodobite" + "update": "Posodobite", + "update_device_error": "Posodabljanje naprave ni uspelo" }, "entities": { "caption": "Entitete", @@ -1983,6 +2014,7 @@ "add_scene": "Dodajanje scene", "delete_confirm": "Ali ste prepričani, da želite izbrisati to sceno?", "delete_scene": "Brisanje scene", + "duplicate": "Podvoji", "edit_scene": "Urejanje scene", "header": "Urejevalnik scen", "headers": { @@ -2316,6 +2348,7 @@ "zwave_info": "Z-Wave Informacije" }, "navigation": { + "logs": "Dnevniki", "network": "Omrežje" }, "network_status": { @@ -3271,6 +3304,12 @@ "primary_color": "Primarna barva", "reset": "Ponastavi" }, + "time_format": { + "formats": { + "12": "12 ur (AM / PM)", + "24": "24 ur" + } + }, "vibrate": { "description": "V tej napravi omogočite ali onemogočite vibracije pri krmiljenju naprav.", "header": "Vibriraj" From 0ef3421fa23185a93ad639e6a3854f656e629807 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 18 Jun 2021 11:15:07 +0200 Subject: [PATCH 38/73] Bump chartjs to version 3 (#9401) --- build-scripts/bundle.js | 2 - package.json | 4 +- src/common/color/colors.ts | 63 ++ src/common/color/rgb.ts | 2 +- src/common/datetime/format_date.ts | 13 + src/common/number/clamp.ts | 2 + src/common/style/icon_color_css.ts | 13 +- src/common/util/throttle.ts | 32 +- src/components/chart/chart-date-adapter.ts | 197 ++++++ src/components/chart/ha-chart-base.ts | 229 ++++++ .../chart/state-history-chart-line.ts | 392 +++++++++++ .../chart/state-history-chart-timeline.ts | 310 ++++++++ .../{ => chart}/state-history-charts.ts | 16 +- src/components/chart/timeline-chart/const.ts | 18 + .../chart/timeline-chart/textbar-element.ts | 60 ++ .../timeline-chart/timeline-controller.ts | 160 +++++ .../chart/timeline-chart/timeline-scale.ts | 55 ++ src/components/entity/ha-chart-base.js | 661 ------------------ src/components/state-history-chart-line.js | 433 ------------ .../state-history-chart-timeline.js | 286 -------- src/dialogs/more-info/ha-more-info-history.ts | 2 +- src/dialogs/more-info/ha-more-info-logbook.ts | 1 - src/panels/history/ha-panel-history.ts | 2 +- .../lovelace/cards/hui-history-graph-card.ts | 6 +- src/panels/lovelace/cards/hui-map-card.ts | 17 +- .../lovelace/cards/hui-thermostat-card.ts | 30 +- src/resources/chartjs.ts | 35 + src/resources/ha-chart-scripts.js | 60 -- src/resources/ha-style.ts | 30 +- src/resources/styles.ts | 5 +- yarn.lock | 48 +- 31 files changed, 1616 insertions(+), 1568 deletions(-) create mode 100644 src/common/color/colors.ts create mode 100644 src/common/number/clamp.ts create mode 100644 src/components/chart/chart-date-adapter.ts create mode 100644 src/components/chart/ha-chart-base.ts create mode 100644 src/components/chart/state-history-chart-line.ts create mode 100644 src/components/chart/state-history-chart-timeline.ts rename src/components/{ => chart}/state-history-charts.ts (88%) create mode 100644 src/components/chart/timeline-chart/const.ts create mode 100644 src/components/chart/timeline-chart/textbar-element.ts create mode 100644 src/components/chart/timeline-chart/timeline-controller.ts create mode 100644 src/components/chart/timeline-chart/timeline-scale.ts delete mode 100644 src/components/entity/ha-chart-base.js delete mode 100644 src/components/state-history-chart-line.js delete mode 100644 src/components/state-history-chart-timeline.js create mode 100644 src/resources/chartjs.ts delete mode 100644 src/resources/ha-chart-scripts.js diff --git a/build-scripts/bundle.js b/build-scripts/bundle.js index dc4b59b02a..cd6e1ba854 100644 --- a/build-scripts/bundle.js +++ b/build-scripts/bundle.js @@ -5,8 +5,6 @@ const paths = require("./paths.js"); // Files from NPM Packages that should not be imported module.exports.ignorePackages = ({ latestBuild }) => [ - // Bloats bundle and it's not used. - path.resolve(require.resolve("moment"), "../locale"), // Part of yaml.js and only used for !!js functions that we don't use require.resolve("esprima"), ]; diff --git a/package.json b/package.json index 5e99d75f81..934e858b68 100644 --- a/package.json +++ b/package.json @@ -96,11 +96,11 @@ "@vibrant/quantizer-mmcq": "^3.2.1-alpha.1", "@vue/web-component-wrapper": "^1.2.0", "@webcomponents/webcomponentsjs": "^2.2.7", - "chart.js": "^2.9.4", - "chartjs-chart-timeline": "^0.4.0", + "chart.js": "^3.3.2", "comlink": "^4.3.1", "core-js": "^3.6.5", "cropperjs": "^1.5.11", + "date-fns": "^2.22.1", "deep-clone-simple": "^1.1.1", "deep-freeze": "^0.0.1", "fecha": "^4.2.0", diff --git a/src/common/color/colors.ts b/src/common/color/colors.ts new file mode 100644 index 0000000000..d70aa5ce6a --- /dev/null +++ b/src/common/color/colors.ts @@ -0,0 +1,63 @@ +export const COLORS = [ + "#377eb8", + "#984ea3", + "#00d2d5", + "#ff7f00", + "#af8d00", + "#7f80cd", + "#b3e900", + "#c42e60", + "#a65628", + "#f781bf", + "#8dd3c7", + "#bebada", + "#fb8072", + "#80b1d3", + "#fdb462", + "#fccde5", + "#bc80bd", + "#ffed6f", + "#c4eaff", + "#cf8c00", + "#1b9e77", + "#d95f02", + "#e7298a", + "#e6ab02", + "#a6761d", + "#0097ff", + "#00d067", + "#f43600", + "#4ba93b", + "#5779bb", + "#927acc", + "#97ee3f", + "#bf3947", + "#9f5b00", + "#f48758", + "#8caed6", + "#f2b94f", + "#eff26e", + "#e43872", + "#d9b100", + "#9d7a00", + "#698cff", + "#d9d9d9", + "#00d27e", + "#d06800", + "#009f82", + "#c49200", + "#cbe8ff", + "#fecddf", + "#c27eb6", + "#8cd2ce", + "#c4b8d9", + "#f883b0", + "#a49100", + "#f48800", + "#27d0df", + "#a04a9b", +]; + +export function getColorByIndex(index: number) { + return COLORS[index % COLORS.length]; +} diff --git a/src/common/color/rgb.ts b/src/common/color/rgb.ts index 54b69408dc..8e83eab6a0 100644 --- a/src/common/color/rgb.ts +++ b/src/common/color/rgb.ts @@ -1,4 +1,4 @@ -const luminosity = (rgb: [number, number, number]): number => { +export const luminosity = (rgb: [number, number, number]): number => { // http://www.w3.org/TR/WCAG20/#relativeluminancedef const lum: [number, number, number] = [0, 0, 0]; for (let i = 0; i < rgb.length; i++) { diff --git a/src/common/datetime/format_date.ts b/src/common/datetime/format_date.ts index fa82187a46..e9b70430a0 100644 --- a/src/common/datetime/format_date.ts +++ b/src/common/datetime/format_date.ts @@ -17,6 +17,19 @@ export const formatDate = toLocaleDateStringSupportsOptions formatDateMem(locale).format(dateObj) : (dateObj: Date) => format(dateObj, "longDate"); +const formatDateShortMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + day: "numeric", + month: "short", + }) +); + +export const formatDateShort = toLocaleDateStringSupportsOptions + ? (dateObj: Date, locale: FrontendLocaleData) => + formatDateShortMem(locale).format(dateObj) + : (dateObj: Date) => format(dateObj, "shortDate"); + const formatDateWeekdayMem = memoizeOne( (locale: FrontendLocaleData) => new Intl.DateTimeFormat(locale.language, { diff --git a/src/common/number/clamp.ts b/src/common/number/clamp.ts new file mode 100644 index 0000000000..4368d20add --- /dev/null +++ b/src/common/number/clamp.ts @@ -0,0 +1,2 @@ +export const clamp = (value: number, min: number, max: number) => + Math.min(Math.max(value, min), max); diff --git a/src/common/style/icon_color_css.ts b/src/common/style/icon_color_css.ts index fbc663653a..b636ffa89c 100644 --- a/src/common/style/icon_color_css.ts +++ b/src/common/style/icon_color_css.ts @@ -29,31 +29,28 @@ export const iconColorCSS = css` } ha-icon[data-domain="climate"][data-state="cooling"] { - color: var(--cool-color, #2b9af9); + color: var(--cool-color, var(--state-climate-cool-color)); } ha-icon[data-domain="climate"][data-state="heating"] { - color: var(--heat-color, #ff8100); + color: var(--heat-color, var(--state-climate-heat-color)); } ha-icon[data-domain="climate"][data-state="drying"] { - color: var(--dry-color, #efbd07); + color: var(--dry-color, var(--state-climate-dry-color)); } ha-icon[data-domain="alarm_control_panel"] { color: var(--alarm-color-armed, var(--label-badge-red)); } - ha-icon[data-domain="alarm_control_panel"][data-state="disarmed"] { color: var(--alarm-color-disarmed, var(--label-badge-green)); } - ha-icon[data-domain="alarm_control_panel"][data-state="pending"], ha-icon[data-domain="alarm_control_panel"][data-state="arming"] { color: var(--alarm-color-pending, var(--label-badge-yellow)); animation: pulse 1s infinite; } - ha-icon[data-domain="alarm_control_panel"][data-state="triggered"] { color: var(--alarm-color-triggered, var(--label-badge-red)); animation: pulse 1s infinite; @@ -73,11 +70,11 @@ export const iconColorCSS = css` ha-icon[data-domain="plant"][data-state="problem"], ha-icon[data-domain="zwave"][data-state="dead"] { - color: var(--error-state-color, #db4437); + color: var(--state-icon-error-color); } /* Color the icon if unavailable */ ha-icon[data-state="unavailable"] { - color: var(--state-icon-unavailable-color); + color: var(--state-unavailable-color); } `; diff --git a/src/common/util/throttle.ts b/src/common/util/throttle.ts index 4832a2709b..2860f66be5 100644 --- a/src/common/util/throttle.ts +++ b/src/common/util/throttle.ts @@ -5,32 +5,20 @@ // as much as it can, without ever going more than once per `wait` duration; // but if you'd like to disable the execution on the leading edge, pass // `false for leading`. To disable execution on the trailing edge, ditto. -export const throttle = unknown>( - func: T, +export const throttle = ( + func: (...args: T) => void, wait: number, leading = true, trailing = true -): T => { +) => { let timeout: number | undefined; let previous = 0; - let context: any; - let args: any; - const later = () => { - previous = leading === false ? 0 : Date.now(); - timeout = undefined; - func.apply(context, args); - if (!timeout) { - context = null; - args = null; - } - }; - // @ts-ignore - return function (...argmnts) { - // @ts-ignore - // @typescript-eslint/no-this-alias - context = this; - args = argmnts; - + return (...args: T): void => { + const later = () => { + previous = leading === false ? 0 : Date.now(); + timeout = undefined; + func(...args); + }; const now = Date.now(); if (!previous && leading === false) { previous = now; @@ -42,7 +30,7 @@ export const throttle = unknown>( timeout = undefined; } previous = now; - func.apply(context, args); + func(...args); } else if (!timeout && trailing !== false) { timeout = window.setTimeout(later, remaining); } diff --git a/src/components/chart/chart-date-adapter.ts b/src/components/chart/chart-date-adapter.ts new file mode 100644 index 0000000000..a25163b662 --- /dev/null +++ b/src/components/chart/chart-date-adapter.ts @@ -0,0 +1,197 @@ +import { _adapters } from "chart.js"; +import { + startOfSecond, + startOfMinute, + startOfHour, + startOfDay, + startOfWeek, + startOfMonth, + startOfQuarter, + startOfYear, + addMilliseconds, + addSeconds, + addMinutes, + addHours, + addDays, + addWeeks, + addMonths, + addQuarters, + addYears, + differenceInMilliseconds, + differenceInSeconds, + differenceInMinutes, + differenceInHours, + differenceInDays, + differenceInWeeks, + differenceInMonths, + differenceInQuarters, + differenceInYears, + endOfSecond, + endOfMinute, + endOfHour, + endOfDay, + endOfWeek, + endOfMonth, + endOfQuarter, + endOfYear, +} from "date-fns"; +import { formatDate, formatDateShort } from "../../common/datetime/format_date"; +import { + formatDateTime, + formatDateTimeWithSeconds, +} from "../../common/datetime/format_date_time"; +import { + formatTime, + formatTimeWithSeconds, +} from "../../common/datetime/format_time"; + +const FORMATS = { + datetime: "datetime", + datetimeseconds: "datetimeseconds", + millisecond: "millisecond", + second: "second", + minute: "minute", + hour: "hour", + day: "day", + week: "week", + month: "month", + quarter: "quarter", + year: "year", +}; + +_adapters._date.override({ + formats: () => FORMATS, + parse: (value: Date | number) => { + if (!(value instanceof Date)) { + return value; + } + return value.getTime(); + }, + format: function (time, fmt: keyof typeof FORMATS) { + switch (fmt) { + case "datetime": + return formatDateTime(new Date(time), this.options.locale); + case "datetimeseconds": + return formatDateTimeWithSeconds(new Date(time), this.options.locale); + case "millisecond": + return formatTimeWithSeconds(new Date(time), this.options.locale); + case "second": + return formatTimeWithSeconds(new Date(time), this.options.locale); + case "minute": + return formatTime(new Date(time), this.options.locale); + case "hour": + return formatTime(new Date(time), this.options.locale); + case "day": + return formatDateShort(new Date(time), this.options.locale); + case "week": + return formatDate(new Date(time), this.options.locale); + case "month": + return formatDate(new Date(time), this.options.locale); + case "quarter": + return formatDate(new Date(time), this.options.locale); + case "year": + return formatDate(new Date(time), this.options.locale); + default: + return ""; + } + }, + // @ts-ignore + add: (time, amount, unit) => { + switch (unit) { + case "millisecond": + return addMilliseconds(time, amount); + case "second": + return addSeconds(time, amount); + case "minute": + return addMinutes(time, amount); + case "hour": + return addHours(time, amount); + case "day": + return addDays(time, amount); + case "week": + return addWeeks(time, amount); + case "month": + return addMonths(time, amount); + case "quarter": + return addQuarters(time, amount); + case "year": + return addYears(time, amount); + default: + return time; + } + }, + diff: (max, min, unit) => { + switch (unit) { + case "millisecond": + return differenceInMilliseconds(max, min); + case "second": + return differenceInSeconds(max, min); + case "minute": + return differenceInMinutes(max, min); + case "hour": + return differenceInHours(max, min); + case "day": + return differenceInDays(max, min); + case "week": + return differenceInWeeks(max, min); + case "month": + return differenceInMonths(max, min); + case "quarter": + return differenceInQuarters(max, min); + case "year": + return differenceInYears(max, min); + default: + return 0; + } + }, + // @ts-ignore + startOf: (time, unit, weekday) => { + switch (unit) { + case "second": + return startOfSecond(time); + case "minute": + return startOfMinute(time); + case "hour": + return startOfHour(time); + case "day": + return startOfDay(time); + case "week": + return startOfWeek(time); + case "isoWeek": + return startOfWeek(time, { + weekStartsOn: +weekday! as 0 | 1 | 2 | 3 | 4 | 5 | 6, + }); + case "month": + return startOfMonth(time); + case "quarter": + return startOfQuarter(time); + case "year": + return startOfYear(time); + default: + return time; + } + }, + // @ts-ignore + endOf: (time, unit) => { + switch (unit) { + case "second": + return endOfSecond(time); + case "minute": + return endOfMinute(time); + case "hour": + return endOfHour(time); + case "day": + return endOfDay(time); + case "week": + return endOfWeek(time); + case "month": + return endOfMonth(time); + case "quarter": + return endOfQuarter(time); + case "year": + return endOfYear(time); + default: + return time; + } + }, +}); diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts new file mode 100644 index 0000000000..a976083c34 --- /dev/null +++ b/src/components/chart/ha-chart-base.ts @@ -0,0 +1,229 @@ +import type { + Chart, + ChartType, + ChartData, + ChartOptions, + TooltipModel, +} from "chart.js"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { styleMap } from "lit/directives/style-map"; +import { clamp } from "../../common/number/clamp"; + +@customElement("ha-chart-base") +export default class HaChartBase extends LitElement { + public chart?: Chart; + + @property() + public chartType: ChartType = "line"; + + @property({ attribute: false }) + public data: ChartData = { datasets: [] }; + + @property({ attribute: false }) + public options?: ChartOptions; + + @state() private _tooltip?: TooltipModel; + + @state() private _height?: string; + + protected firstUpdated() { + this._setupChart(); + } + + public willUpdate(changedProps: PropertyValues): void { + super.willUpdate(changedProps); + + if (!this.hasUpdated || !this.chart) { + return; + } + + if (changedProps.has("type")) { + this.chart.config.type = this.chartType; + } + + if (changedProps.has("data")) { + this.chart.data = this.data; + } + if (changedProps.has("options")) { + this.chart.options = this._createOptions(); + } + this.chart.update("none"); + } + + protected render() { + return html` +
+ + ${this._tooltip + ? html`
+
${this._tooltip.title}
+ ${this._tooltip.beforeBody + ? html`
+ ${this._tooltip.beforeBody} +
` + : ""} +
+
    + ${this._tooltip.body.map( + (item, i) => html`
  • + ${item.lines.join("\n")} +
  • ` + )} +
+
+
` + : ""} +
+ `; + } + + private async _setupChart() { + const ctx: CanvasRenderingContext2D = this.renderRoot + .querySelector("canvas")! + .getContext("2d")!; + + this.chart = new (await import("../../resources/chartjs")).Chart(ctx, { + type: this.chartType, + data: this.data, + options: this._createOptions(), + plugins: [ + { + id: "afterRenderHook", + afterRender: (chart) => { + this._height = `${chart.height}px`; + }, + }, + ], + }); + } + + private _createOptions() { + return { + ...this.options, + plugins: { + ...this.options?.plugins, + tooltip: { + ...this.options?.plugins?.tooltip, + enabled: false, + external: (context) => this._handleTooltip(context), + }, + }, + }; + } + + private _handleTooltip(context: { + chart: Chart; + tooltip: TooltipModel; + }) { + if (context.tooltip.opacity === 0) { + this._tooltip = undefined; + return; + } + this._tooltip = { ...context.tooltip }; + } + + public updateChart = (): void => { + if (this.chart) { + this.chart.update(); + } + }; + + static get styles(): CSSResultGroup { + return css` + :host { + display: block; + } + .chartContainer { + position: relative; + overflow: hidden; + height: 0; + transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1); + } + .chartTooltip { + padding: 4px; + font-size: 90%; + position: absolute; + background: rgba(80, 80, 80, 0.9); + color: white; + border-radius: 4px; + pointer-events: none; + transform: translate(-50%, 12px); + z-index: 1000; + width: 200px; + transition: opacity 0.15s ease-in-out; + } + :host([rtl]) .chartTooltip { + direction: rtl; + } + .chartTooltip ul { + display: inline-block; + padding: 0 0px; + margin: 5px 0 0 0; + width: 100%; + } + .chartTooltip ul { + margin: 0 3px; + } + .chartTooltip li { + display: block; + white-space: pre-line; + } + .chartTooltip li::first-line { + line-height: 0; + } + .chartTooltip .title { + text-align: center; + font-weight: 500; + } + .chartTooltip .beforeBody { + text-align: center; + font-weight: 300; + word-break: break-all; + } + .chartTooltip em { + border-radius: 4px; + display: inline-block; + height: 10px; + margin-right: 4px; + width: 10px; + } + :host([rtl]) .chartTooltip em { + margin-right: inherit; + margin-left: 4px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-chart-base": HaChartBase; + } +} diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts new file mode 100644 index 0000000000..24733ce3f4 --- /dev/null +++ b/src/components/chart/state-history-chart-line.ts @@ -0,0 +1,392 @@ +import type { ChartData, ChartDataset, ChartOptions } from "chart.js"; +import { html, LitElement, PropertyValues } from "lit"; +import { property, state } from "lit/decorators"; +import { getColorByIndex } from "../../common/color/colors"; +import { LineChartEntity, LineChartState } from "../../data/history"; +import { HomeAssistant } from "../../types"; +import "./ha-chart-base"; + +class StateHistoryChartLine extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public data: LineChartEntity[] = []; + + @property({ type: Boolean }) public names = false; + + @property() public unit?: string; + + @property() public identifier?: string; + + @property({ type: Boolean }) public isSingleDevice = false; + + @property({ attribute: false }) public endTime?: Date; + + @state() private _chartData?: ChartData<"line">; + + @state() private _chartOptions?: ChartOptions<"line">; + + protected render() { + return html` + + `; + } + + public willUpdate(changedProps: PropertyValues) { + if (!this.hasUpdated) { + this._chartOptions = { + parsing: false, + animation: false, + scales: { + x: { + type: "time", + adapters: { + date: { + locale: this.hass.locale, + }, + }, + ticks: { + maxRotation: 0, + sampleSize: 5, + autoSkipPadding: 20, + major: { + enabled: true, + }, + font: (context) => + context.tick && context.tick.major + ? ({ weight: "bold" } as any) + : {}, + }, + time: { + tooltipFormat: "datetimeseconds", + }, + }, + y: { + ticks: { + maxTicksLimit: 7, + }, + title: { + display: true, + text: this.unit, + }, + }, + }, + plugins: { + tooltip: { + mode: "nearest", + callbacks: { + label: (context) => + `${context.dataset.label}: ${context.parsed.y} ${this.unit}`, + }, + }, + filler: { + propagate: true, + }, + legend: { + display: !this.isSingleDevice, + labels: { + usePointStyle: true, + }, + }, + }, + hover: { + mode: "nearest", + }, + elements: { + line: { + tension: 0.1, + borderWidth: 1.5, + }, + point: { + hitRadius: 5, + }, + }, + }; + } + if (changedProps.has("data")) { + this._generateData(); + } + } + + private _generateData() { + let colorIndex = 0; + const computedStyles = getComputedStyle(this); + const deviceStates = this.data; + const datasets: ChartDataset<"line">[] = []; + let endTime: Date; + + if (deviceStates.length === 0) { + return; + } + + function safeParseFloat(value) { + const parsed = parseFloat(value); + return isFinite(parsed) ? parsed : null; + } + + endTime = + this.endTime || + // Get the highest date from the last date of each device + new Date( + Math.max.apply( + null, + deviceStates.map((devSts) => + new Date( + devSts.states[devSts.states.length - 1].last_changed + ).getMilliseconds() + ) + ) + ); + if (endTime > new Date()) { + endTime = new Date(); + } + + const names = this.names || {}; + deviceStates.forEach((states) => { + const domain = states.domain; + const name = names[states.entity_id] || states.name; + // array containing [value1, value2, etc] + let prevValues: any[] | null = null; + + const data: ChartDataset<"line">[] = []; + + const pushData = (timestamp: Date, datavalues: any[] | null) => { + if (!datavalues) return; + if (timestamp > endTime) { + // Drop datapoints that are after the requested endTime. This could happen if + // endTime is "now" and client time is not in sync with server time. + return; + } + data.forEach((d, i) => { + if (datavalues[i] === null && prevValues && prevValues[i] !== null) { + // null data values show up as gaps in the chart. + // If the current value for the dataset is null and the previous + // value of the data set is not null, then add an 'end' point + // to the chart for the previous value. Otherwise the gap will + // be too big. It will go from the start of the previous data + // value until the start of the next data value. + d.data.push({ x: timestamp.getTime(), y: prevValues[i] }); + } + d.data.push({ x: timestamp.getTime(), y: datavalues[i] }); + }); + prevValues = datavalues; + }; + + const addDataSet = ( + nameY: string, + step = false, + fill = false, + color?: string + ) => { + if (!color) { + color = getColorByIndex(colorIndex); + colorIndex++; + } + data.push({ + label: nameY, + fill: fill ? "origin" : false, + borderColor: color, + backgroundColor: color + "7F", + stepped: step ? "before" : false, + pointRadius: 0, + data: [], + }); + }; + + if ( + domain === "thermostat" || + domain === "climate" || + domain === "water_heater" + ) { + const hasHvacAction = states.states.some( + (entityState) => entityState.attributes?.hvac_action + ); + + const isHeating = + domain === "climate" && hasHvacAction + ? (entityState: LineChartState) => + entityState.attributes?.hvac_action === "heating" + : (entityState: LineChartState) => entityState.state === "heat"; + const isCooling = + domain === "climate" && hasHvacAction + ? (entityState: LineChartState) => + entityState.attributes?.hvac_action === "cooling" + : (entityState: LineChartState) => entityState.state === "cool"; + + const hasHeat = states.states.some(isHeating); + const hasCool = states.states.some(isCooling); + // We differentiate between thermostats that have a target temperature + // range versus ones that have just a target temperature + + // Using step chart by step-before so manually interpolation not needed. + const hasTargetRange = states.states.some( + (entityState) => + entityState.attributes && + entityState.attributes.target_temp_high !== + entityState.attributes.target_temp_low + ); + addDataSet( + `${this.hass.localize("ui.card.climate.current_temperature", { + name: name, + })}`, + true + ); + if (hasHeat) { + addDataSet( + `${this.hass.localize("ui.card.climate.heating", { name: name })}`, + true, + true, + computedStyles.getPropertyValue("--state-climate-heat-color") + ); + // The "heating" series uses steppedArea to shade the area below the current + // temperature when the thermostat is calling for heat. + } + if (hasCool) { + addDataSet( + `${this.hass.localize("ui.card.climate.cooling", { name: name })}`, + true, + true, + computedStyles.getPropertyValue("--state-climate-cool-color") + ); + // The "cooling" series uses steppedArea to shade the area below the current + // temperature when the thermostat is calling for heat. + } + + if (hasTargetRange) { + addDataSet( + `${this.hass.localize("ui.card.climate.target_temperature_mode", { + name: name, + mode: this.hass.localize("ui.card.climate.high"), + })}`, + true + ); + addDataSet( + `${this.hass.localize("ui.card.climate.target_temperature_mode", { + name: name, + mode: this.hass.localize("ui.card.climate.low"), + })}`, + true + ); + } else { + addDataSet( + `${this.hass.localize("ui.card.climate.target_temperature_entity", { + name: name, + })}`, + true + ); + } + + states.states.forEach((entityState) => { + if (!entityState.attributes) return; + const curTemp = safeParseFloat( + entityState.attributes.current_temperature + ); + const series = [curTemp]; + if (hasHeat) { + series.push(isHeating(entityState) ? curTemp : null); + } + if (hasCool) { + series.push(isCooling(entityState) ? curTemp : null); + } + if (hasTargetRange) { + const targetHigh = safeParseFloat( + entityState.attributes.target_temp_high + ); + const targetLow = safeParseFloat( + entityState.attributes.target_temp_low + ); + series.push(targetHigh, targetLow); + pushData(new Date(entityState.last_changed), series); + } else { + const target = safeParseFloat(entityState.attributes.temperature); + series.push(target); + pushData(new Date(entityState.last_changed), series); + } + }); + } else if (domain === "humidifier") { + addDataSet( + `${this.hass.localize("ui.card.humidifier.target_humidity_entity", { + name: name, + })}`, + true + ); + addDataSet( + `${this.hass.localize("ui.card.humidifier.on_entity", { + name: name, + })}`, + true, + true + ); + + states.states.forEach((entityState) => { + if (!entityState.attributes) return; + const target = safeParseFloat(entityState.attributes.humidity); + const series = [target]; + series.push(entityState.state === "on" ? target : null); + pushData(new Date(entityState.last_changed), series); + }); + } else { + // Only disable interpolation for sensors + const isStep = domain === "sensor"; + addDataSet(name, isStep); + + let lastValue: number; + let lastDate: Date; + let lastNullDate: Date | null = null; + + // Process chart data. + // When state is `unknown`, calculate the value and break the line. + states.states.forEach((entityState) => { + const value = safeParseFloat(entityState.state); + const date = new Date(entityState.last_changed); + if (value !== null && lastNullDate) { + const dateTime = date.getTime(); + const lastNullDateTime = lastNullDate.getTime(); + const lastDateTime = lastDate?.getTime(); + const tmpValue = + (value - lastValue) * + ((lastNullDateTime - lastDateTime) / + (dateTime - lastDateTime)) + + lastValue; + pushData(lastNullDate, [tmpValue]); + pushData(new Date(lastNullDateTime + 1), [null]); + pushData(date, [value]); + lastDate = date; + lastValue = value; + lastNullDate = null; + } else if (value !== null && lastNullDate === null) { + pushData(date, [value]); + lastDate = date; + lastValue = value; + } else if ( + value === null && + lastNullDate === null && + lastValue !== undefined + ) { + lastNullDate = date; + } + }); + } + + // Add an entry for final values + pushData(endTime, prevValues); + + // Concat two arrays + Array.prototype.push.apply(datasets, data); + }); + + this._chartData = { + datasets, + }; + } +} +customElements.define("state-history-chart-line", StateHistoryChartLine); + +declare global { + interface HTMLElementTagNameMap { + "state-history-chart-line": StateHistoryChartLine; + } +} diff --git a/src/components/chart/state-history-chart-timeline.ts b/src/components/chart/state-history-chart-timeline.ts new file mode 100644 index 0000000000..ee2fc7d007 --- /dev/null +++ b/src/components/chart/state-history-chart-timeline.ts @@ -0,0 +1,310 @@ +import type { ChartData, ChartDataset, ChartOptions } from "chart.js"; +import { HassEntity } from "home-assistant-js-websocket"; +import { html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { getColorByIndex } from "../../common/color/colors"; +import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time"; +import { computeDomain } from "../../common/entity/compute_domain"; +import { computeRTL } from "../../common/util/compute_rtl"; +import { TimelineEntity } from "../../data/history"; +import { HomeAssistant } from "../../types"; +import "./ha-chart-base"; +import type { TimeLineData } from "./timeline-chart/const"; + +/** Binary sensor device classes for which the static colors for on/off need to be inverted. + * List the ones were "off" = good or normal state = should be rendered "green". + */ +const BINARY_SENSOR_DEVICE_CLASS_COLOR_INVERTED = new Set([ + "battery", + "door", + "garage_door", + "gas", + "lock", + "opening", + "problem", + "safety", + "smoke", + "window", +]); + +const STATIC_STATE_COLORS = new Set([ + "on", + "off", + "home", + "not_home", + "unavailable", + "unknown", + "idle", +]); + +const stateColorMap: Map = new Map(); + +let colorIndex = 0; + +const invertOnOff = (entityState?: HassEntity) => + entityState && + computeDomain(entityState.entity_id) === "binary_sensor" && + "device_class" in entityState.attributes && + BINARY_SENSOR_DEVICE_CLASS_COLOR_INVERTED.has( + entityState.attributes.device_class! + ); + +const getColor = ( + stateString: string, + entityState: HassEntity, + computedStyles: CSSStyleDeclaration +) => { + if (invertOnOff(entityState)) { + stateString = stateString === "on" ? "off" : "on"; + } + if (stateColorMap.has(stateString)) { + return stateColorMap.get(stateString); + } + if (STATIC_STATE_COLORS.has(stateString)) { + const color = computedStyles.getPropertyValue( + `--state-${stateString}-color` + ); + stateColorMap.set(stateString, color); + return color; + } + const color = getColorByIndex(colorIndex); + colorIndex++; + stateColorMap.set(stateString, color); + return color; +}; + +@customElement("state-history-chart-timeline") +export class StateHistoryChartTimeline extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public data: TimelineEntity[] = []; + + @property({ type: Boolean }) public names = false; + + @property() public unit?: string; + + @property() public identifier?: string; + + @property({ type: Boolean }) public isSingleDevice = false; + + @property({ attribute: false }) public endTime?: Date; + + @state() private _chartData?: ChartData<"timeline">; + + @state() private _chartOptions?: ChartOptions<"timeline">; + + protected render() { + return html` + + `; + } + + public willUpdate(changedProps: PropertyValues) { + if (!this.hasUpdated) { + this._chartOptions = { + maintainAspectRatio: false, + parsing: false, + animation: false, + scales: { + x: { + type: "timeline", + position: "bottom", + adapters: { + date: { + locale: this.hass.locale, + }, + }, + ticks: { + autoSkip: true, + maxRotation: 0, + sampleSize: 5, + autoSkipPadding: 20, + major: { + enabled: true, + }, + font: (context) => + context.tick && context.tick.major + ? ({ weight: "bold" } as any) + : {}, + }, + grid: { + offset: false, + }, + time: { + tooltipFormat: "datetimeseconds", + }, + }, + y: { + type: "category", + barThickness: 20, + offset: true, + grid: { + display: false, + drawBorder: false, + drawTicks: false, + }, + ticks: { + display: this.data.length !== 1, + }, + afterSetDimensions: (y) => { + y.maxWidth = y.chart.width * 0.18; + }, + position: computeRTL(this.hass) ? "right" : "left", + }, + }, + plugins: { + tooltip: { + mode: "nearest", + callbacks: { + title: (context) => + context![0].chart!.data!.labels![ + context[0].datasetIndex + ] as string, + beforeBody: (context) => context[0].dataset.label || "", + label: (item) => { + const d = item.dataset.data[item.dataIndex] as TimeLineData; + return [ + d.label || "", + formatDateTimeWithSeconds(d.start, this.hass.locale), + formatDateTimeWithSeconds(d.end, this.hass.locale), + ]; + }, + labelColor: (item) => ({ + borderColor: (item.dataset.data[item.dataIndex] as TimeLineData) + .color!, + backgroundColor: (item.dataset.data[ + item.dataIndex + ] as TimeLineData).color!, + }), + }, + }, + filler: { + propagate: true, + }, + }, + }; + } + if (changedProps.has("data")) { + this._generateData(); + } + } + + private _generateData() { + const computedStyles = getComputedStyle(this); + let stateHistory = this.data; + + if (!stateHistory) { + stateHistory = []; + } + + const startTime = new Date( + stateHistory.reduce( + (minTime, stateInfo) => + Math.min(minTime, new Date(stateInfo.data[0].last_changed).getTime()), + new Date().getTime() + ) + ); + + // end time is Math.max(startTime, last_event) + let endTime = + this.endTime || + new Date( + stateHistory.reduce( + (maxTime, stateInfo) => + Math.max( + maxTime, + new Date( + stateInfo.data[stateInfo.data.length - 1].last_changed + ).getTime() + ), + startTime.getTime() + ) + ); + + if (endTime > new Date()) { + endTime = new Date(); + } + + const labels: string[] = []; + const datasets: ChartDataset<"timeline">[] = []; + const names = this.names || {}; + // stateHistory is a list of lists of sorted state objects + stateHistory.forEach((stateInfo) => { + let newLastChanged: Date; + let prevState: string | null = null; + let locState: string | null = null; + let prevLastChanged = startTime; + const entityDisplay: string = + names[stateInfo.entity_id] || stateInfo.name; + + const dataRow: TimeLineData[] = []; + stateInfo.data.forEach((entityState) => { + let newState: string | null = entityState.state; + const timeStamp = new Date(entityState.last_changed); + if (!newState) { + newState = null; + } + if (timeStamp > endTime) { + // Drop datapoints that are after the requested endTime. This could happen if + // endTime is 'now' and client time is not in sync with server time. + return; + } + if (prevState === null) { + prevState = newState; + locState = entityState.state_localize; + prevLastChanged = new Date(entityState.last_changed); + } else if (newState !== prevState) { + newLastChanged = new Date(entityState.last_changed); + + dataRow.push({ + start: prevLastChanged, + end: newLastChanged, + label: locState, + color: getColor( + prevState, + this.hass.states[stateInfo.entity_id], + computedStyles + ), + }); + + prevState = newState; + locState = entityState.state_localize; + prevLastChanged = newLastChanged; + } + }); + + if (prevState !== null) { + dataRow.push({ + start: prevLastChanged, + end: endTime, + label: locState, + color: getColor( + prevState, + this.hass.states[stateInfo.entity_id], + computedStyles + ), + }); + } + datasets.push({ + data: dataRow, + label: stateInfo.entity_id, + }); + labels.push(entityDisplay); + }); + + this._chartData = { + labels: labels, + datasets: datasets, + }; + } +} + +declare global { + interface HTMLElementTagNameMap { + "state-history-chart-timeline": StateHistoryChartTimeline; + } +} diff --git a/src/components/state-history-charts.ts b/src/components/chart/state-history-charts.ts similarity index 88% rename from src/components/state-history-charts.ts rename to src/components/chart/state-history-charts.ts index 9be40220da..c31559c838 100644 --- a/src/components/state-history-charts.ts +++ b/src/components/chart/state-history-charts.ts @@ -7,10 +7,10 @@ import { TemplateResult, } from "lit"; import { customElement, property } from "lit/decorators"; -import { isComponentLoaded } from "../common/config/is_component_loaded"; -import { HistoryResult } from "../data/history"; -import type { HomeAssistant } from "../types"; -import "./ha-circular-progress"; +import { isComponentLoaded } from "../../common/config/is_component_loaded"; +import { HistoryResult } from "../../data/history"; +import type { HomeAssistant } from "../../types"; +import "../ha-circular-progress"; import "./state-history-chart-line"; import "./state-history-chart-timeline"; @@ -24,7 +24,7 @@ class StateHistoryCharts extends LitElement { @property({ attribute: false }) public endTime?: Date; - @property({ type: Boolean }) public upToNow = false; + @property({ type: Boolean, attribute: "up-to-now" }) public upToNow = false; @property({ type: Boolean, attribute: "no-single" }) public noSingle = false; @@ -101,12 +101,12 @@ class StateHistoryCharts extends LitElement { return css` :host { display: block; - /* height of single timeline chart = 58px */ - min-height: 58px; + /* height of single timeline chart = 60px */ + min-height: 60px; } .info { text-align: center; - line-height: 58px; + line-height: 60px; color: var(--secondary-text-color); } `; diff --git a/src/components/chart/timeline-chart/const.ts b/src/components/chart/timeline-chart/const.ts new file mode 100644 index 0000000000..ac5f234272 --- /dev/null +++ b/src/components/chart/timeline-chart/const.ts @@ -0,0 +1,18 @@ +export interface TimeLineData { + start: Date; + end: Date; + label?: string | null; + color?: string; +} + +declare module "chart.js" { + interface ChartTypeRegistry { + timeline: { + chartOptions: BarControllerChartOptions; + datasetOptions: BarControllerDatasetOptions; + defaultDataPoint: TimeLineData; + parsedDataType: any; + scales: "timeline"; + }; + } +} diff --git a/src/components/chart/timeline-chart/textbar-element.ts b/src/components/chart/timeline-chart/textbar-element.ts new file mode 100644 index 0000000000..1348021b0e --- /dev/null +++ b/src/components/chart/timeline-chart/textbar-element.ts @@ -0,0 +1,60 @@ +import { BarElement, BarOptions, BarProps } from "chart.js"; +import { hex2rgb } from "../../../common/color/convert-color"; +import { luminosity } from "../../../common/color/rgb"; + +export interface TextBarProps extends BarProps { + text?: string | null; + options?: Partial; +} + +export interface TextBaroptions extends BarOptions { + textPad?: number; + textColor?: string; + backgroundColor: string; +} + +export class TextBarElement extends BarElement { + static id = "textbar"; + + draw(ctx) { + super.draw(ctx); + const options = this.options as TextBaroptions; + const { x, y, base, width, text } = (this as BarElement< + TextBarProps, + TextBaroptions + >).getProps(["x", "y", "base", "width", "text"]); + + if (!text) { + return; + } + + ctx.beginPath(); + const textRect = ctx.measureText(text); + if ( + textRect.width === 0 || + textRect.width + (options.textPad || 4) + 2 > width + ) { + return; + } + const textColor = + options.textColor || + (options.backgroundColor && + (luminosity(hex2rgb(options.backgroundColor)) > 0.5 ? "#000" : "#fff")); + + // ctx.font = "12px arial"; + ctx.fillStyle = textColor; + ctx.lineWidth = 0; + ctx.strokeStyle = textColor; + ctx.textBaseline = "middle"; + ctx.fillText( + text, + x - width / 2 + (options.textPad || 4), + y + (base - y) / 2 + ); + } + + tooltipPosition(useFinalPosition: boolean) { + const { x, y, base } = this.getProps(["x", "y", "base"], useFinalPosition); + return { x, y: y + (base - y) / 2 }; + } +} diff --git a/src/components/chart/timeline-chart/timeline-controller.ts b/src/components/chart/timeline-chart/timeline-controller.ts new file mode 100644 index 0000000000..6b6ce7c41b --- /dev/null +++ b/src/components/chart/timeline-chart/timeline-controller.ts @@ -0,0 +1,160 @@ +import { BarController, BarElement } from "chart.js"; +import { TimeLineData } from "./const"; +import { TextBarProps } from "./textbar-element"; + +function parseValue(entry, item, vScale, i) { + const startValue = vScale.parse(entry.start, i); + const endValue = vScale.parse(entry.end, i); + const min = Math.min(startValue, endValue); + const max = Math.max(startValue, endValue); + let barStart = min; + let barEnd = max; + + if (Math.abs(min) > Math.abs(max)) { + barStart = max; + barEnd = min; + } + + // Store `barEnd` (furthest away from origin) as parsed value, + // to make stacking straight forward + item[vScale.axis] = barEnd; + + item._custom = { + barStart, + barEnd, + start: startValue, + end: endValue, + min, + max, + }; + + return item; +} + +export class TimelineController extends BarController { + static id = "timeline"; + + static defaults = { + dataElementType: "textbar", + dataElementOptions: ["text", "textColor", "textPadding"], + elements: { + showText: true, + textPadding: 4, + minBarWidth: 1, + }, + + layout: { + padding: { + left: 0, + right: 0, + top: 0, + bottom: 0, + }, + }, + }; + + static overrides = { + maintainAspectRatio: false, + plugins: { + legend: { + display: false, + }, + }, + }; + + parseObjectData(meta, data, start, count) { + const iScale = meta.iScale; + const vScale = meta.vScale; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed: any[] = []; + let i; + let ilen; + let item; + let entry; + + for (i = start, ilen = start + count; i < ilen; ++i) { + entry = data[i]; + item = {}; + item[iScale.axis] = singleScale || iScale.parse(labels[i], i); + parsed.push(parseValue(entry, item, vScale, i)); + } + return parsed; + } + + getLabelAndValue(index) { + const meta = this._cachedMeta; + const { vScale } = meta; + const data = this.getDataset().data[index] as TimeLineData; + + return { + label: vScale!.getLabelForValue(this.index) || "", + value: data.label || "", + }; + } + + updateElements( + bars: BarElement[], + start: number, + count: number, + mode: "reset" | "resize" | "none" | "hide" | "show" | "normal" | "active" + ) { + const vScale = this._cachedMeta.vScale!; + const iScale = this._cachedMeta.iScale!; + const dataset = this.getDataset(); + + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions!); + + const horizontal = vScale.isHorizontal(); + + this.updateSharedOptions(sharedOptions!, mode, firstOpts); + + for (let index = start; index < start + count; index++) { + const data = dataset.data[index] as TimeLineData; + + // @ts-ignore + const y = vScale.getPixelForValue(this.index); + + // @ts-ignore + const xStart = iScale.getPixelForValue(data.start.getTime()); + // @ts-ignore + const xEnd = iScale.getPixelForValue(data.end.getTime()); + const width = xEnd - xStart; + + const height = 10; + + const properties: TextBarProps = { + horizontal, + x: xStart + width / 2, // Center of the bar + y: y - height, // Top of bar + width, + height: 0, + base: y + height, // Bottom of bar, + // Text + text: data.label, + }; + + if (includeOptions) { + properties.options = + sharedOptions || this.resolveDataElementOptions(index, mode); + + properties.options = { + ...properties.options, + backgroundColor: data.color, + }; + } + + this.updateElement(bars[index], index, properties as any, mode); + } + } + + removeHoverStyle(_element, _datasetIndex, _index) { + // this._setStyle(element, index, 'active', false); + } + + setHoverStyle(_element, _datasetIndex, _index) { + // this._setStyle(element, index, 'active', true); + } +} diff --git a/src/components/chart/timeline-chart/timeline-scale.ts b/src/components/chart/timeline-chart/timeline-scale.ts new file mode 100644 index 0000000000..8d5086dafc --- /dev/null +++ b/src/components/chart/timeline-chart/timeline-scale.ts @@ -0,0 +1,55 @@ +import { TimeScale } from "chart.js"; +import { TimeLineData } from "./const"; + +export class TimeLineScale extends TimeScale { + static id = "timeline"; + + static defaults = { + position: "bottom", + tooltips: { + mode: "nearest", + }, + ticks: { + autoSkip: true, + }, + }; + + determineDataLimits() { + const options = this.options; + // @ts-ignore + const adapter = this._adapter; + const unit = options.time.unit || "day"; + let { min, max } = this.getUserBounds(); + + const chart = this.chart; + + // Convert data to timestamps + chart.data.datasets.forEach((dataset, index) => { + if (!chart.isDatasetVisible(index)) { + return; + } + for (const data of dataset.data as TimeLineData[]) { + let timestamp0 = adapter.parse(data.start, this); + let timestamp1 = adapter.parse(data.end, this); + if (timestamp0 > timestamp1) { + [timestamp0, timestamp1] = [timestamp1, timestamp0]; + } + if (min > timestamp0 && timestamp0) { + min = timestamp0; + } + if (max < timestamp1 && timestamp1) { + max = timestamp1; + } + } + }); + + // In case there is no valid min/max, var's use today limits + min = + isFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit); + + // Make sure that max is strictly higher than min (required by the lookup table) + this.min = Math.min(min, max - 1); + this.max = Math.max(min + 1, max); + } +} diff --git a/src/components/entity/ha-chart-base.js b/src/components/entity/ha-chart-base.js deleted file mode 100644 index 2ae4d7cf26..0000000000 --- a/src/components/entity/ha-chart-base.js +++ /dev/null @@ -1,661 +0,0 @@ -/* eslint-plugin-disable lit */ -import { IronResizableBehavior } from "@polymer/iron-resizable-behavior/iron-resizable-behavior"; -import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class"; -import { timeOut } from "@polymer/polymer/lib/utils/async"; -import { Debouncer } from "@polymer/polymer/lib/utils/debounce"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { formatTime } from "../../common/datetime/format_time"; -import "../ha-icon-button"; - -// eslint-disable-next-line no-unused-vars -/* global Chart moment Color */ - -let scriptsLoaded = null; - -class HaChartBase extends mixinBehaviors( - [IronResizableBehavior], - PolymerElement -) { - static get template() { - return html` - - -
- -
-
[[tooltip.title]]
- -
-
    - -
-
-
-
- `; - } - - get chart() { - return this._chart; - } - - static get properties() { - return { - data: Object, - identifier: String, - rendered: { - type: Boolean, - notify: true, - value: false, - readOnly: true, - }, - metas: { - type: Array, - value: () => [], - }, - tooltip: { - type: Object, - value: () => ({ - opacity: "0", - left: "0", - top: "0", - xPadding: "5", - yPadding: "3", - }), - }, - unit: Object, - rtl: { - type: Boolean, - reflectToAttribute: true, - }, - }; - } - - static get observers() { - return ["onPropsChange(data)"]; - } - - connectedCallback() { - super.connectedCallback(); - this._isAttached = true; - this.onPropsChange(); - this._resizeListener = () => { - this._debouncer = Debouncer.debounce( - this._debouncer, - timeOut.after(10), - () => { - if (this._isAttached) { - this.resizeChart(); - } - } - ); - }; - - if (typeof ResizeObserver === "function") { - this.resizeObserver = new ResizeObserver((entries) => { - entries.forEach(() => { - this._resizeListener(); - }); - }); - this.resizeObserver.observe(this.$.chartTarget); - } else { - this.addEventListener("iron-resize", this._resizeListener); - } - - if (scriptsLoaded === null) { - scriptsLoaded = import("../../resources/ha-chart-scripts.js"); - } - scriptsLoaded.then((ChartModule) => { - this.ChartClass = ChartModule.default; - this.onPropsChange(); - }); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this._isAttached = false; - if (this.resizeObserver) { - this.resizeObserver.unobserve(this.$.chartTarget); - } - - this.removeEventListener("iron-resize", this._resizeListener); - - if (this._resizeTimer !== undefined) { - clearInterval(this._resizeTimer); - this._resizeTimer = undefined; - } - } - - onPropsChange() { - if (!this._isAttached || !this.ChartClass || !this.data) { - return; - } - this.drawChart(); - } - - _customTooltips(tooltip) { - // Hide if no tooltip - if (tooltip.opacity === 0) { - this.set(["tooltip", "opacity"], 0); - return; - } - // Set caret Position - if (tooltip.yAlign) { - this.set(["tooltip", "yAlign"], tooltip.yAlign); - } else { - this.set(["tooltip", "yAlign"], "no-transform"); - } - - const title = tooltip.title ? tooltip.title[0] || "" : ""; - this.set(["tooltip", "title"], title); - - if (tooltip.beforeBody) { - this.set(["tooltip", "beforeBody"], tooltip.beforeBody.join("\n")); - } - - const bodyLines = tooltip.body.map((n) => n.lines); - - // Set Text - if (tooltip.body) { - this.set( - ["tooltip", "lines"], - bodyLines.map((body, i) => { - const colors = tooltip.labelColors[i]; - return { - color: colors.borderColor, - bgColor: colors.backgroundColor, - text: body.join("\n"), - }; - }) - ); - } - const parentWidth = this.$.chartTarget.clientWidth; - let positionX = tooltip.caretX; - const positionY = this._chart.canvas.offsetTop + tooltip.caretY; - if (tooltip.caretX + 100 > parentWidth) { - positionX = parentWidth - 100; - } else if (tooltip.caretX < 100) { - positionX = 100; - } - positionX += this._chart.canvas.offsetLeft; - // Display, position, and set styles for font - this.tooltip = { - ...this.tooltip, - opacity: 1, - left: `${positionX}px`, - top: `${positionY}px`, - }; - } - - _legendClick(event) { - event = event || window.event; - event.stopPropagation(); - let target = event.target || event.srcElement; - while (target.nodeName !== "LI") { - // user clicked child, find parent LI - target = target.parentElement; - } - const index = event.model.itemsIndex; - - const meta = this._chart.getDatasetMeta(index); - meta.hidden = - meta.hidden === null ? !this._chart.data.datasets[index].hidden : null; - this.set( - ["metas", index, "hidden"], - this._chart.isDatasetVisible(index) ? null : "hidden" - ); - this._chart.update(); - } - - _drawLegend() { - const chart = this._chart; - // New data for old graph. Keep metadata. - const preserveVisibility = - this._oldIdentifier && this.identifier === this._oldIdentifier; - this._oldIdentifier = this.identifier; - this.set( - "metas", - this._chart.data.datasets.map((x, i) => ({ - label: x.label, - color: x.color, - bgColor: x.backgroundColor, - hidden: - preserveVisibility && i < this.metas.length - ? this.metas[i].hidden - : !chart.isDatasetVisible(i), - })) - ); - let updateNeeded = false; - if (preserveVisibility) { - for (let i = 0; i < this.metas.length; i++) { - const meta = chart.getDatasetMeta(i); - if (!!meta.hidden !== !!this.metas[i].hidden) updateNeeded = true; - meta.hidden = this.metas[i].hidden ? true : null; - } - } - if (updateNeeded) { - chart.update(); - } - this.unit = this.data.unit; - } - - _formatTickValue(value, index, values) { - if (values.length === 0) { - return value; - } - const date = new Date(values[index].value); - return formatTime(date, this.hass.locale); - } - - drawChart() { - const data = this.data.data; - const ctx = this.$.chartCanvas; - - if ((!data.datasets || !data.datasets.length) && !this._chart) { - return; - } - if (this.data.type !== "timeline" && data.datasets.length > 0) { - const cnt = data.datasets.length; - const colors = this.constructor.getColorList(cnt); - for (let loopI = 0; loopI < cnt; loopI++) { - data.datasets[loopI].borderColor = colors[loopI].rgbString(); - data.datasets[loopI].backgroundColor = colors[loopI] - .alpha(0.6) - .rgbaString(); - } - } - - if (this._chart) { - this._customTooltips({ opacity: 0 }); - this._chart.data = data; - this._chart.update({ duration: 0 }); - if (this.isTimeline) { - this._chart.options.scales.yAxes[0].gridLines.display = data.length > 1; - } else if (this.data.legend === true) { - this._drawLegend(); - } - this.resizeChart(); - } else { - if (!data.datasets) { - return; - } - this._customTooltips({ opacity: 0 }); - const plugins = [{ afterRender: () => this._setRendered(true) }]; - let options = { - responsive: true, - maintainAspectRatio: false, - animation: { - duration: 0, - }, - hover: { - animationDuration: 0, - }, - responsiveAnimationDuration: 0, - tooltips: { - enabled: false, - custom: this._customTooltips.bind(this), - }, - legend: { - display: false, - }, - line: { - spanGaps: true, - }, - elements: { - font: "12px 'Roboto', 'sans-serif'", - }, - ticks: { - fontFamily: "'Roboto', 'sans-serif'", - }, - }; - options = Chart.helpers.merge(options, this.data.options); - options.scales.xAxes[0].ticks.callback = this._formatTickValue.bind(this); - if (this.data.type === "timeline") { - this.set("isTimeline", true); - if (this.data.colors !== undefined) { - this._colorFunc = this.constructor.getColorGenerator( - this.data.colors.staticColors, - this.data.colors.staticColorIndex - ); - } - if (this._colorFunc !== undefined) { - options.elements.colorFunction = this._colorFunc; - } - if (data.datasets.length === 1) { - if (options.scales.yAxes[0].ticks) { - options.scales.yAxes[0].ticks.display = false; - } else { - options.scales.yAxes[0].ticks = { display: false }; - } - if (options.scales.yAxes[0].gridLines) { - options.scales.yAxes[0].gridLines.display = false; - } else { - options.scales.yAxes[0].gridLines = { display: false }; - } - } - this.$.chartTarget.style.height = "50px"; - } else { - this.$.chartTarget.style.height = "160px"; - } - const chartData = { - type: this.data.type, - data: this.data.data, - options: options, - plugins: plugins, - }; - // Async resize after dom update - this._chart = new this.ChartClass(ctx, chartData); - if (this.isTimeline !== true && this.data.legend === true) { - this._drawLegend(); - } - this.resizeChart(); - } - } - - resizeChart() { - if (!this._chart) return; - // Chart not ready - if (this._resizeTimer === undefined) { - this._resizeTimer = setInterval(this.resizeChart.bind(this), 10); - return; - } - - clearInterval(this._resizeTimer); - this._resizeTimer = undefined; - - this._resizeChart(); - } - - _resizeChart() { - const chartTarget = this.$.chartTarget; - - const options = this.data; - const data = options.data; - - if (data.datasets.length === 0) { - return; - } - - if (!this.isTimeline) { - this._chart.resize(); - return; - } - - // Recalculate chart height for Timeline chart - const areaTop = this._chart.chartArea.top; - const areaBot = this._chart.chartArea.bottom; - const height1 = this._chart.canvas.clientHeight; - if (areaBot > 0) { - this._axisHeight = height1 - areaBot + areaTop; - } - - if (!this._axisHeight) { - chartTarget.style.height = "50px"; - this._chart.resize(); - this.resizeChart(); - return; - } - if (this._axisHeight) { - const cnt = data.datasets.length; - const targetHeight = 30 * cnt + this._axisHeight + "px"; - if (chartTarget.style.height !== targetHeight) { - chartTarget.style.height = targetHeight; - } - this._chart.resize(); - } - } - - // Get HSL distributed color list - static getColorList(count) { - let processL = false; - if (count > 10) { - processL = true; - count = Math.ceil(count / 2); - } - const h1 = 360 / count; - const result = []; - for (let loopI = 0; loopI < count; loopI++) { - result[loopI] = Color().hsl(h1 * loopI, 80, 38); - if (processL) { - result[loopI + count] = Color().hsl(h1 * loopI, 80, 62); - } - } - return result; - } - - static getColorGenerator(staticColors, startIndex) { - // Known colors for static data, - // should add for very common state string manually. - // Palette modified from http://google.github.io/palette.js/ mpn65, Apache 2.0 - const palette = [ - "ff0029", - "66a61e", - "377eb8", - "984ea3", - "00d2d5", - "ff7f00", - "af8d00", - "7f80cd", - "b3e900", - "c42e60", - "a65628", - "f781bf", - "8dd3c7", - "bebada", - "fb8072", - "80b1d3", - "fdb462", - "fccde5", - "bc80bd", - "ffed6f", - "c4eaff", - "cf8c00", - "1b9e77", - "d95f02", - "e7298a", - "e6ab02", - "a6761d", - "0097ff", - "00d067", - "f43600", - "4ba93b", - "5779bb", - "927acc", - "97ee3f", - "bf3947", - "9f5b00", - "f48758", - "8caed6", - "f2b94f", - "eff26e", - "e43872", - "d9b100", - "9d7a00", - "698cff", - "d9d9d9", - "00d27e", - "d06800", - "009f82", - "c49200", - "cbe8ff", - "fecddf", - "c27eb6", - "8cd2ce", - "c4b8d9", - "f883b0", - "a49100", - "f48800", - "27d0df", - "a04a9b", - ]; - function getColorIndex(idx) { - // Reuse the color if index too large. - return Color("#" + palette[idx % palette.length]); - } - const colorDict = {}; - let colorIndex = 0; - if (startIndex > 0) colorIndex = startIndex; - if (staticColors) { - Object.keys(staticColors).forEach((c) => { - const c1 = staticColors[c]; - if (isFinite(c1)) { - colorDict[c.toLowerCase()] = getColorIndex(c1); - } else { - colorDict[c.toLowerCase()] = Color(staticColors[c]); - } - }); - } - // Custom color assign - function getColor(__, data) { - let ret; - const name = data[3]; - if (name === null) return Color().hsl(0, 40, 38); - if (name === undefined) return Color().hsl(120, 40, 38); - let name1 = name.toLowerCase(); - if (ret === undefined) { - if (data[4]) { - // Invert on/off if data[4] is true. Required for some binary_sensor device classes - // (BINARY_SENSOR_DEVICE_CLASS_COLOR_INVERTED) where "off" is the good (= green color) value. - name1 = name1 === "on" ? "off" : name1 === "off" ? "on" : name1; - } - - ret = colorDict[name1]; - } - if (ret === undefined) { - ret = getColorIndex(colorIndex); - colorIndex++; - colorDict[name1] = ret; - } - return ret; - } - return getColor; - } -} -customElements.define("ha-chart-base", HaChartBase); diff --git a/src/components/state-history-chart-line.js b/src/components/state-history-chart-line.js deleted file mode 100644 index dc767fb45c..0000000000 --- a/src/components/state-history-chart-line.js +++ /dev/null @@ -1,433 +0,0 @@ -import "@polymer/polymer/lib/utils/debounce"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { formatDateTimeWithSeconds } from "../common/datetime/format_date_time"; -import LocalizeMixin from "../mixins/localize-mixin"; -import "./entity/ha-chart-base"; - -class StateHistoryChartLine extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - - - `; - } - - static get properties() { - return { - hass: { - type: Object, - }, - chartData: Object, - data: Object, - names: Object, - unit: String, - identifier: String, - - isSingleDevice: { - type: Boolean, - value: false, - }, - - endTime: Object, - rendered: { - type: Boolean, - value: false, - observer: "_onRenderedChanged", - }, - }; - } - - static get observers() { - return ["dataChanged(data, endTime, isSingleDevice)"]; - } - - connectedCallback() { - super.connectedCallback(); - this._isAttached = true; - this.drawChart(); - } - - ready() { - super.ready(); - // safari doesn't always render the canvas when we animate it, so we remove overflow hidden when the animation is complete - this.addEventListener("transitionend", () => { - this.style.overflow = "auto"; - }); - } - - dataChanged() { - this.drawChart(); - } - - _onRenderedChanged(rendered) { - if (rendered) { - this.animateHeight(); - } - } - - animateHeight() { - requestAnimationFrame(() => - requestAnimationFrame(() => { - this.style.height = this.$.chart.scrollHeight + "px"; - }) - ); - } - - drawChart() { - if (!this._isAttached) { - return; - } - - const unit = this.unit; - const deviceStates = this.data; - const datasets = []; - let endTime; - - if (deviceStates.length === 0) { - return; - } - - function safeParseFloat(value) { - const parsed = parseFloat(value); - return isFinite(parsed) ? parsed : null; - } - - endTime = - this.endTime || - // Get the highest date from the last date of each device - new Date( - Math.max.apply( - null, - deviceStates.map( - (devSts) => - new Date(devSts.states[devSts.states.length - 1].last_changed) - ) - ) - ); - if (endTime > new Date()) { - endTime = new Date(); - } - - const names = this.names || {}; - deviceStates.forEach((states) => { - const domain = states.domain; - const name = names[states.entity_id] || states.name; - // array containing [value1, value2, etc] - let prevValues; - const data = []; - - function pushData(timestamp, datavalues) { - if (!datavalues) return; - if (timestamp > endTime) { - // Drop datapoints that are after the requested endTime. This could happen if - // endTime is "now" and client time is not in sync with server time. - return; - } - data.forEach((d, i) => { - if (datavalues[i] === null && prevValues && prevValues[i] !== null) { - // null data values show up as gaps in the chart. - // If the current value for the dataset is null and the previous - // value of the data set is not null, then add an 'end' point - // to the chart for the previous value. Otherwise the gap will - // be too big. It will go from the start of the previous data - // value until the start of the next data value. - d.data.push({ x: timestamp, y: prevValues[i] }); - } - d.data.push({ x: timestamp, y: datavalues[i] }); - }); - prevValues = datavalues; - } - - function addColumn(nameY, step, fill) { - let dataFill = false; - let dataStep = false; - if (fill) { - dataFill = "origin"; - } - if (step) { - dataStep = "before"; - } - data.push({ - label: nameY, - fill: dataFill, - steppedLine: dataStep, - pointRadius: 0, - data: [], - unitText: unit, - }); - } - - if ( - domain === "thermostat" || - domain === "climate" || - domain === "water_heater" - ) { - const hasHvacAction = states.states.some( - (state) => state.attributes && state.attributes.hvac_action - ); - - const isHeating = - domain === "climate" && hasHvacAction - ? (state) => state.attributes.hvac_action === "heating" - : (state) => state.state === "heat"; - const isCooling = - domain === "climate" && hasHvacAction - ? (state) => state.attributes.hvac_action === "cooling" - : (state) => state.state === "cool"; - - const hasHeat = states.states.some(isHeating); - const hasCool = states.states.some(isCooling); - // We differentiate between thermostats that have a target temperature - // range versus ones that have just a target temperature - - // Using step chart by step-before so manually interpolation not needed. - const hasTargetRange = states.states.some( - (state) => - state.attributes && - state.attributes.target_temp_high !== - state.attributes.target_temp_low - ); - - addColumn( - `${this.hass.localize( - "ui.card.climate.current_temperature", - "name", - name - )}`, - true - ); - if (hasHeat) { - addColumn( - `${this.hass.localize("ui.card.climate.heating", "name", name)}`, - true, - true - ); - // The "heating" series uses steppedArea to shade the area below the current - // temperature when the thermostat is calling for heat. - } - if (hasCool) { - addColumn( - `${this.hass.localize("ui.card.climate.cooling", "name", name)}`, - true, - true - ); - // The "cooling" series uses steppedArea to shade the area below the current - // temperature when the thermostat is calling for heat. - } - - if (hasTargetRange) { - addColumn( - `${this.hass.localize( - "ui.card.climate.target_temperature_mode", - "name", - name, - "mode", - this.hass.localize("ui.card.climate.high") - )}`, - true - ); - addColumn( - `${this.hass.localize( - "ui.card.climate.target_temperature_mode", - "name", - name, - "mode", - this.hass.localize("ui.card.climate.low") - )}`, - true - ); - } else { - addColumn( - `${this.hass.localize( - "ui.card.climate.target_temperature_entity", - "name", - name - )}`, - true - ); - } - - states.states.forEach((state) => { - if (!state.attributes) return; - const curTemp = safeParseFloat(state.attributes.current_temperature); - const series = [curTemp]; - if (hasHeat) { - series.push(isHeating(state) ? curTemp : null); - } - if (hasCool) { - series.push(isCooling(state) ? curTemp : null); - } - if (hasTargetRange) { - const targetHigh = safeParseFloat( - state.attributes.target_temp_high - ); - const targetLow = safeParseFloat(state.attributes.target_temp_low); - series.push(targetHigh, targetLow); - pushData(new Date(state.last_changed), series); - } else { - const target = safeParseFloat(state.attributes.temperature); - series.push(target); - pushData(new Date(state.last_changed), series); - } - }); - } else if (domain === "humidifier") { - addColumn( - `${this.hass.localize( - "ui.card.humidifier.target_humidity_entity", - "name", - name - )}`, - true - ); - addColumn( - `${this.hass.localize("ui.card.humidifier.on_entity", "name", name)}`, - true, - true - ); - - states.states.forEach((state) => { - if (!state.attributes) return; - const target = safeParseFloat(state.attributes.humidity); - const series = [target]; - series.push(state.state === "on" ? target : null); - pushData(new Date(state.last_changed), series); - }); - } else { - // Only disable interpolation for sensors - const isStep = domain === "sensor"; - addColumn(name, isStep); - - let lastValue = null; - let lastDate = null; - let lastNullDate = null; - - // Process chart data. - // When state is `unknown`, calculate the value and break the line. - states.states.forEach((state) => { - const value = safeParseFloat(state.state); - const date = new Date(state.last_changed); - if (value !== null && lastNullDate !== null) { - const dateTime = date.getTime(); - const lastNullDateTime = lastNullDate.getTime(); - const lastDateTime = lastDate.getTime(); - const tmpValue = - (value - lastValue) * - ((lastNullDateTime - lastDateTime) / - (dateTime - lastDateTime)) + - lastValue; - pushData(lastNullDate, [tmpValue]); - pushData(new Date(lastNullDateTime + 1), [null]); - pushData(date, [value]); - lastDate = date; - lastValue = value; - lastNullDate = null; - } else if (value !== null && lastNullDate === null) { - pushData(date, [value]); - lastDate = date; - lastValue = value; - } else if ( - value === null && - lastNullDate === null && - lastValue !== null - ) { - lastNullDate = date; - } - }); - } - - // Add an entry for final values - pushData(endTime, prevValues, false); - - // Concat two arrays - Array.prototype.push.apply(datasets, data); - }); - - const formatTooltipTitle = (items, data) => { - const item = items[0]; - const date = data.datasets[item.datasetIndex].data[item.index].x; - - return formatDateTimeWithSeconds(date, this.hass.locale); - }; - - const chartOptions = { - type: "line", - unit: unit, - legend: !this.isSingleDevice, - options: { - scales: { - xAxes: [ - { - type: "time", - ticks: { - major: { - fontStyle: "bold", - }, - source: "auto", - sampleSize: 5, - autoSkipPadding: 20, - maxRotation: 0, - }, - }, - ], - yAxes: [ - { - ticks: { - maxTicksLimit: 7, - }, - }, - ], - }, - tooltips: { - mode: "neareach", - callbacks: { - title: formatTooltipTitle, - }, - }, - hover: { - mode: "neareach", - }, - layout: { - padding: { - top: 5, - }, - }, - elements: { - line: { - tension: 0.1, - pointRadius: 0, - borderWidth: 1.5, - }, - point: { - hitRadius: 5, - }, - }, - plugins: { - filler: { - propagate: true, - }, - }, - }, - data: { - labels: [], - datasets: datasets, - }, - }; - this.chartData = chartOptions; - } -} -customElements.define("state-history-chart-line", StateHistoryChartLine); diff --git a/src/components/state-history-chart-timeline.js b/src/components/state-history-chart-timeline.js deleted file mode 100644 index fa29388da3..0000000000 --- a/src/components/state-history-chart-timeline.js +++ /dev/null @@ -1,286 +0,0 @@ -import "@polymer/polymer/lib/utils/debounce"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { formatDateTimeWithSeconds } from "../common/datetime/format_date_time"; -import { computeDomain } from "../common/entity/compute_domain"; -import { computeRTL } from "../common/util/compute_rtl"; -import LocalizeMixin from "../mixins/localize-mixin"; -import "./entity/ha-chart-base"; - -/** Binary sensor device classes for which the static colors for on/off need to be inverted. - * List the ones were "off" = good or normal state = should be rendered "green". - */ -const BINARY_SENSOR_DEVICE_CLASS_COLOR_INVERTED = new Set([ - "battery", - "door", - "garage_door", - "gas", - "lock", - "opening", - "problem", - "safety", - "smoke", - "window", -]); - -class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - - - `; - } - - static get properties() { - return { - hass: { - type: Object, - }, - chartData: Object, - data: { - type: Object, - observer: "dataChanged", - }, - names: Object, - noSingle: Boolean, - endTime: Date, - rendered: { - type: Boolean, - value: false, - reflectToAttribute: true, - }, - rtl: { - reflectToAttribute: true, - computed: "_computeRTL(hass)", - }, - }; - } - - static get observers() { - return ["dataChanged(data, endTime, localize, language)"]; - } - - connectedCallback() { - super.connectedCallback(); - this._isAttached = true; - this.drawChart(); - } - - dataChanged() { - this.drawChart(); - } - - drawChart() { - const staticColors = { - on: 1, - off: 0, - home: 1, - not_home: 0, - unavailable: "#a0a0a0", - unknown: "#606060", - idle: 2, - }; - let stateHistory = this.data; - - if (!this._isAttached) { - return; - } - - if (!stateHistory) { - stateHistory = []; - } - - const startTime = new Date( - stateHistory.reduce( - (minTime, stateInfo) => - Math.min(minTime, new Date(stateInfo.data[0].last_changed)), - new Date() - ) - ); - - // end time is Math.max(startTime, last_event) - let endTime = - this.endTime || - new Date( - stateHistory.reduce( - (maxTime, stateInfo) => - Math.max( - maxTime, - new Date(stateInfo.data[stateInfo.data.length - 1].last_changed) - ), - startTime - ) - ); - - if (endTime > new Date()) { - endTime = new Date(); - } - - const labels = []; - const datasets = []; - // stateHistory is a list of lists of sorted state objects - const names = this.names || {}; - stateHistory.forEach((stateInfo) => { - let newLastChanged; - let prevState = null; - let locState = null; - let prevLastChanged = startTime; - const entityDisplay = names[stateInfo.entity_id] || stateInfo.name; - - const invertOnOff = - computeDomain(stateInfo.entity_id) === "binary_sensor" && - BINARY_SENSOR_DEVICE_CLASS_COLOR_INVERTED.has( - this.hass.states[stateInfo.entity_id].attributes.device_class - ); - - const dataRow = []; - stateInfo.data.forEach((state) => { - let newState = state.state; - const timeStamp = new Date(state.last_changed); - if (newState === undefined || newState === "") { - newState = null; - } - if (timeStamp > endTime) { - // Drop datapoints that are after the requested endTime. This could happen if - // endTime is 'now' and client time is not in sync with server time. - return; - } - if (prevState !== null && newState !== prevState) { - newLastChanged = new Date(state.last_changed); - - dataRow.push([ - prevLastChanged, - newLastChanged, - locState, - prevState, - invertOnOff, - ]); - - prevState = newState; - locState = state.state_localize; - prevLastChanged = newLastChanged; - } else if (prevState === null) { - prevState = newState; - locState = state.state_localize; - prevLastChanged = new Date(state.last_changed); - } - }); - - if (prevState !== null) { - dataRow.push([ - prevLastChanged, - endTime, - locState, - prevState, - invertOnOff, - ]); - } - datasets.push({ - data: dataRow, - entity_id: stateInfo.entity_id, - }); - labels.push(entityDisplay); - }); - - const formatTooltipLabel = (item, data) => { - const values = data.datasets[item.datasetIndex].data[item.index]; - - const start = formatDateTimeWithSeconds(values[0], this.hass.locale); - const end = formatDateTimeWithSeconds(values[1], this.hass.locale); - const state = values[2]; - - return [state, start, end]; - }; - - const formatTooltipBeforeBody = (item, data) => { - if (!this.hass.userData || !this.hass.userData.showAdvanced || !item[0]) { - return ""; - } - // Extract the entity ID from the dataset. - const values = data.datasets[item[0].datasetIndex]; - return values.entity_id || ""; - }; - - const chartOptions = { - type: "timeline", - options: { - tooltips: { - callbacks: { - label: formatTooltipLabel, - beforeBody: formatTooltipBeforeBody, - }, - }, - scales: { - xAxes: [ - { - ticks: { - major: { - fontStyle: "bold", - }, - sampleSize: 5, - autoSkipPadding: 50, - maxRotation: 0, - }, - categoryPercentage: undefined, - barPercentage: undefined, - time: { - format: undefined, - }, - }, - ], - yAxes: [ - { - afterSetDimensions: (yaxe) => { - yaxe.maxWidth = yaxe.chart.width * 0.18; - }, - position: this._computeRTL ? "right" : "left", - categoryPercentage: undefined, - barPercentage: undefined, - time: { format: undefined }, - }, - ], - }, - }, - datasets: { - categoryPercentage: 0.8, - barPercentage: 0.9, - }, - data: { - labels: labels, - datasets: datasets, - }, - colors: { - staticColors: staticColors, - staticColorIndex: 3, - }, - }; - this.chartData = chartOptions; - } - - _computeRTL(hass) { - return computeRTL(hass); - } -} -customElements.define( - "state-history-chart-timeline", - StateHistoryChartTimeline -); diff --git a/src/dialogs/more-info/ha-more-info-history.ts b/src/dialogs/more-info/ha-more-info-history.ts index 6dcb3144de..199e8e9490 100644 --- a/src/dialogs/more-info/ha-more-info-history.ts +++ b/src/dialogs/more-info/ha-more-info-history.ts @@ -2,7 +2,7 @@ import { html, LitElement, PropertyValues, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { throttle } from "../../common/util/throttle"; -import "../../components/state-history-charts"; +import "../../components/chart/state-history-charts"; import { getRecentWithCache } from "../../data/cached-history"; import { HistoryResult } from "../../data/history"; import { HomeAssistant } from "../../types"; diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index 90d01e75a9..f109633e53 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -4,7 +4,6 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { throttle } from "../../common/util/throttle"; import "../../components/ha-circular-progress"; -import "../../components/state-history-charts"; import { fetchUsers } from "../../data/user"; import { getLogbookData, LogbookEntry } from "../../data/logbook"; import { loadTraceContexts, TraceContexts } from "../../data/trace"; diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index 31737c8874..cef5aa53c3 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -8,7 +8,7 @@ import "../../components/ha-circular-progress"; import "../../components/ha-date-range-picker"; import type { DateRangePickerRanges } from "../../components/ha-date-range-picker"; import "../../components/ha-menu-button"; -import "../../components/state-history-charts"; +import "../../components/chart/state-history-charts"; import { computeHistory, fetchDate } from "../../data/history"; import "../../layouts/ha-app-layout"; import { haStyle } from "../../resources/styles"; diff --git a/src/panels/lovelace/cards/hui-history-graph-card.ts b/src/panels/lovelace/cards/hui-history-graph-card.ts index b17a1ad1e0..b61f3c0512 100644 --- a/src/panels/lovelace/cards/hui-history-graph-card.ts +++ b/src/panels/lovelace/cards/hui-history-graph-card.ts @@ -10,7 +10,7 @@ import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { throttle } from "../../../common/util/throttle"; import "../../../components/ha-card"; -import "../../../components/state-history-charts"; +import "../../../components/chart/state-history-charts"; import { CacheConfig, getRecentWithCache } from "../../../data/cached-history"; import { HistoryResult } from "../../../data/history"; import { HomeAssistant } from "../../../types"; @@ -139,8 +139,8 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard { .isLoadingData=${!this._stateHistory} .historyData=${this._stateHistory} .names=${this._names} - .upToNow=${true} - .noSingle=${true} + up-to-now + no-single >
diff --git a/src/panels/lovelace/cards/hui-map-card.ts b/src/panels/lovelace/cards/hui-map-card.ts index e6c825d9b9..88ccf2104c 100644 --- a/src/panels/lovelace/cards/hui-map-card.ts +++ b/src/panels/lovelace/cards/hui-map-card.ts @@ -25,23 +25,10 @@ import "../../../components/map/ha-map"; import { mdiImageFilterCenterFocus } from "@mdi/js"; import type { HaMap, HaMapPaths } from "../../../components/map/ha-map"; import memoizeOne from "memoize-one"; +import { getColorByIndex } from "../../../common/color/colors"; const MINUTE = 60000; -const COLORS = [ - "#0288D1", - "#00AA00", - "#984ea3", - "#00d2d5", - "#ff7f00", - "#af8d00", - "#7f80cd", - "#b3e900", - "#c42e60", - "#a65628", - "#f781bf", - "#8dd3c7", -]; @customElement("hui-map-card") class HuiMapCard extends LitElement implements LovelaceCard { @property({ attribute: false }) public hass!: HomeAssistant; @@ -225,7 +212,7 @@ class HuiMapCard extends LitElement implements LovelaceCard { if (color) { return color; } - color = COLORS[this._colorIndex % COLORS.length]; + color = getColorByIndex(this._colorIndex); this._colorIndex++; this._colorDict[entityId] = color; return color; diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 1d50d04180..19ba06708a 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -447,47 +447,37 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { --name-font-size: 1.2rem; --brightness-font-size: 1.2rem; --rail-border-color: transparent; - --auto-color: green; - --eco-color: springgreen; - --cool-color: #2b9af9; - --heat-color: #ff8100; - --manual-color: #44739e; - --off-color: #8a8a8a; - --fan_only-color: #8a8a8a; - --dry-color: #efbd07; - --idle-color: #8a8a8a; - --unknown-color: #bac; } .auto, .heat_cool { - --mode-color: var(--auto-color); + --mode-color: var(--state-climate-auto-color); } .cool { - --mode-color: var(--cool-color); + --mode-color: var(--state-climate-cool-color); } .heat { - --mode-color: var(--heat-color); + --mode-color: var(--state-climate-heat-color); } .manual { - --mode-color: var(--manual-color); + --mode-color: var(--state-climate-manual-color); } .off { - --mode-color: var(--off-color); + --mode-color: var(--state-climate-off-color); } .fan_only { - --mode-color: var(--fan_only-color); + --mode-color: var(--state-climate-fan_only-color); } .eco { - --mode-color: var(--eco-color); + --mode-color: var(--state-climate-eco-color); } .dry { - --mode-color: var(--dry-color); + --mode-color: var(--state-climate-dry-color); } .idle { - --mode-color: var(--idle-color); + --mode-color: var(--state-climate-idle-color); } .unknown-mode { - --mode-color: var(--unknown-color); + --mode-color: var(--state-unknown-color); } .more-info { diff --git a/src/resources/chartjs.ts b/src/resources/chartjs.ts new file mode 100644 index 0000000000..811addaa8b --- /dev/null +++ b/src/resources/chartjs.ts @@ -0,0 +1,35 @@ +import { + LineController, + TimeScale, + LinearScale, + PointElement, + LineElement, + Filler, + Legend, + Title, + Tooltip, + CategoryScale, + Chart, +} from "chart.js"; +import { TextBarElement } from "../components/chart/timeline-chart/textbar-element"; +import { TimelineController } from "../components/chart/timeline-chart/timeline-controller"; +import { TimeLineScale } from "../components/chart/timeline-chart/timeline-scale"; +import "../components/chart/chart-date-adapter"; + +export { Chart } from "chart.js"; + +Chart.register( + Tooltip, + Title, + Legend, + Filler, + TimeScale, + LinearScale, + LineController, + PointElement, + LineElement, + TextBarElement, + TimeLineScale, + TimelineController, + CategoryScale +); diff --git a/src/resources/ha-chart-scripts.js b/src/resources/ha-chart-scripts.js deleted file mode 100644 index 500c803788..0000000000 --- a/src/resources/ha-chart-scripts.js +++ /dev/null @@ -1,60 +0,0 @@ -import Chart from "chart.js"; -import "chartjs-chart-timeline"; - -// This function add a new interaction mode to Chart.js that -// returns one point for every dataset. -Chart.Interaction.modes.neareach = function (chart, e, options) { - const getRange = { - x: (a, b) => Math.abs(a.x - b.x), - y: (a, b) => Math.abs(a.y - b.y), - // eslint-disable-next-line no-restricted-properties - xy: (a, b) => Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2), - }; - const getRangeMax = { - x: (r) => r, - y: (r) => r, - xy: (r) => r * r, - }; - let position; - if (e.native) { - position = { - x: e.x, - y: e.y, - }; - } else { - position = Chart.helpers.getRelativePosition(e, chart); - } - const elements = []; - const elementsRange = []; - const datasets = chart.data.datasets; - let meta; - options.axis = options.axis || "xy"; - const rangeFunc = getRange[options.axis]; - const rangeMaxFunc = getRangeMax[options.axis]; - - for (let i = 0, ilen = datasets.length; i < ilen; ++i) { - if (!chart.isDatasetVisible(i)) { - continue; - } - - meta = chart.getDatasetMeta(i); - for (let j = 0, jlen = meta.data.length; j < jlen; ++j) { - const element = meta.data[j]; - if (!element._view.skip) { - const vm = element._view; - const range = rangeFunc(vm, position); - const oldRange = elementsRange[i]; - if (range < rangeMaxFunc(vm.radius + vm.hitRadius)) { - if (oldRange === undefined || oldRange > range) { - elementsRange[i] = range; - elements[i] = element; - } - } - } - } - } - const ret = elements.filter((n) => n !== undefined); - return ret; -}; - -export default Chart; diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts index 82439c105e..fbfeb09eed 100644 --- a/src/resources/ha-style.ts +++ b/src/resources/ha-style.ts @@ -42,10 +42,6 @@ documentContainer.innerHTML = ` --success-color: #0f9d58; --info-color: #4285f4; - /* states and badges */ - --state-icon-color: #44739e; - --state-icon-active-color: #FDD835; - /* background and sidebar */ --card-background-color: #ffffff; --primary-background-color: #fafafa; @@ -60,6 +56,32 @@ documentContainer.innerHTML = ` --label-badge-green: #0DA035; --label-badge-yellow: #f4b400; + /* states and badges */ + --state-icon-color: #44739e; + /* an active state is anything that would require attention */ + --state-icon-active-color: #FDD835; + /* an error state is anything that would be considered an error */ + /* --state-icon-error-color: #db4437; derived from error-color */ + + --state-on-color: #66a61e; + --state-off-color: #ff0029; + --state-home-color: #66a61e; + --state-not_home-color: #ff0029; + /* --state-unavailable-color: #a0a0a0; derived from disabled-text-color */ + --state-unknown-color: #606060; + --state-idle-color: #377eb8; + + /* climate state colors */ + --state-climate-auto-color: #008000; + --state-climate-eco-color: #00ff7f; + --state-climate-cool-color: #2b9af9; + --state-climate-heat-color: #ff8100; + --state-climate-manual-color: #44739e; + --state-climate-off-color: #8a8a8a; + --state-climate-fan_only-color: #8a8a8a; + --state-climate-dry-color: #efbd07; + --state-climate-idle-color: #8a8a8a; + /* Paper-styles color.html dependency is stripped on build. When a default paper-style color is used, it needs to be copied diff --git a/src/resources/styles.ts b/src/resources/styles.ts index 54e298f1c2..035832e689 100644 --- a/src/resources/styles.ts +++ b/src/resources/styles.ts @@ -34,8 +34,9 @@ export const darkStyles = { }; export const derivedStyles = { - "error-state-color": "var(--error-color)", - "state-icon-unavailable-color": "var(--disabled-text-color)", + "state-icon-error-color": "var(--error-state-color, var(--error-color))", + "state-unavailable-color": + "var(--state-icon-unavailable-color, var(--disabled-text-color))", "sidebar-text-color": "var(--primary-text-color)", "sidebar-background-color": "var(--card-background-color)", "sidebar-selected-text-color": "var(--primary-color)", diff --git a/yarn.lock b/yarn.lock index eae3bc00de..1671fdf6e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4634,33 +4634,10 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chart.js@^2.9.4: - version "2.9.4" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684" - integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A== - dependencies: - chartjs-color "^2.1.0" - moment "^2.10.2" - -chartjs-chart-timeline@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chartjs-chart-timeline/-/chartjs-chart-timeline-0.4.0.tgz#cbd25dc5ddb5c2b34289f8dd7a2a627d71e251e8" - integrity sha512-a3iOFgMUXgEK9zyDFXlL7cfhO6z4DkeuGqok1xnNVNg12ciSt/k1jDBFk8JKN+sVNZfoqeGAFBT9zvb++iEWnA== - -chartjs-color-string@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71" - integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A== - dependencies: - color-name "^1.0.0" - -chartjs-color@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.3.0.tgz#0e7e1e8dba37eae8415fd3db38bf572007dd958f" - integrity sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g== - dependencies: - chartjs-color-string "^0.6.0" - color-convert "^0.5.3" +chart.js@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.3.2.tgz#667f3a0b6371b9719d8949c04a5bcbaec0d8c615" + integrity sha512-H0hSO7xqTIrwxoACqnSoNromEMfXvfuVnrbuSt2TuXfBDDofbnto4zuZlRtRvC73/b37q3wGAWZyUU41QPvNbA== check-error@^1.0.2: version "1.0.2" @@ -4942,11 +4919,6 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" - integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0= - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -4966,7 +4938,7 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== @@ -5360,6 +5332,11 @@ d@1: dependencies: es5-ext "^0.10.9" +date-fns@^2.22.1: + version "2.22.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.22.1.tgz#1e5af959831ebb1d82992bf67b765052d8f0efc4" + integrity sha512-yUFPQjrxEmIsMqlHhAhmxkuH769baF21Kk+nZwZGyrMoyLA+LugaQtC0+Tqf9CBUUULWwUJt6Q5ySI3LJDDCGg== + dateformat@^1.0.7-1.2.3: version "1.0.12" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" @@ -9425,11 +9402,6 @@ mocha@^8.4.0: yargs-parser "20.2.4" yargs-unparser "2.0.0" -moment@^2.10.2: - version "2.24.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" - integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" From cecb66451c7748db60ebcab29387aaf820048afa Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 19 Jun 2021 00:48:32 +0000 Subject: [PATCH 39/73] Translation update --- translations/frontend/bg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/frontend/bg.json b/translations/frontend/bg.json index a04a0754f6..af50e2574f 100644 --- a/translations/frontend/bg.json +++ b/translations/frontend/bg.json @@ -1113,7 +1113,7 @@ "buttons": { "add": "Добавете устройства чрез това устройство", "clusters": "Управление на клъстери", - "device_children": "Преглед на дъщерни", + "device_children": "Преглед на дъщерните устройства", "reconfigure": "Преконфигуриране на устройството", "remove": "Премахване на устройството", "zigbee_information": "Подпис на Zigbee устройството" From c1d571de42c41a60aac7884e3c2d6b298ccb10b0 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sat, 19 Jun 2021 13:26:19 +0200 Subject: [PATCH 40/73] Add Select entity (#9422) Co-authored-by: Bram Kragten --- src/common/const.ts | 3 + src/data/select.ts | 25 +++ .../create-element/create-row-element.ts | 2 + .../entity-rows/hui-select-entity-row.ts | 186 ++++++++++++++++++ src/state-summary/state-card-content.js | 1 + src/state-summary/state-card-select.ts | 99 ++++++++++ 6 files changed, 316 insertions(+) create mode 100644 src/data/select.ts create mode 100644 src/panels/lovelace/entity-rows/hui-select-entity-row.ts create mode 100644 src/state-summary/state-card-select.ts diff --git a/src/common/const.ts b/src/common/const.ts index 6ec749d662..40374552e0 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -42,6 +42,7 @@ export const FIXED_DOMAIN_ICONS = { remote: "hass:remote", scene: "hass:palette", script: "hass:script-text", + select: "hass:format-list-bulleted", sensor: "hass:eye", simple_alarm: "hass:bell", sun: "hass:white-balance-sunny", @@ -83,6 +84,7 @@ export const DOMAINS_WITH_CARD = [ "number", "scene", "script", + "select", "timer", "vacuum", "water_heater", @@ -121,6 +123,7 @@ export const DOMAINS_HIDE_MORE_INFO = [ "input_text", "number", "scene", + "select", ]; /** Domains that should have the history hidden in the more info dialog. */ diff --git a/src/data/select.ts b/src/data/select.ts new file mode 100644 index 0000000000..9d7058d8ce --- /dev/null +++ b/src/data/select.ts @@ -0,0 +1,25 @@ +import { + HassEntityAttributeBase, + HassEntityBase, +} from "home-assistant-js-websocket"; +import { HomeAssistant } from "../types"; + +interface SelectEntityAttributes extends HassEntityAttributeBase { + options: string[]; +} + +export interface SelectEntity extends HassEntityBase { + attributes: SelectEntityAttributes; +} + +export const setSelectOption = ( + hass: HomeAssistant, + entity: string, + option: string +) => + hass.callService( + "select", + "select_option", + { option }, + { entity_id: entity } + ); diff --git a/src/panels/lovelace/create-element/create-row-element.ts b/src/panels/lovelace/create-element/create-row-element.ts index 955f4741c9..f1b63c717c 100644 --- a/src/panels/lovelace/create-element/create-row-element.ts +++ b/src/panels/lovelace/create-element/create-row-element.ts @@ -37,6 +37,7 @@ const LAZY_LOAD_TYPES = { "input-text-entity": () => import("../entity-rows/hui-input-text-entity-row"), "lock-entity": () => import("../entity-rows/hui-lock-entity-row"), "number-entity": () => import("../entity-rows/hui-number-entity-row"), + "select-entity": () => import("../entity-rows/hui-select-entity-row"), "timer-entity": () => import("../entity-rows/hui-timer-entity-row"), conditional: () => import("../special-rows/hui-conditional-row"), "weather-entity": () => import("../entity-rows/hui-weather-entity-row"), @@ -68,6 +69,7 @@ const DOMAIN_TO_ELEMENT_TYPE = { remote: "toggle", scene: "scene", script: "script", + select: "select", sensor: "sensor", timer: "timer", switch: "toggle", diff --git a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts new file mode 100644 index 0000000000..7133db16f8 --- /dev/null +++ b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts @@ -0,0 +1,186 @@ +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { ifDefined } from "lit/directives/if-defined"; +import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const"; +import { stopPropagation } from "../../../common/dom/stop_propagation"; +import { computeDomain } from "../../../common/entity/compute_domain"; +import { computeStateName } from "../../../common/entity/compute_state_name"; +import "../../../components/entity/state-badge"; +import "../../../components/ha-paper-dropdown-menu"; +import { UNAVAILABLE_STATES } from "../../../data/entity"; +import { forwardHaptic } from "../../../data/haptics"; +import { SelectEntity, setSelectOption } from "../../../data/select"; +import { ActionHandlerEvent } from "../../../data/lovelace"; +import { HomeAssistant } from "../../../types"; +import { EntitiesCardEntityConfig } from "../cards/types"; +import { actionHandler } from "../common/directives/action-handler-directive"; +import { handleAction } from "../common/handle-action"; +import { hasAction } from "../common/has-action"; +import { hasConfigOrEntityChanged } from "../common/has-changed"; +import { createEntityNotFoundWarning } from "../components/hui-warning"; +import { LovelaceRow } from "./types"; + +@customElement("hui-select-entity-row") +class HuiSelectEntityRow extends LitElement implements LovelaceRow { + @property({ attribute: false }) public hass?: HomeAssistant; + + @state() private _config?: EntitiesCardEntityConfig; + + public setConfig(config: EntitiesCardEntityConfig): void { + if (!config || !config.entity) { + throw new Error("Entity must be specified"); + } + + this._config = config; + } + + protected shouldUpdate(changedProps: PropertyValues): boolean { + return hasConfigOrEntityChanged(this, changedProps); + } + + protected render(): TemplateResult { + if (!this.hass || !this._config) { + return html``; + } + + const stateObj = this.hass.states[this._config.entity] as + | SelectEntity + | undefined; + + if (!stateObj) { + return html` + + ${createEntityNotFoundWarning(this.hass, this._config.entity)} + + `; + } + + const pointer = + (this._config.tap_action && this._config.tap_action.action !== "none") || + (this._config.entity && + !DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this._config.entity))); + + return html` + + + + ${stateObj.attributes.options + ? stateObj.attributes.options.map( + (option) => + html` + ${(stateObj.attributes.device_class && + this.hass!.localize( + `component.select.state.${stateObj.attributes.device_class}.${option}` + )) || + this.hass!.localize( + `component.select.state._.${option}` + ) || + option} + ` + ) + : ""} + + + `; + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + + if (!this.hass || !this._config) { + return; + } + + const stateObj = this.hass.states[this._config.entity] as + | SelectEntity + | undefined; + + if (!stateObj) { + return; + } + + // Update selected after rendering the items or else it won't work in Firefox + if (stateObj.attributes.options) { + this.shadowRoot!.querySelector( + "paper-listbox" + )!.selected = stateObj.attributes.options.indexOf(stateObj.state); + } + } + + private _handleAction(ev: ActionHandlerEvent) { + handleAction(this, this.hass!, this._config!, ev.detail.action!); + } + + static get styles(): CSSResultGroup { + return css` + :host { + display: flex; + align-items: center; + } + ha-paper-dropdown-menu { + margin-left: 16px; + flex: 1; + } + paper-item { + cursor: pointer; + min-width: 200px; + } + .pointer { + cursor: pointer; + } + state-badge:focus { + outline: none; + background: var(--divider-color); + border-radius: 100%; + } + `; + } + + private _selectedChanged(ev): void { + const stateObj = this.hass!.states[this._config!.entity]; + const option = ev.target.selectedItem.option; + if (option === stateObj.state) { + return; + } + + forwardHaptic("light"); + + setSelectOption(this.hass!, stateObj.entity_id, option); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-select-entity-row": HuiSelectEntityRow; + } +} diff --git a/src/state-summary/state-card-content.js b/src/state-summary/state-card-content.js index 8a365f612a..f3ee74bbf3 100644 --- a/src/state-summary/state-card-content.js +++ b/src/state-summary/state-card-content.js @@ -14,6 +14,7 @@ import "./state-card-media_player"; import "./state-card-number"; import "./state-card-scene"; import "./state-card-script"; +import "./state-card-select"; import "./state-card-timer"; import "./state-card-toggle"; import "./state-card-vacuum"; diff --git a/src/state-summary/state-card-select.ts b/src/state-summary/state-card-select.ts new file mode 100644 index 0000000000..0876f71e41 --- /dev/null +++ b/src/state-summary/state-card-select.ts @@ -0,0 +1,99 @@ +import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; +import { customElement, property } from "lit/decorators"; +import { stopPropagation } from "../common/dom/stop_propagation"; +import { computeStateName } from "../common/entity/compute_state_name"; +import "../components/entity/state-badge"; +import { SelectEntity, setSelectOption } from "../data/select"; +import type { HomeAssistant } from "../types"; + +@customElement("state-card-select") +class StateCardSelect extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public stateObj!: SelectEntity; + + protected render(): TemplateResult { + return html` + + + + ${this.stateObj.attributes.options.map( + (option) => + html` + ${(this.stateObj.attributes.device_class && + this.hass.localize( + `component.select.state.${this.stateObj.attributes.device_class}.${option}` + )) || + this.hass.localize(`component.select.state._.${option}`) || + option} + ` + )} + + + `; + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if (!changedProps.has("stateObj")) { + return; + } + // Update selected after rendering the items or else it won't work in Firefox + this.shadowRoot!.querySelector( + "paper-listbox" + )!.selected = this.stateObj.attributes.options.indexOf(this.stateObj.state); + } + + private _selectedOptionChanged(ev) { + const option = ev.target.selectedItem.option; + if (option === this.stateObj.state) { + return; + } + setSelectOption(this.hass, this.stateObj.entity_id, option); + } + + static get styles(): CSSResultGroup { + return css` + :host { + display: block; + } + + state-badge { + float: left; + margin-top: 10px; + } + + paper-dropdown-menu-light { + display: block; + margin-left: 53px; + } + + paper-item { + cursor: pointer; + min-width: 200px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "state-card-select": StateCardSelect; + } +} From 7745c10d079980ad0381211d1a809f89b96aaaa1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 20 Jun 2021 00:48:37 +0000 Subject: [PATCH 41/73] Translation update --- translations/frontend/ca.json | 6 +++--- translations/frontend/ru.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index d4a80333ba..c15932954c 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -558,9 +558,9 @@ }, "counter": { "actions": { - "decrement": "decreixement", - "increment": "increment", - "reset": "restablir" + "decrement": "decrementa", + "increment": "incrementa", + "reset": "restableix" } }, "cover": { diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 6254ed7396..b611bf919d 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -1022,9 +1022,9 @@ }, "input_select": { "add": "Добавить", - "add_option": "Добавить опцию", - "no_options": "Добавьте доступные для выбора опции.", - "options": "Опции" + "add_option": "Добавить вариант", + "no_options": "Добавьте доступные для выбора варианты.", + "options": "Варианты" }, "input_text": { "max": "Максимальная длина", From 2c9aa1cab420dd991dd427d012c75331ce41d24e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 21 Jun 2021 00:48:39 +0000 Subject: [PATCH 42/73] Translation update --- translations/frontend/de.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/frontend/de.json b/translations/frontend/de.json index 1ac790a99c..89fa98cd1d 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -820,6 +820,7 @@ "was_unplugged": "wurde ausgesteckt", "was_unsafe": "war unsicher" }, + "retrieval_error": "Fehler beim Abrufen von Logbucheinträgen", "show_trace": "Trace anzeigen" }, "media-browser": { From 14fcff7774b615125f2629ea34c4f450e8e4758b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 21 Jun 2021 09:41:06 +0200 Subject: [PATCH 43/73] Fix secrets schema (#9446) --- hassio/src/addon-view/config/hassio-addon-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/src/addon-view/config/hassio-addon-config.ts b/hassio/src/addon-view/config/hassio-addon-config.ts index 199a5f8af2..661f3a118c 100644 --- a/hassio/src/addon-view/config/hassio-addon-config.ts +++ b/hassio/src/addon-view/config/hassio-addon-config.ts @@ -134,7 +134,7 @@ class HassioAddonConfig extends LitElement { >` : html` `} ${this._error ? html`
${this._error}
` : ""} ${!this._yamlMode || From 202d6957bc2cd98cb4c9a55d71a2ac909ff08b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 21 Jun 2021 09:41:38 +0200 Subject: [PATCH 44/73] Allow clearing values in optional selects (#9442) Co-authored-by: Bram Kragten --- src/components/ha-form/ha-form-select.ts | 54 +++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/components/ha-form/ha-form-select.ts b/src/components/ha-form/ha-form-select.ts index 5cf9dc013d..c796bc8baf 100644 --- a/src/components/ha-form/ha-form-select.ts +++ b/src/components/ha-form/ha-form-select.ts @@ -1,14 +1,19 @@ +import "@material/mwc-icon-button/mwc-icon-button"; +import { mdiClose, mdiMenuDown } from "@mdi/js"; +import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; +import "@polymer/paper-menu-button/paper-menu-button"; +import "@polymer/paper-ripple/paper-ripple"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; -import "../ha-paper-dropdown-menu"; +import "../ha-svg-icon"; import { HaFormElement, HaFormSelectData, HaFormSelectSchema } from "./ha-form"; @customElement("ha-form-select") export class HaFormSelect extends LitElement implements HaFormElement { - @property() public schema!: HaFormSelectSchema; + @property({ attribute: false }) public schema!: HaFormSelectSchema; @property() public data!: HaFormSelectData; @@ -26,7 +31,33 @@ export class HaFormSelect extends LitElement implements HaFormElement { protected render(): TemplateResult { return html` - + + - + `; } @@ -57,6 +88,11 @@ export class HaFormSelect extends LitElement implements HaFormElement { return Array.isArray(item) ? item[1] || item[0] : item; } + private _clearValue(ev: CustomEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { value: undefined }); + } + private _valueChanged(ev: CustomEvent) { if (!ev.detail.value) { return; @@ -68,8 +104,16 @@ export class HaFormSelect extends LitElement implements HaFormElement { static get styles(): CSSResultGroup { return css` - ha-paper-dropdown-menu { + paper-menu-button { display: block; + padding: 0; + } + paper-input > mwc-icon-button { + --mdc-icon-button-size: 24px; + padding: 2px; + } + .clear-button { + color: var(--secondary-text-color); } `; } From 9a4a1cb4ecc5515355e3627c2c31cce843e993e5 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 21 Jun 2021 10:38:50 +0200 Subject: [PATCH 45/73] Fix charts tooltips and legends (#9448) --- src/components/chart/ha-chart-base.ts | 146 ++++++++++++++++++++------ 1 file changed, 116 insertions(+), 30 deletions(-) diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index a976083c34..142f8252f7 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -11,6 +11,11 @@ import { classMap } from "lit/directives/class-map"; import { styleMap } from "lit/directives/style-map"; import { clamp } from "../../common/number/clamp"; +interface Tooltip extends TooltipModel { + top: string; + left: string; +} + @customElement("ha-chart-base") export default class HaChartBase extends LitElement { public chart?: Chart; @@ -24,12 +29,19 @@ export default class HaChartBase extends LitElement { @property({ attribute: false }) public options?: ChartOptions; - @state() private _tooltip?: TooltipModel; + @state() private _tooltip?: Tooltip; @state() private _height?: string; + @state() private _hiddenDatasets: Set = new Set(); + protected firstUpdated() { this._setupChart(); + this.data.datasets.forEach((dataset, index) => { + if (dataset.hidden) { + this._hiddenDatasets.add(index); + } + }); } public willUpdate(changedProps: PropertyValues): void { @@ -54,6 +66,30 @@ export default class HaChartBase extends LitElement { protected render() { return html` + ${this.options?.plugins?.legend?.display === true + ? html`
+
    + ${this.data.datasets.map( + (dataset, index) => html`
  • +
    + ${dataset.label} +
  • ` + )} +
+
` + : ""}
${this._tooltip.title}
@@ -85,15 +119,16 @@ export default class HaChartBase extends LitElement {
    ${this._tooltip.body.map( (item, i) => html`
  • - ${item.lines.join("\n")} + >
+ ${item.lines.join("\n")} ` )} @@ -134,10 +169,30 @@ export default class HaChartBase extends LitElement { enabled: false, external: (context) => this._handleTooltip(context), }, + legend: { + ...this.options?.plugins?.legend, + display: false, + }, }, }; } + private _legendClick(ev) { + if (!this.chart) { + return; + } + const index = ev.currentTarget.datasetIndex; + if (this.chart.isDatasetVisible(index)) { + this.chart.setDatasetVisibility(index, false); + this._hiddenDatasets.add(index); + } else { + this.chart.setDatasetVisibility(index, true); + this._hiddenDatasets.delete(index); + } + this.chart.update("none"); + this.requestUpdate("_hiddenDatasets"); + } + private _handleTooltip(context: { chart: Chart; tooltip: TooltipModel; @@ -146,7 +201,15 @@ export default class HaChartBase extends LitElement { this._tooltip = undefined; return; } - this._tooltip = { ...context.tooltip }; + this._tooltip = { + ...context.tooltip, + top: this.chart!.canvas.offsetTop + context.tooltip.caretY + 12 + "px", + left: + this.chart!.canvas.offsetLeft + + clamp(context.tooltip.caretX, 100, this.clientWidth - 100) - + 100 + + "px", + }; } public updateChart = (): void => { @@ -161,42 +224,76 @@ export default class HaChartBase extends LitElement { display: block; } .chartContainer { - position: relative; overflow: hidden; height: 0; transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1); } + .chartLegend { + text-align: center; + } + .chartLegend li { + cursor: pointer; + display: inline-flex; + padding: 0 8px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + box-sizing: border-box; + align-items: center; + color: var(--secondary-text-color); + } + .chartLegend .hidden { + text-decoration: line-through; + } + .chartLegend .bullet, + .chartTooltip .bullet { + border-width: 1px; + border-style: solid; + border-radius: 50%; + display: inline-block; + height: 16px; + margin-right: 4px; + width: 16px; + flex-shrink: 0; + box-sizing: border-box; + } + .chartTooltip .bullet { + align-self: baseline; + } + :host([rtl]) .chartTooltip .bullet { + margin-right: inherit; + margin-left: 4px; + } .chartTooltip { - padding: 4px; + padding: 8px; font-size: 90%; position: absolute; background: rgba(80, 80, 80, 0.9); color: white; border-radius: 4px; pointer-events: none; - transform: translate(-50%, 12px); z-index: 1000; width: 200px; - transition: opacity 0.15s ease-in-out; + box-sizing: border-box; } :host([rtl]) .chartTooltip { direction: rtl; } + .chartLegend ul, .chartTooltip ul { display: inline-block; padding: 0 0px; - margin: 5px 0 0 0; + margin: 8px 0 0 0; width: 100%; } .chartTooltip ul { - margin: 0 3px; + margin: 0 4px; } .chartTooltip li { - display: block; + display: flex; white-space: pre-line; - } - .chartTooltip li::first-line { - line-height: 0; + align-items: center; + line-height: 16px; } .chartTooltip .title { text-align: center; @@ -207,17 +304,6 @@ export default class HaChartBase extends LitElement { font-weight: 300; word-break: break-all; } - .chartTooltip em { - border-radius: 4px; - display: inline-block; - height: 10px; - margin-right: 4px; - width: 10px; - } - :host([rtl]) .chartTooltip em { - margin-right: inherit; - margin-left: 4px; - } `; } } From 4fbc31d0b06d4d7c794381d09b17205748a2a01b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 22 Jun 2021 00:48:29 +0000 Subject: [PATCH 46/73] Translation update --- translations/frontend/fr.json | 14 ++- translations/frontend/hu.json | 162 +++++++++++++++++++--------------- 2 files changed, 102 insertions(+), 74 deletions(-) diff --git a/translations/frontend/fr.json b/translations/frontend/fr.json index 2088f1fe42..8955807461 100644 --- a/translations/frontend/fr.json +++ b/translations/frontend/fr.json @@ -380,6 +380,7 @@ "snapshot": { "addons": "Modules complémentaires", "available_snapshots": "Instantanés disponibles", + "confirm_password": "Confirmez le mot de passe de l'instantané", "could_not_create": "Impossible de créer un instantané", "create": "Créer", "create_blocked_not_running": "La création d’un instantané n’est pas possible en ce moment car le système est en état {state}.", @@ -402,6 +403,7 @@ "password": "Mot de passe", "password_protected": "protégé par mot de passe", "password_protection": "Protection par mot de passe", + "passwords_not_matching": "Les mots de passe ne correspondent pas", "security": "Sécurité", "type": "Type", "upload_snapshot": "Téléverser un instantané" @@ -798,6 +800,7 @@ "was_unplugged": "était débranché", "was_unsafe": "n'était pas sûr" }, + "retrieval_error": "Erreur lors de la récupération d'une entrée du journal", "show_trace": "Afficher la trace" }, "media-browser": { @@ -3857,10 +3860,19 @@ "intro": "Êtes-vous prêt à réveiller votre maison, à récupérer votre vie privée et à rejoindre une communauté mondiale de bricoleurs?", "next": "Suivant", "restore": { + "addons": "Modules complémentaires", + "confirm_password": "Confirmez le mot de passe de l'instantané", "description": "Vous pouvez également restaurer à partir d'un instantané précédent.", + "folders": "Dossiers", + "full_snapshot": "Instantané complet", "hide_log": "Masquer le journal", "in_progress": "Restauration en cours", - "show_log": "Afficher le journal" + "partial_snapshot": "Instantané partiel", + "password": "Mot de passe de l'instantané", + "password_protection": "Protection par mot de passe", + "select_type": "Sélectionnez les éléments à restaurer", + "show_log": "Afficher le journal", + "type": "Type d'instantané" }, "user": { "create_account": "Créer un compte", diff --git a/translations/frontend/hu.json b/translations/frontend/hu.json index 7f79d1ea49..b4e93321d6 100644 --- a/translations/frontend/hu.json +++ b/translations/frontend/hu.json @@ -272,7 +272,7 @@ "addon_new_version": "Új verzió érhető el", "addon_running": "A bővítmény fut", "addon_stopped": "A bővítmény leállt", - "addons": "Bővítmények", + "addons": "Telepített bővítmények", "no_addons": "Még nincs telepítve egyetlen bővítmény sem. A kezdéshez menjen át a bővítmény boltba!" }, "dialog": { @@ -330,6 +330,7 @@ "create": "Létrehozás", "create_blocked_not_running": "Jelenleg nem lehet pillanatképet létrehozni, mivel a rendszer {state} állapotban van.", "create_snapshot": "Pillanatkép létrehozása", + "delete_snapshot_confirm": "törlés", "description": "A pillanatképekkel könnyen hozhatsz létre vagy tölthetsz vissza mentést a teljes Home Assistant példányodról.", "enter_password": "Add meg a jelszót", "folder": { @@ -341,14 +342,14 @@ }, "folders": "Mappák", "full_snapshot": "Teljes pillanatkép", - "name": "Név", + "name": "Pillanatkép neve", "no_snapshots": "Nincs még egyetlen pillanatképed sem létrehozva.", "partial_snapshot": "Részleges pillanatkép", - "password": "Jelszó", + "password": "Pillanatkép jelszava", "password_protected": "jelszóval védett", "password_protection": "Jelszóvédelem", "security": "Biztonság", - "type": "Típus", + "type": "Pillanatkép típusa", "upload_snapshot": "Pillanatkép feltöltése" }, "store": { @@ -444,7 +445,7 @@ }, "automation": { "last_triggered": "Utoljára aktiválva", - "trigger": "Végrehajt" + "trigger": "Műveletek futtatása" }, "camera": { "not_available": "Kép nem áll rendelkezésre" @@ -497,7 +498,7 @@ "brightness": "Fényerő", "color_temperature": "Színhőmérséklet", "effect": "Hatás", - "white_value": "Fehér érték" + "white_value": "Fehér fényerő" }, "lock": { "code": "Kód", @@ -643,6 +644,9 @@ "no_match": "Nem található egyező terület", "show_areas": "Területek megjelenítése" }, + "attributes": { + "expansion_header": "Attribútumok" + }, "blueprint-picker": { "add_user": "Felhasználó hozzáadása", "remove_user": "Felhasználó eltávolítása", @@ -951,8 +955,8 @@ "remove_intro": "Ha az entitás már nincs használatban, akkor nyugodtan eltávolíthatod." }, "script": { - "last_action": "Utolsó Művelet", - "last_triggered": "Utoljára aktivált" + "last_action": "Utolsó művelet", + "last_triggered": "Utolsó aktiválás" }, "settings": "Entitás beállítások", "sun": { @@ -1020,40 +1024,40 @@ "zone": "Zónák" }, "reload": { - "automation": "Automatizálások újratöltése", - "command_line": "Parancssori entitások újratöltése", - "core": "Lokáció és testreszabások újratöltése", - "filesize": "Fájlméret entitások újratöltése", - "filter": "Szűrőentitások újratöltése", - "generic": "Általános IP kamera entitások újratöltése", - "generic_thermostat": "Általános termosztát entitások újratöltése", - "group": "Csoportok, csoport entitások és értesítési szolgáltatások újratöltése", - "history_stats": "Előzmény statisztika entitások újratöltése", - "homekit": "HomeKit újratöltése", - "input_boolean": "Logikai változó bemenetek újratöltése", - "input_datetime": "Időpont bemenetek újratöltése", - "input_number": "Szám bemenetek újratöltése", - "input_select": "Választási bemenetek újratöltése", - "input_text": "Szöveg bemenetek újratöltése", - "min_max": "Min/max entitások újratöltése", - "mqtt": "Manuálisan konfigurált MQTT entitások újratöltése", - "person": "Személyek újratöltése", - "ping": "Ping bináris érzékelő entitások újratöltése", - "reload": "{domain} újratöltése", - "rest": "Rest entitások és értesítési szolgáltatások újratöltése", - "rpi_gpio": "Raspberry Pi GPIO entitások újratöltése", - "scene": "Jelenetek újratöltése", - "script": "Szkriptek újratöltése", - "smtp": "SMTP értesítési szolgáltatások újratöltése", - "statistics": "Statisztikai entitások újratöltése", - "telegram": "Telegram értesítési szolgáltatások újratöltése", - "template": "Sablon entitások újratöltése", - "trend": "Trend entitások újratöltése", - "universal": "Univerzális médialejátszó entitások újratöltése", - "zone": "Zónák újratöltése" + "automation": "Automatizálások", + "command_line": "Parancssori entitások", + "core": "Lokáció és testreszabások", + "filesize": "Fájlméret entitások", + "filter": "Szűrőentitások", + "generic": "Általános IP kamera entitások", + "generic_thermostat": "Általános termosztát entitások", + "group": "Csoportok, csoport entitások és értesítési szolgáltatások", + "history_stats": "Előzmény statisztika entitások", + "homekit": "HomeKit", + "input_boolean": "Logikai változó bemenetek", + "input_datetime": "Időpont bemenetek", + "input_number": "Szám bemenetek", + "input_select": "Választási bemenetek", + "input_text": "Szöveg bemenetek", + "min_max": "Min/max entitások", + "mqtt": "Manuálisan konfigurált MQTT entitások", + "person": "Személyek", + "ping": "Ping bináris érzékelő entitások", + "reload": "{domain}", + "rest": "Rest entitások és értesítési szolgáltatások", + "rpi_gpio": "Raspberry Pi GPIO entitások", + "scene": "Jelenetek", + "script": "Szkriptek", + "smtp": "SMTP értesítési szolgáltatások", + "statistics": "Statisztikai entitások", + "telegram": "Telegram értesítési szolgáltatások", + "template": "Sablon entitások", + "trend": "Trend entitások", + "universal": "Univerzális médialejátszó entitások", + "zone": "Zónák" }, "server_control": { - "perform_action": "{action} Szerver", + "perform_action": "{action} szerver", "restart": "Újraindítás", "stop": "Leállítás" } @@ -1576,11 +1580,12 @@ "info_state_reporting": "Ha engedélyezed az állapotjelentést, akkor a Home Assistant minden állapotváltozást el fog küldeni a feltárt entitásokról az Amazon-nak. Ez lehetővé teszi, hogy mindig láthasd a legfrissebb állapotokat az Alexa alkalmazásban, és az állapotváltozásokkal rutinokat hozhass létre.", "manage_entities": "Entitások kezelése", "state_reporting_error": "Nem lehet {enable_disable} az állapotjelentést.", - "sync_entities": "Entitások szinkronizálása", + "sync_entities": "Entitások szinkronizálása az Amazonnal", "sync_entities_error": "Nem sikerült szinkronizálni az entitásokat:", "title": "Alexa" }, "connected": "Csatlakoztatva", + "connecting": "Csatlakozás...", "connection_status": "Felhő kapcsolat állapota", "fetching_subscription": "Előfizetés lekérése...", "google": { @@ -1658,7 +1663,7 @@ "description_login": "Bejelentkezve mint {email}", "description_not_login": "Nincs bejelentkezve", "dialog_certificate": { - "certificate_expiration_date": "Tanúsítvány lejárati dátuma", + "certificate_expiration_date": "Tanúsítvány lejárati dátuma:", "certificate_information": "Tanúsítvány-információ", "close": "Bezárás", "fingerprint": "Tanúsítvány ujjlenyomata:", @@ -2444,39 +2449,39 @@ "description": "A Home Assistant szerver újraindítása és leállítása", "section": { "reloading": { - "automation": "Automatizálások újratöltése", - "command_line": "Parancssori entitások újratöltése", - "core": "Lokáció és testreszabások újratöltése", - "filesize": "Fájlméret entitások újratöltése", - "filter": "Szűrőentitások újratöltése", - "generic": "Általános IP kamera entitások újratöltése", - "generic_thermostat": "Általános termosztát entitások újratöltése", - "group": "Csoportok, csoport entitások és értesítési szolgáltatások újratöltése", + "automation": "Automatizálások", + "command_line": "Parancssori entitások", + "core": "Lokáció és testreszabások", + "filesize": "Fájlméret entitások", + "filter": "Szűrőentitások", + "generic": "Általános IP kamera entitások", + "generic_thermostat": "Általános termosztát entitások", + "group": "Csoportok, csoport entitások és értesítési szolgáltatások", "heading": "YAML konfiguráció újratöltése", - "history_stats": "Előzmény statisztika entitások újratöltése", - "homekit": "HomeKit újratöltése", - "input_boolean": "Logikai változó bemenetek újratöltése", - "input_datetime": "Időpont bemenetek újratöltése", - "input_number": "Szám bemenetek újratöltése", - "input_select": "Választási bemenetek újratöltése", - "input_text": "Szöveg bemenetek újratöltése", + "history_stats": "Előzmény statisztika entitások", + "homekit": "HomeKit", + "input_boolean": "Logikai változó bemenetek", + "input_datetime": "Időpont bemenetek", + "input_number": "Szám bemenetek", + "input_select": "Választási bemenetek", + "input_text": "Szöveg bemenetek", "introduction": "A Home Assistant bizonyos részei újraindítás nélkül újratölthetőek. Újratöltéskor az aktuálisan betöltött YAML konfiguráció helyére betöltődik az új.", - "min_max": "Min/max entitások újratöltése", - "mqtt": "Manuálisan konfigurált MQTT entitások újratöltése", - "person": "Személyek újratöltése", - "ping": "Ping bináris érzékelő entitások újratöltése", - "reload": "{domain} újratöltése", - "rest": "Rest entitások és értesítési szolgáltatások újratöltése", - "rpi_gpio": "Raspberry Pi GPIO entitások újratöltése", - "scene": "Jelenetek újratöltése", - "script": "Szkriptek újratöltése", - "smtp": "SMTP értesítési szolgáltatások újratöltése", - "statistics": "Statisztikai entitások újratöltése", - "telegram": "Telegram értesítési szolgáltatások újratöltése", - "template": "Sablon entitások újratöltése", - "trend": "Trend entitások újratöltése", - "universal": "Univerzális médialejátszó entitások újratöltése", - "zone": "Zónák újratöltése" + "min_max": "Min/max entitások", + "mqtt": "Manuálisan konfigurált MQTT entitások", + "person": "Személyek", + "ping": "Ping bináris érzékelő entitások", + "reload": "{domain}", + "rest": "Rest entitások és értesítési szolgáltatások", + "rpi_gpio": "Raspberry Pi GPIO entitások", + "scene": "Jelenetek", + "script": "Szkriptek", + "smtp": "SMTP értesítési szolgáltatások", + "statistics": "Statisztikai entitások", + "telegram": "Telegram értesítési szolgáltatások", + "template": "Sablon entitások", + "trend": "Trend entitások", + "universal": "Univerzális médialejátszó entitások", + "zone": "Zónák" }, "server_management": { "confirm_restart": "Biztosan újra szeretnéd indítani a Home Assistant-ot?", @@ -3699,6 +3704,17 @@ "primary_color": "Elsődleges szín", "reset": "Visszaállítás" }, + "time_format": { + "description": "Válaszd ki az időformátumot.", + "dropdown_label": "Időformátum", + "formats": { + "12": "12 óra (AM/PM)", + "24": "24 óra", + "language": "Automatikus (nyelvi beállítás használata)", + "system": "Rendszer területi beállításainak használata" + }, + "header": "Időformátum" + }, "vibrate": { "description": "Rezgés engedélyezése vagy tiltása ezen az eszközön az eszközök vezérlésekor.", "header": "Rezgés" From c327fe11b82dc5b49cde9588c92bc312db365f00 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 23 Jun 2021 00:48:18 +0000 Subject: [PATCH 47/73] Translation update --- translations/frontend/ja.json | 83 +++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/translations/frontend/ja.json b/translations/frontend/ja.json index c096f0fec0..fd0a649eb9 100644 --- a/translations/frontend/ja.json +++ b/translations/frontend/ja.json @@ -312,6 +312,9 @@ "no_addons": "まだアドオンがインストールされていません。アドオンストアにアクセスして始めましょう!" }, "dialog": { + "hardware": { + "search": "ハードウェアの検索" + }, "network": { "connected_to": "{ssid}に接続しました", "dhcp": "DHCP", @@ -360,7 +363,9 @@ }, "my": { "error": "不明なエラーが発生しました", + "error_addon_no_ingress": "要求されたアドオンは入力をサポートしていません", "error_addon_not_found": "アドオンが見つかりません", + "error_addon_not_started": "要求されたアドオンは実行されていません。最初に起動してください", "faq_link": "マイホームアシスタントFAQ", "not_supported": "このリダイレクトは、HomeAssistantインスタンスではサポートされていません。 サポートされているリダイレクトとそれらが導入されたバージョンについては、{link}を確認してください。" }, @@ -373,13 +378,19 @@ "snapshot": { "addons": "アドオン", "available_snapshots": "利用可能なスナップショット", + "confirm_password": "スナップショットパスワードの確認", "could_not_create": "スナップショットを作成できませんでした。", "create": "作成", "create_blocked_not_running": "システムが {state} 状態であるため、スナップショットの作成は現在できません。", "create_snapshot": "スナップショットの作成", "created": "作成", + "delete_selected": "選択したスナップショットの削除", + "delete_snapshot_confirm": "削除", + "delete_snapshot_text": "{number}を削除しますか?{number, plural,\n one {snapshot}\n other {snapshots}\n}?", + "delete_snapshot_title": "スナップショットの削除", "description": "スナップショットでは、Home Assistantインスタンスのすべてのデータを簡単にバックアップして復元することができます。", "enter_password": "パスワードを入力してください。", + "failed_to_delete": "削除できませんでした", "folder": { "addons/local": "ローカルアドオン", "homeassistant": "HomeAssistantの設定", @@ -395,7 +406,9 @@ "password": "パスワード", "password_protected": "パスワードで保護されています", "password_protection": "パスワード保護", + "passwords_not_matching": "パスワードが一致しません", "security": "セキュリティ", + "selected": "{number}が選択されました", "type": "タイプ", "upload_snapshot": "スナップショットのアップロード" }, @@ -555,6 +568,7 @@ }, "light": { "brightness": "明るさ", + "color_brightness": "色の明るさ", "color_temperature": "色温度", "effect": "効果", "white_value": "白さの値" @@ -708,6 +722,9 @@ "no_match": "一致するエリアが見つかりません", "show_areas": "エリアを表示" }, + "attributes": { + "expansion_header": "属性" + }, "blueprint-picker": { "add_user": "ユーザーの追加", "remove_user": "ユーザーの削除", @@ -786,6 +803,7 @@ "was_unplugged": "プラグが抜かれました", "was_unsafe": "安全ではなかった" }, + "retrieval_error": "ログ ブックエントリの取得中にエラーが発生しました", "show_trace": "トレースの表示" }, "media-browser": { @@ -1178,7 +1196,15 @@ } }, "zha_reconfigure_device": { - "heading": "デバイスを再設定" + "attribute": "属性", + "button_hide": "詳細を非表示", + "button_show": "詳細を表示", + "configuration_complete": "デバイスの再構成が完了しました。", + "configuration_failed": "デバイスの再構成に失敗しました。追加情報はログで入手できる場合があります。", + "configuring_alt": "設定", + "heading": "デバイスを再設定", + "in_progress": "デバイスを再構成中です。これには時間がかかる場合があります。", + "start_reconfiguration": "再構成を開始" } }, "duration": { @@ -1241,7 +1267,8 @@ "caption": "エリア", "data_table": { "area": "エリア", - "devices": "デバイス" + "devices": "デバイス", + "entities": "エンティティ" }, "delete": { "confirmation_text": "このエリアのすべてのデバイスは割り当て解除されます。", @@ -1253,6 +1280,7 @@ "create": "作成", "default_name": "新しいエリア", "delete": "削除", + "linked_entities_caption": "エンティティ", "name": "名前", "name_required": "名前は必須です", "unknown_error": "不明なエラー", @@ -1679,6 +1707,7 @@ "title": "Alexa" }, "connected": "接続", + "connecting": "接続しています...", "connection_status": "クラウド接続の状態", "fetching_subscription": "サブスクリプションを取得しています。", "google": { @@ -1713,6 +1742,11 @@ "instance_is_available": "インスタンスは次の場所にあります", "instance_will_be_available": "インスタンスは次の時点で利用可能になります。", "link_learn_how_it_works": "仕組みを学ぶ", + "not_connected": "接続されていません", + "remote_enabled": { + "caption": "自動的に接続", + "description": "このオプションを有効にすると、ホームアシスタントのインスタンスが常にリモートでアクセスできるようになります。" + }, "title": "リモートコントロール" }, "sign_out": "サインアウト", @@ -2016,7 +2050,8 @@ "scripts": "スクリプト", "unknown_error": "不明なエラー", "unnamed_device": "名前のないデバイス", - "update": "更新" + "update": "更新", + "update_device_error": "デバイスの更新に失敗しました" }, "entities": { "caption": "エンティティ", @@ -2123,6 +2158,7 @@ "license": "Apache 2.0ライセンスの下で公開", "path_configuration": "ディスク上に configuration.yaml へのパス: {path}", "server": "サーバー", + "setup_time": "設定時間", "source": "ソース:", "system_health_error": "「システムの正常性」コンポーネントが有効されていません、configuration.yaml に 'system_health:' を追加してください。", "system_health": { @@ -2173,6 +2209,11 @@ "rename": "名前を変更", "restart_confirm": "ホーム アシスタントを再起動して、この統合の削除を完了します。", "services": "{count} {count, plural,\n one {サービス}\n other {サービス}\n}", + "state": { + "loaded": "読み込み", + "not_loaded": "読み込まれていません", + "setup_retry": "設定をやり直す" + }, "system_options": "システムオプション", "unnamed_entry": "名前のないエントリ" }, @@ -2190,6 +2231,7 @@ }, "finish": "完了", "loading_first_time": "インテグレーションのインストールを完了するまでお待ちください", + "next": "次", "not_all_required_fields": "必須フィールドの一覧に入力するわけではありません。", "not_loaded": "インテグレーションファイルを読み込めませんでした。ホームアシスタントを再起動してください。", "pick_flow_step": { @@ -2528,6 +2570,7 @@ "add_scene": "シーンを追加", "delete_confirm": "このシーンを削除してもよろしいですか?", "delete_scene": "シーンを削除", + "duplicate_scene": "シーンの複製", "edit_scene": "シーンを編集", "header": "シーンエディター", "headers": { @@ -2853,6 +2896,8 @@ "follow_device_instructions": "デバイスに付属の指示に従って、デバイスでペアリングを開始します。", "inclusion_failed": "ノードを追加できませんでした。詳細については、ログを確認してください。", "inclusion_finished": "ノードが追加されました。ノードのバックグラウンドでの設定が完了すると、すべてのエンティティが表示されるまで数分かかる場合があります。", + "interview_failed": "デバイスのインタビューに失敗しました。追加情報がログに残っている場合があります。", + "interview_started": "デバイスはインタビュー中です。これには時間がかかる場合があります。", "introduction": "このウィザードでは、Z-Wave ネットワークにノードを追加する手順を説明します。", "secure_inclusion_warning": "セキュアなデバイスには、追加の帯域幅が必要です。安全なデバイスが多すぎると、Z-Waveネットワークが遅くなる可能性があります。ロックやガレージドアオープナーなど、必要なデバイスにのみ安全な組み込みを使用することをお勧めします。", "start_inclusion": "インクルージョンを開始", @@ -2890,7 +2935,11 @@ "node_status": "ノードの状態", "zwave_info": "Z-Wave情報" }, + "logs": { + "log_level_changed": "ログレベルが変更されました。{level}に変更されました。" + }, "navigation": { + "logs": "ログ", "network": "ネットワーク" }, "network_status": { @@ -2915,6 +2964,12 @@ "unknown": "不明" }, "reinterview_node": { + "battery_device_warning": "再会する前に、バッテリー駆動のデバイスをスリープ解除する必要があります。デバイスをウェイクアップする方法については、デバイスのマニュアルを参照してください。", + "in_progress": "デバイスがインタビュー中です。これには時間がかかる場合があります。", + "interview_complete": "デバイスのインタビューが完了しました。", + "interview_failed": "デバイスのインタビューに失敗しました。追加情報がログに残っている場合があります。", + "run_in_background": "このダイアログを閉じても、インタビューはバックグラウンドで継続されます。", + "start_reinterview": "再インタビューを開始", "title": "Z-Waveデバイスへの再インタビュー" }, "remove_node": { @@ -3777,10 +3832,19 @@ "intro": "あなたはあなたの家を目覚めさせ、あなたのプライバシーを取り戻し、ティンカーの世界的なコミュニティに参加する準備ができていますか?", "next": "次", "restore": { + "addons": "アドオン", + "confirm_password": "スナップショットパスワードの確認", "description": "以前のスナップショットから復元することもできます。", + "folders": "フォルダ", + "full_snapshot": "フルスナップショット", "hide_log": "ログ全体を非表示", "in_progress": "復元中", - "show_log": "ログ全体を表示" + "partial_snapshot": "部分的スナップショット", + "password": "スナップショットパスワード", + "password_protection": "パスワード保護", + "select_type": "何を復元するかを選択します", + "show_log": "ログ全体を表示", + "type": "スナップショットタイプ" }, "user": { "create_account": "アカウントの作成", @@ -3924,6 +3988,17 @@ "primary_color": "プライマリーの色", "reset": "リセット" }, + "time_format": { + "description": "時刻のフォーマットを選択します。", + "dropdown_label": "時間形式", + "formats": { + "12": "12時間(AM / PM)", + "24": "24時間", + "language": "自動 (言語設定を使用)", + "system": "システムロケールを使用する" + }, + "header": "時間形式" + }, "vibrate": { "description": "デバイスを制御するときに、このデバイスのバイブレーションを有効または無効にします。", "header": "バイブレーション機能" From d93db169631f6862164a80c40e326d3bc7454211 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Thu, 24 Jun 2021 13:21:30 +0200 Subject: [PATCH 48/73] Add button for zwave_js options flow (#9001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joakim Sørensen --- .../zwave_js/zwave_js-config-dashboard.ts | 18 ++++++++++++++++++ src/translations/en.json | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts index 44c66b7ba4..07e0b72d9f 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts @@ -29,6 +29,8 @@ import "../../../ha-config-section"; import { showZWaveJSAddNodeDialog } from "./show-dialog-zwave_js-add-node"; import { showZWaveJSRemoveNodeDialog } from "./show-dialog-zwave_js-remove-node"; import { configTabs } from "./zwave_js-config-router"; +import { getConfigEntries } from "../../../../../data/config_entries"; +import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-options-flow"; @customElement("zwave_js-config-dashboard") class ZWaveJSConfigDashboard extends LitElement { @@ -162,6 +164,11 @@ class ZWaveJSConfigDashboard extends LitElement { "ui.panel.config.zwave_js.common.remove_node" )} + + ${this.hass.localize( + "ui.panel.config.zwave_js.common.reconfigure_server" + )} +
@@ -262,6 +269,17 @@ class ZWaveJSConfigDashboard extends LitElement { ); } + private async _openOptionFlow() { + if (!this.configEntryId) { + return; + } + const configEntries = await getConfigEntries(this.hass); + const configEntry = configEntries.find( + (entry) => entry.entry_id === this.configEntryId + ); + showOptionsFlowDialog(this, configEntry!); + } + private async _dumpDebugClicked() { await this._fetchNodeStatus(); diff --git a/src/translations/en.json b/src/translations/en.json index 030742b168..4896d0c5bd 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2587,7 +2587,8 @@ "home_id": "Home ID", "close": "Close", "add_node": "Add Node", - "remove_node": "Remove Node" + "remove_node": "Remove Node", + "reconfigure_server": "Re-configure Server" }, "dashboard": { "header": "Manage your Z-Wave Network", From a4aba93d5703f55ade19d5046b9897d2672ee26e Mon Sep 17 00:00:00 2001 From: rianadon Date: Thu, 24 Jun 2021 14:14:36 -0700 Subject: [PATCH 49/73] Add input elements to login page for password managers (#9369) --- src/auth/ha-auth-flow.ts | 27 +++++- src/auth/ha-password-manager-polyfill.ts | 110 +++++++++++++++++++++++ 2 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 src/auth/ha-password-manager-polyfill.ts diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts index 85dcf053e9..c04f91acc9 100644 --- a/src/auth/ha-auth-flow.ts +++ b/src/auth/ha-auth-flow.ts @@ -7,6 +7,7 @@ import { PropertyValues, TemplateResult, } from "lit"; +import "./ha-password-manager-polyfill"; import { property, state } from "lit/decorators"; import "../components/ha-form/ha-form"; import "../components/ha-markdown"; @@ -20,7 +21,7 @@ import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; type State = "loading" | "error" | "step"; class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { - @property() public authProvider?: AuthProvider; + @property({ attribute: false }) public authProvider?: AuthProvider; @property() public clientId?: string; @@ -37,7 +38,15 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { @state() private _errorMessage?: string; protected render() { - return html`
${this._renderForm()}
`; + return html` +
${this._renderForm()}
+ + `; } protected firstUpdated(changedProps: PropertyValues) { @@ -231,11 +240,17 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { await this.updateComplete; // 100ms to give all the form elements time to initialize. setTimeout(() => { - const form = this.shadowRoot!.querySelector("ha-form"); + const form = this.renderRoot.querySelector("ha-form"); if (form) { (form as any).focus(); } }, 100); + + setTimeout(() => { + this.renderRoot.querySelector( + "ha-password-manager-polyfill" + )!.boundingRect = this.getBoundingClientRect(); + }, 500); } private _stepDataChanged(ev: CustomEvent) { @@ -329,3 +344,9 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { } } customElements.define("ha-auth-flow", HaAuthFlow); + +declare global { + interface HTMLElementTagNameMap { + "ha-auth-flow": HaAuthFlow; + } +} diff --git a/src/auth/ha-password-manager-polyfill.ts b/src/auth/ha-password-manager-polyfill.ts new file mode 100644 index 0000000000..1a2e765e05 --- /dev/null +++ b/src/auth/ha-password-manager-polyfill.ts @@ -0,0 +1,110 @@ +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { fireEvent } from "../common/dom/fire_event"; +import { HaFormSchema } from "../components/ha-form/ha-form"; +import { DataEntryFlowStep } from "../data/data_entry_flow"; + +declare global { + interface HTMLElementTagNameMap { + "ha-password-manager-polyfill": HaPasswordManagerPolyfill; + } + interface HASSDomEvents { + "form-submitted": undefined; + } +} + +const ENABLED_HANDLERS = [ + "homeassistant", + "legacy_api_password", + "command_line", +]; + +@customElement("ha-password-manager-polyfill") +export class HaPasswordManagerPolyfill extends LitElement { + @property({ attribute: false }) public step?: DataEntryFlowStep; + + @property({ attribute: false }) public stepData: any; + + @property({ attribute: false }) public boundingRect?: DOMRect; + + protected createRenderRoot() { + // Add under document body so the element isn't placed inside any shadow roots + return document.body; + } + + private get styles() { + return ` + .password-manager-polyfill { + position: absolute; + top: ${this.boundingRect?.y || 148}px; + left: calc(50% - ${(this.boundingRect?.width || 360) / 2}px); + width: ${this.boundingRect?.width || 360}px; + opacity: 0; + z-index: -1; + } + .password-manager-polyfill input { + width: 100%; + height: 62px; + padding: 0; + border: 0; + } + .password-manager-polyfill input[type="submit"] { + width: 0; + height: 0; + } + `; + } + + protected render(): TemplateResult { + if ( + this.step && + this.step.type === "form" && + this.step.step_id === "init" && + ENABLED_HANDLERS.includes(this.step.handler[0]) + ) { + return html` + + `; + } + return html``; + } + + private render_input(schema: HaFormSchema): TemplateResult | string { + const inputType = schema.name.includes("password") ? "password" : "text"; + if (schema.type !== "string") { + return ""; + } + return html` + + `; + } + + private _handleSubmit(ev: Event) { + ev.preventDefault(); + fireEvent(this, "form-submitted"); + } + + private _valueChanged(ev: Event) { + const target = ev.target! as HTMLInputElement; + this.stepData = { ...this.stepData, [target.id]: target.value }; + fireEvent(this, "value-changed", { + value: this.stepData, + }); + } +} From 27730e65e7e1984cced8526ef6f28ee27b40ee90 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 25 Jun 2021 00:47:31 +0000 Subject: [PATCH 50/73] Translation update --- translations/frontend/en.json | 1 + translations/frontend/es.json | 1 + translations/frontend/et.json | 1 + translations/frontend/ja.json | 4 +- translations/frontend/lt.json | 1273 +++++++++++++++++++++++++++- translations/frontend/ru.json | 1 + translations/frontend/zh-Hans.json | 1 + 7 files changed, 1234 insertions(+), 48 deletions(-) diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 17b1da1b4d..c105428f82 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -2965,6 +2965,7 @@ "home_id": "Home ID", "network": "Network", "node_id": "Node ID", + "reconfigure_server": "Re-configure Server", "remove_node": "Remove Node" }, "dashboard": { diff --git a/translations/frontend/es.json b/translations/frontend/es.json index f898948e66..4ad16212b8 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -2965,6 +2965,7 @@ "home_id": "ID de casa", "network": "Red", "node_id": "ID del Nodo", + "reconfigure_server": "Reconfigurar el servidor", "remove_node": "Eliminar Nodo" }, "dashboard": { diff --git a/translations/frontend/et.json b/translations/frontend/et.json index 912eddb469..2f47fa463a 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -2965,6 +2965,7 @@ "home_id": "Kodu ID", "network": "Võrk", "node_id": "Sõlme ID", + "reconfigure_server": "Taasseadista server", "remove_node": "Eemalda sõlm" }, "dashboard": { diff --git a/translations/frontend/ja.json b/translations/frontend/ja.json index fd0a649eb9..839f80267b 100644 --- a/translations/frontend/ja.json +++ b/translations/frontend/ja.json @@ -1250,12 +1250,12 @@ "notification_toast": { "connection_lost": "接続が切れました。再接続中...", "dismiss": "閉じる", - "integration_starting": "{integration}を開始すると、完了するまですべてが利用できるわけではありません。", + "integration_starting": "{integration}の開始、完了するまですべてが利用できるわけではありません。", "service_call_failed": "サービス{service}の呼び出しに失敗しました。", "started": "ホームアシスタントが開始されました!", "starting": "Home Assistantが起動中です。全て利用可能なるまでもうしばらくお待ち下さい。", "triggered": "トリガーしました {name}", - "wrapping_up_startup": "スタートアップの締めくくりとして、終了するまですべてが利用できるわけではありません。" + "wrapping_up_startup": "起動開始、起動完了するまですべてが利用できるわけではありません。" }, "panel": { "config": { diff --git a/translations/frontend/lt.json b/translations/frontend/lt.json index 5016bb31cf..1491572285 100644 --- a/translations/frontend/lt.json +++ b/translations/frontend/lt.json @@ -1,7 +1,8 @@ { "config_entry": { "disabled_by": { - "device": "Įrenginys" + "device": "Įrenginys", + "user": "Vartotojas" } }, "groups": { @@ -11,6 +12,7 @@ "system-users": "Vartotojai" }, "panel": { + "calendar": "Kalendorius", "config": "Konfigūracija", "developer_tools": "Kūrėjo įrankiai", "history": "Istorija", @@ -28,8 +30,29 @@ "off": "Išjungta", "on": "Įjungta" }, + "hvac_action": { + "cooling": "Aušinimas", + "drying": "Džiovinimas", + "fan": "Ventiliatorius", + "heating": "Šildymas", + "idle": "Laukimo režimas", + "off": "Išjungta" + }, "preset_mode": { - "away": "Išvykęs" + "activity": "Veikla", + "away": "Išvykęs", + "boost": "Padidinti", + "comfort": "Komfortas", + "eco": "Eko", + "home": "Namai", + "sleep": "Miegoti" + } + }, + "humidifier": { + "mode": { + "auto": "Automatinis", + "baby": "Kūdikio", + "sleep": "Miego" } } }, @@ -61,6 +84,8 @@ }, "state": { "default": { + "off": "Išjungta", + "on": "Įjungta", "unavailable": "(nepasiekiamas)", "unknown": "Nežinoma" } @@ -68,28 +93,97 @@ "supervisor": { "addon": { "dashboard": { + "action_error": { + "start_invalid_config": "Eiti į konfigūraciją" + }, + "capability": { + "apparmor": { + "title": "AppArmor" + }, + "label": { + "apparmor": "apparmor", + "auth": "auth", + "docker": "docker", + "hardware": "hardware", + "hass": "hass", + "hassio": "hassio", + "host": "host", + "host_pid": "host pid", + "ingress": "ingress", + "rating": "rating", + "stage": "stage" + }, + "role": { + "admin": "admin", + "backup": "backup", + "default": "default", + "homeassistant": "homeassistant", + "manager": "manager" + } + }, "visit_addon_page": "Apsilankykite puslapyje {name}, jei reikia daugiau detalių" + }, + "panel": { + "configuration": "Konfigūracija", + "documentation": "Dokumentacija" } }, "common": { "cancel": "Atšaukti", "close": "Užverti", - "save": "Išsaugoti" + "description": "Aprašymas", + "error": { + "unknown": "Nežinoma klaida", + "update_failed": "Atnaujinimas nepavyko" + }, + "failed_to_restart_name": "Nepavyko paleisti iš naujo {name}", + "failed_to_update_name": "Nepavyko atnaujinti {name}", + "learn_more": "Sužinokite daugiau", + "new_version_available": "Galima nauja versija", + "reload": "Perkrauti", + "restart": "Paleisti iš naujo", + "restart_name": "Iš naujo paleisti {name}", + "running_version": "Šiuo metu naudojate {version}", + "save": "Išsaugoti", + "show_more": "Rodyti daugiau informacijos apie tai", + "version": "Versija" }, "confirm": { + "restart": { + "text": "Ar jūs tikrai norite iš naujo paleisti {name}?", + "title": "Iš naujo paleisti {name}" + }, "update": { "title": "Atnaujinti {name}" } }, + "dashboard": { + "addon_new_version": "Galima nauja versija" + }, "dialog": { + "hardware": { + "attributes": "Atributai", + "device_path": "Įrenginio kelias", + "id": "ID", + "search": "Ieškoti įrenginių", + "title": "Įrenginiai" + }, "network": { "connected_to": "Prisijungta prie {ssid}", + "dhcp": "DHCP", "disabled": "Išjungta", "dns_servers": "DNS serveriai", "failed_to_change": "Nepavyko pakeisti tinklo nustatymų", + "gateway": "Šliuzo adresas", + "ip_netmask": "IP adresas/Netmask", "open": "Atidaryti", "scan_ap": "Ieškoti prieigos taškų", - "unsaved": "Turite neišsaugotų pakeitimų, ar tikrai norite išeiti?" + "static": "Statinis", + "title": "Tinklo nustatymai", + "unsaved": "Turite neišsaugotų pakeitimų, ar tikrai norite išeiti?", + "warning": "Jei keičiate „Wi-Fi“, IP ar šliuzo adresus, galite prarasti ryšį!", + "wep": "WEP", + "wpa": "wpa-psk" }, "registries": { "add_new_registry": "Pridėti naują registrą", @@ -116,46 +210,151 @@ "my": { "error_addon_not_found": "Priedas nerastas" }, + "panel": { + "dashboard": "Prietaisų skydelis", + "system": "Sistema" + }, "snapshot": { "addons": "Priedai", "could_not_create": "Nepavyko sukurti momentinės kopijos", "create": "Sukurti", + "created": "Sukurta", + "delete_snapshot_confirm": "ištrinti", "enter_password": "Įveskite slaptažodį.", + "failed_to_delete": "Ištrinti nepavyko", "folder": { - "homeassistant": "„Home Assistant“ konfigūracija" + "homeassistant": "„Home Assistant“ konfigūracija", + "share": "Dalintis" }, "folders": "Aplankai", "name": "Pavadinimas", "no_snapshots": "Dar neturite momentinių kopijų.", "password": "Slaptažodis", + "passwords_not_matching": "Slaptažodžiai nesutampa", "security": "Saugumas", + "select_type": "Pasirinkite, ką atkurti", + "selected": "{number} pasirinkta", "type": "Tipas" }, + "store": { + "no_results_found": "Rezultatų {repository} nerasta.", + "registries": "Registrai", + "repositories": "Saugyklos" + }, "system": { + "core": { + "cpu_usage": "Pagrindinio procesoriaus naudojimas", + "ram_usage": "Pagrindinės operatyviosios atminties naudojimas" + }, "host": { + "change": "Keisti", + "docker_version": "Docker versija", "hardware": "Įranga", - "import_from_usb": "Importuoti iš USB" + "import_from_usb": "Importuoti iš USB", + "ip_address": "IP adresas", + "operating_system": "Operacinė sistema" + }, + "log": { + "get_logs": "Nepavyko gauti {provider} žurnalų, {error}" + }, + "supervisor": { + "channel": "Kanalas", + "share_diagonstics_title": "Padėkite tobulinti Home Assistant", + "unhealthy_reason": { + "untrusted": "Aptiktas nepatikimas turinys" + }, + "warning": "ĮSPĖJIMAS" } } }, "ui": { + "auth_store": { + "ask": "Ar norite likti prisijungę?", + "confirm": "Taip", + "decline": "Ne" + }, "card": { "alarm_control_panel": { "arm_custom_bypass": "Individualizuotas apėjimas", - "arm_night": "Naktinė apsauga" + "arm_night": "Naktinė apsauga", + "clear_code": "Išvalyti", + "code": "Kodas" }, "camera": { "not_available": "Vaizdas negalimas" }, + "climate": { + "currently": "Šiuo metu", + "on_off": "Įjungta / išjungta" + }, + "counter": { + "actions": { + "decrement": "pamažinti", + "increment": "padidinti", + "reset": "atstatyti" + } + }, + "cover": { + "position": "Padėtis", + "tilt_position": "Pakreipimo padėtis" + }, + "fan": { + "direction": "Kryptis", + "speed": "Greitis" + }, + "humidifier": { + "mode": "Režimas" + }, + "light": { + "brightness": "Ryškumas", + "color_temperature": "Spalvos temperatūra", + "white_value": "Baltas ryškumas" + }, + "lock": { + "lock": "Užrakinti", + "unlock": "Atrakinti" + }, + "media_player": { + "media_play": "Paleisti", + "media_play_pause": "Paleisti/pristabdyti", + "sound_mode": "Garso režimas", + "source": "Šaltinis", + "text_to_speak": "Tekstas, kurį reikia kalbėti", + "turn_off": "Išjungti", + "turn_on": "Įjungti" + }, "persistent_notification": { "dismiss": "Atmesti" }, + "scene": { + "activate": "Suaktyvinti" + }, + "service": { + "run": "Paleisti" + }, + "timer": { + "actions": { + "cancel": "atšaukti", + "finish": "užbaigti", + "pause": "sustabdyti", + "start": "pradėti" + } + }, + "vacuum": { + "actions": { + "resume_cleaning": "Tęsti valymą", + "start_cleaning": "Pradėti valymą", + "turn_off": "Išjungti", + "turn_on": "Įjungti" + } + }, "weather": { "attributes": { "air_pressure": "Atmosferos slėgis", "humidity": "Santykinė oro drėgmė", "precipitation": "Krituliai", "temperature": "Temperatūra", + "visibility": "Matomumas", "wind_speed": "Vėjo greitis" }, "cardinal_direction": { @@ -168,26 +367,71 @@ "sw": "PV", "w": "V" }, - "forecast": "Prognozė" + "forecast": "Prognozė", + "high": "Aukštas", + "low": "Žemas" } }, "common": { + "back": "Atgal", "cancel": "Atšaukti", + "close": "Uždaryti", + "continue": "Tęsti", + "copied": "Nukopijuota", + "delete": "Ištrinti", + "disable": "Išjungti", + "enable": "Įgalinti", + "error_required": "Privaloma", + "leave": "Palikti", "loading": "Pakrovimas", - "save": "Išsaugoti" + "menu": "Meniu", + "next": "Kitas", + "no": "Ne", + "not_now": "Ne dabar", + "previous": "Ankstesnis", + "refresh": "Atnaujinti", + "remove": "Pašalinti", + "rename": "Pervardyti", + "save": "Išsaugoti", + "skip": "Praleisti", + "stay": "Likti", + "successfully_deleted": "Sėkmingai ištrinta", + "successfully_saved": "Sėkmingai išsaugota", + "undo": "Atšaukti", + "yes": "Taip" }, "components": { "area-picker": { + "add_dialog": { + "failed_create_area": "Nepavyko sukurti srities.", + "text": "Įveskite naujos srities pavadinimą." + }, + "add_new": "Pridėti naują sritį...", + "area": "Sritis", "no_areas": "Neturite jokių sričių", "no_match": "Nerasta atitinkančių sričių" }, + "attributes": { + "expansion_header": "Atributai" + }, "blueprint-picker": { "add_user": "Pridėti vartotoją", "remove_user": "Pašalinti vartotoją", "select_blueprint": "Pasirinkite techninį planą" }, + "data-table": { + "clear": "Išvalyti", + "hidden": "{number} paslėpta", + "no-data": "Nėra duomenų" + }, + "date-range-picker": { + "end_date": "Pabaigos data", + "select": "Pasirinkite", + "start_date": "Pradžios data" + }, "device-picker": { "device": "Įrenginys", + "no_area": "Nėra srities", "no_devices": "Neturite jokių įrenginių", "no_match": "Nerasta atitinkančių įrenginių", "show_devices": "Rodyti įrenginius" @@ -197,6 +441,10 @@ "no_match": "Nerasta atitinkančių objektų" } }, + "history_charts": { + "loading_history": "Įkeliama būsenos retrospektyva...", + "no_history_found": "Būsenos istorija nerasta." + }, "logbook": { "by_service": "pagal paslaugą", "messages": { @@ -204,6 +452,8 @@ "changed_to_state": "pakeista į {state}", "cleared_device_class": "išvalyta ({device_class} neaptikta)", "detected_device_class": "aptikta {device_class}", + "is_closing": "uždaroma", + "is_opening": "atidaroma", "rose": "pakilo", "set": "nustatyti", "turned_off": "Išjungta", @@ -225,6 +475,42 @@ "was_unsafe": "buvo nesaugus" } }, + "media-browser": { + "class": { + "album": "Albumas", + "app": "Programėlė", + "artist": "Atlikėjas", + "channel": "Kanalas", + "composer": "Kompozitorius", + "contributing_artist": "Prisidedantis atlikėjas", + "directory": "Biblioteka", + "episode": "Serija", + "genre": "Žanras", + "movie": "Filmas", + "music": "Muzika", + "playlist": "Grojaraštis", + "podcast": "Podkastas", + "season": "Sezonas", + "tv_show": "Televizijos laida", + "url": "URL", + "video": "Vaizdo įrašas" + }, + "documentation": "dokumentacija" + }, + "picture-upload": { + "label": "Paveikslėlis", + "unsupported_format": "Nepalaikomas formatas, prašome pasirinkti JPEG, PNG arba GIF atvaizdą." + }, + "related-filter-menu": { + "filter_by_area": "Filtruoti pagal sritį", + "filter_by_device": "Filtruoti pagal įrenginį", + "filtered_by_area": "sritis: {area_name}", + "filtered_by_device": "įrenginys: {device_name}" + }, + "related-items": { + "area": "Sritis", + "device": "Įrenginys" + }, "relative_time": { "duration": { "day": "{count} {count, plural,\n one {diena}\n other {dienos}\n}", @@ -232,7 +518,11 @@ "minute": "{count} {count, plural,\n one {minutė}\n other {minutės}\n}", "second": "{count} {count, plural,\n one {sekundė}\n other {sekundės}\n}", "week": "{count} {count, plural,\n one {savaitė}\n other {savaitės}\n}" - } + }, + "never": "Niekada" + }, + "service-control": { + "integration_doc": "Integracijos dokumentacija" }, "target-picker": { "add_area_id": "Pasirinkite sritį", @@ -249,12 +539,22 @@ } }, "dialogs": { + "config_entry_system_options": { + "restart_home_assistant": "Kad pakeitimai įsigaliotų, turite iš naujo paleisti Home Assistant.", + "update": "Atnaujinti" + }, "entity_registry": { + "dismiss": "Atmesti", "editor": { "device_disabled": "Šio objekto įrenginys išjungtas.", + "name": "Pavadinimas", "open_device_settings": "Atidaryti įrenginio nustatymus" }, - "faq": "dokumentacija" + "faq": "dokumentacija", + "settings": "Nustatymai" + }, + "generic": { + "close": "uždaryti" }, "helper_settings": { "counter": { @@ -264,12 +564,28 @@ "restore": "Atkurkite paskutinę žinomą reikšmę paleidus „Home Assistant“", "step": "Žingsnio dydis" }, + "input_number": { + "step": "Žingsnio dydis", + "unit_of_measurement": "Matavimo vienetai" + }, + "input_select": { + "add": "Pridėti", + "add_option": "Pridėti parinktį", + "options": "Parinktys" + }, "timer": { "duration": "Trukmė" } }, + "image_cropper": { + "crop": "Apkarpyti" + }, "more_info_control": { + "details": "Išsami informacija", "dismiss": "Atsisakyti dialogo", + "history": "Istorija", + "last_changed": "Paskutinį kartą pakeista", + "last_updated": "Paskutinį kartą atnaujinta", "remote": { "activity": "Dabartinė veikla" }, @@ -284,6 +600,24 @@ }, "updater": { "title": "Atnaujinimo instrukcijos" + }, + "vacuum": { + "fan_speed": "Ventiliatoriaus greitis", + "locate": "Surasti", + "pause": "Pristabdyti", + "return_home": "Grįžti namo", + "start": "Pradėti", + "start_pause": "Pradėti/Pristabdyti", + "status": "Būsena", + "stop": "Sustabdyti" + } + }, + "options_flow": { + "form": { + "header": "Parinktys" + }, + "success": { + "description": "Parinktys sėkmingai išsaugotos." } }, "quick-bar": { @@ -308,9 +642,48 @@ "server_control": "Serverio valdikliai", "users": "Vartotojai", "zone": "Zonos" + }, + "server_control": { + "perform_action": "{action} serveris", + "restart": "Paleisti iš naujo", + "stop": "Sustabdyti" + }, + "types": { + "reload": "Perkrauti", + "server_control": "Serveris" } }, "filter_placeholder": "Objekto filtras" + }, + "voice_command": { + "did_not_hear": "Home Assistant nieko neišgirdo", + "error": "Oi, įvyko klaida", + "how_can_i_help": "Kuo galiu padėti?", + "label": "Įveskite klausimą ir paspauskite „Enter“" + }, + "zha_device_info": { + "buttons": { + "device_children": "Peržiūrėti vaikus" + }, + "confirmations": { + "remove": "Ar jūs tikrai norite pašalinti įrenginį?" + }, + "last_seen": "Paskutinį kartą matyta", + "manuf": "sukūrė {manufacturer}", + "no_area": "Nėra srities", + "unknown": "Nežinoma" + }, + "zha_reconfigure_device": { + "attribute": "Atributas", + "button_hide": "Slėpti išsamią informaciją", + "button_show": "Rodyti išsamią informaciją", + "configuration_complete": "Įrenginio perkonfigūravimas baigtas.", + "configuration_failed": "Įrenginio perkonfigūravimas nepavyko. Žurnaluose gali būti papildomos informacijos.", + "configuring_alt": "Konfigūruojama", + "in_progress": "Įrenginys perkonfigūruojamas. Tai gali užtrukti.", + "reporting_header": "Ataskaitos", + "run_in_background": "Galite uždaryti šį dialogo langą ir perkonfigūravimas bus tęsiamas fone.", + "start_reconfiguration": "Pradėti perkonfigūravimą" } }, "duration": { @@ -320,20 +693,28 @@ "second": "{count} {count, plural,\n one {sekundė}\n other {sekundės}\n}", "week": "{count} {count, plural,\n one {savaitė}\n other {savaitės}\n}" }, + "errors": { + "supervisor": { + "ask": "Prašyti pagalbos" + } + }, "login-form": { "log_in": "Prisijungti", "password": "Slaptažodis", "remember": "Prisiminti" }, "notification_drawer": { + "click_to_configure": "Spustelėkite mygtuką, kad sukonfigūruotumėte {entity}", "close": "Uždaryti", "dismiss_all": "Atmesti viską", "empty": "Pranešimų nėra", "title": "Pranešimai" }, "notification_toast": { + "connection_lost": "Nutrūko ryšys. Jungiamasi iš naujo...", "dismiss": "Atmesti", - "started": "Home Assistant startavo" + "started": "Home Assistant startavo", + "starting": "Home Assistant kraunasi. Visos funkcijos bus prieinamos kai bus baigtas užkrovimas." }, "panel": { "config": { @@ -344,20 +725,29 @@ "areas": { "caption": "Sričių registras", "data_table": { + "area": "Sritis", "devices": "Įrenginiai" }, + "delete": { + "confirmation_title": "Ar jūs tikrai norite ištrinti šią sritį?" + }, "description": "Visų jūsų namų sričių apžvalga.", "editor": { "create": "SUKURTI", + "default_name": "Nauja sritis", "delete": "IŠTRINTI", + "unknown_error": "Nežinoma klaida", "update": "ATNAUJINTI" }, "picker": { + "create_area": "Sukurti sritį", "header": "Sričių registras", "integrations_page": "Integracijų puslapis" } }, "automation": { + "caption": "Automatika", + "description": "Sukurkite pasirinktas automatikos taisykles savo namams", "dialog_new": { "blueprint": { "use_blueprint": "Naudoti techninį planą" @@ -381,19 +771,38 @@ "header": "Veiksmai", "learn_more": "Sužinokite daugiau apie veiksmus", "name": "Veiksmas", + "type_select": "Veiksmo tipas", "type": { + "condition": { + "label": "Sąlyga" + }, "delay": { - "delay": "Uždelsta" + "delay": "Uždelsta", + "label": "Uždelsimas" + }, + "device_id": { + "action": "Veiksmas", + "extra_fields": { + "code": "Kodas", + "humidity": "Drėgmė", + "mode": "Režimas", + "value": "Vertė" + }, + "label": "Įrenginys" }, "event": { "event": "Įvykiai", "label": "Sukurti įvykį" }, + "scene": { + "label": "Suaktyvinti sceną" + }, "wait_template": { "label": "Laukti" } } }, + "alias": "Pavadinimas", "blueprint": { "blueprint_to_use": "Naudotini techniniai planai", "header": "Techninis planas", @@ -401,14 +810,31 @@ "no_inputs": "Šis techninis planas neturi jokių įvesčių." }, "conditions": { + "add": "Pridėti sąlygą", "delete": "Ištrinti", "duplicate": "Dubliuoti", + "header": "Sąlygos", + "introduction": "Sąlygos yra neprivalomos ir neleis automatikos scenarijams veikti, nebent bus įvykdytos visos sąlygos.", "learn_more": "Sužinokite daugiau apie sąlygas", "name": "Sąlyga", "type": { + "and": { + "label": "Ir" + }, + "device": { + "condition": "Sąlyga", + "extra_fields": { + "for": "Trukmė" + }, + "label": "Įrenginys" + }, "numeric_state": { + "above": "Daugiau", "below": "žemiau" }, + "or": { + "label": "Arba" + }, "sun": { "after": "Po:", "before": "Prieš:", @@ -424,7 +850,13 @@ "before": "Prieš", "label": "Laikas", "weekdays": { - "mon": "Pirmadienis" + "fri": "Penktadienis", + "mon": "Pirmadienis", + "sat": "Šeštadienis", + "sun": "Sekmadienis", + "thu": "Ketvirtadienis", + "tue": "Antradienis", + "wed": "Trečiadienis" } }, "zone": { @@ -434,19 +866,37 @@ } }, "copy_to_clipboard": "Kopijuoti į iškarpinę", + "default_name": "Naujas automatikos scenarijus", + "description": { + "label": "Aprašymas", + "placeholder": "Neprivalomas aprašymas" + }, "edit_ui": "Redaguoti naudojant vartotojo sąsają", "edit_yaml": "Redaguoti kaip YAML", + "introduction": "Naudokite automatikos scenarijus, kad atgaivintumėte savo namus.", "load_error_not_editable": "Redagavimas leidžiamas tik automatizavimai, esantys automations.yaml", + "modes": { + "documentation": "automatikos dokumentacija", + "label": "Režimas" + }, + "save": "Išsaugoti", "triggers": { "add": "Pridėti trigerį", "delete": "Ištrinti", "delete_confirm": "Ar tikrai norite tai ištrinti?", "duplicate": "Pasikartojantys", + "header": "Trigeriai", "introduction": "Trigeriai yra tai, kas pradeda automatizavimo taisyklės apdorojimą. Tai pačiai taisyklei galima nurodyti kelis aktyviklius. Kai tik įsijungs trigeris, Home Assistant patikrins sąlygas, jei tokių yra, ir iškviečia veiksmą.", "learn_more": "Sužinokite daugiau apie trigerius", "name": "Trigeris", "type_select": "Trigerio tipas", "type": { + "device": { + "extra_fields": { + "for": "Trukmė" + }, + "label": "Įrenginys" + }, "event": { "context_user_pick": "Pridėti vartotoją", "context_user_picked": "Vartotojo įvykis", @@ -481,6 +931,7 @@ }, "state": { "from": "Iš", + "label": "Būsena", "to": "Kam" }, "sun": { @@ -490,28 +941,55 @@ "sunrise": "Saulėtekis", "sunset": "Saulėlydis" }, + "tag": { + "label": "Žyma" + }, + "template": { + "label": "Šablonas", + "value_template": "Vertės šablonas" + }, "time_pattern": { "hours": "Valandos", "label": "Laiko modelis", "minutes": "Minutes", "seconds": "Sekundės" }, + "time": { + "at": "Tuo metu", + "label": "Laikas" + }, "webhook": { "label": "Webhook", "webhook_id": "Webhook ID" }, "zone": { "event": "Įvykis", + "label": "Zona", + "leave": "Palieka", "zone": "Vieta" } }, "unsupported_platform": "Nėra UI palaikymo platformai: {platform}" - } + }, + "unsaved_confirm": "Turite neišsaugotų pakeitimų, ar tikrai norite išeiti?" }, "picker": { + "add_automation": "Pridėti automatikos scenarijų", + "header": "Automatikos redaktorius", + "introduction": "Automatikos redaktorius leidžia kurti ir redaguoti automatikos scenarijus. Spustelėkite toliau pateiktą nuorodą, kad perskaitytumėte instrukcijas ir įsitikintumėte, jog tinkamai sukonfigūravote Home Assistant.", "learn_more": "Sužinokite daugiau apie automatizavimą", "no_automations": "Redaguojamas automatizavimas nerastas", - "only_editable": "Redagavimas leidžiamas tik automatizavimai, esantys automations.yaml" + "only_editable": "Redagavimas leidžiamas tik automatizavimai, esantys automations.yaml", + "pick_automation": "Pasirinkite redaguojamą automatikos scenarijų" + }, + "thingtalk": { + "link_devices": { + "header": "Puiku! Dabar turime susieti kai kuriuos įrenginius" + }, + "task_selection": { + "error_empty": "Įveskite komandą arba bakstelėkite praleisti.", + "for_example": "Pavyzdžiui:" + } } }, "blueprint": { @@ -548,31 +1026,167 @@ }, "cloud": { "account": { - "connected": "Prisijungęs", - "google": { - "devices_pin": "Įrenginio saugos Pin kodas", - "security_devices": "Apsaugoti įrenginiai" + "alexa": { + "config_documentation": "Konfigūracijos dokumentacija", + "disable": "išjungti", + "enable": "įgalinti", + "title": "Alexa" }, - "not_connected": "Neprisijungęs" + "connected": "Prisijungęs", + "connecting": "Jungiamasi...", + "google": { + "config_documentation": "Konfigūracijos dokumentacija", + "devices_pin": "Įrenginio saugos Pin kodas", + "enter_pin_error": "Nepavyko išsaugoti PIN kodo:", + "not_configured_title": "Google Assistant nėra aktyvuotas", + "security_devices": "Apsaugoti įrenginiai", + "title": "Google Assistant" + }, + "integrations": "Integracijos", + "manage_account": "Tvarkyti paskyrą", + "not_connected": "Neprisijungęs", + "remote": { + "certificate_info": "Sertifikato informacija", + "connected": "Prisijungęs", + "link_learn_how_it_works": "Sužinokite, kaip tai veikia", + "not_connected": "Neprisijungęs", + "remote_enabled": { + "caption": "Automatiškai prisijungti" + }, + "title": "Nuotolinis valdymas" + }, + "sign_out": "Atsijungti", + "tts": { + "default_language": "Numatytoji kalba", + "dialog": { + "target_browser": "Naršyklė" + }, + "female": "Moteris", + "male": "Vyras", + "title": "Tekstas į kalbą", + "try": "Bandyti" + }, + "webhooks": { + "loading": "Įkeliama...", + "manage": "Tvarkyti", + "title": "Webhooks" + } + }, + "alexa": { + "manage_domains": "Tvarkyti domenus", + "title": "Alexa" + }, + "description_login": "Prisijungta kaip {email}", + "description_not_login": "Neprisijungęs", + "dialog_certificate": { + "certificate_expiration_date": "Sertifikato galiojimo data:", + "certificate_information": "Sertifikato informacija", + "close": "Uždaryti", + "fingerprint": "Sertifikato piršto atspaudas:" + }, + "dialog_cloudhook": { + "close": "Uždaryti", + "copied_to_clipboard": "Nukopijuota į iškarpinę", + "view_documentation": "Peržiūrėti dokumentaciją" + }, + "forgot_password": { + "check_your_email": "Patikrinkite savo el. paštą, kuriame rasite instrukcijas, kaip iš naujo nustatyti slaptažodį.", + "email": "El. paštas", + "email_error_msg": "Neteisingas el. pašto adresas", + "instructions": "Įveskite savo el. pašto adresą ir mes atsiųsime jums nuorodą, kad galėtumėte iš naujo nustatyti savo slaptažodį.", + "send_reset_email": "Siųsti atstatymo el. laišką", + "subtitle": "Pamiršote savo slaptažodį", + "title": "Pamiršau slaptažodį" + }, + "google": { + "manage_domains": "Tvarkyti domenus", + "sync_to_google": "Sinchronizuojami pakeitimai su Google.", + "title": "Google Assistant" + }, + "login": { + "alert_email_confirm_necessary": "Prieš prisijungdami turite patvirtinti savo el. pašto adresą.", + "alert_password_change_required": "Prieš prisijungdami turite pakeisti slaptažodį.", + "dismiss": "Atmesti", + "email": "El. paštas", + "email_error_msg": "Neteisingas el. paštas", + "forgot_password": "Pamiršote slaptažodį?", + "learn_more_link": "Sužinokite daugiau apie Home Assistant Cloud", + "password": "Slaptažodis", + "password_error_msg": "Slaptažodis turi turėti bent 8 simbolius", + "sign_in": "Prisijungti", + "start_trial": "Pradėti nemokamą 1 mėnesio bandomąją versiją", + "trial_info": "Mokėjimo informacijos pateikti nereikia" + }, + "register": { + "account_created": "Paskyra sukurta! Patikrinkite savo el. paštą, kuriame rasite instrukcijas, kaip aktyvuoti paskyrą.", + "create_account": "Sukurti paskyrą", + "email_address": "El. pašto adresas", + "email_error_msg": "Neteisingas el. pašto adresas", + "feature_amazon_alexa": "Integracija su Amazon Alexa", + "feature_google_home": "Integracija su Google Assistant", + "information4": "Registruodami paskyrą sutinkate su šiomis sąlygomis ir nuostatomis.", + "link_privacy_policy": "Privatumo politika", + "link_terms_conditions": "Terminai ir sąlygos", + "password": "Slaptažodis", + "password_error_msg": "Slaptažodis turi turėti bent 8 simbolius", + "resend_confirm_email": "Pakartotinai išsiųsti patvirtinimo el. laišką", + "title": "Registruoti paskyrą" } }, "core": { - "caption": "Bendra" + "caption": "Bendra", + "description": "Vienetų sistema, vieta, laiko juosta ir kiti bendrieji parametrai", + "section": { + "core": { + "analytics": { + "learn_more": "Kaip mes tvarkome jūsų duomenis", + "preference": { + "diagnostics": { + "description": "Bendrinkite trigdžių ataskaitas, kai įvyksta netikėtų klaidų.", + "title": "Diagnostika" + }, + "statistics": { + "title": "Naudojimo statistika" + }, + "usage_supervisor": { + "description": "Pavadinimai, versijos ir galimybės." + }, + "usage": { + "description": "Pavadinimai ir versijos informacija.", + "title": "Naudotos integracijos" + } + } + }, + "core_config": { + "latitude": "Platuma", + "longitude": "Ilguma", + "save_button": "Išsaugoti" + }, + "header": "Bendroji konfigūracija", + "introduction": "Konfigūracijos keitimas gali būti varginantis procesas. Taip, mes žinome! Todėl šiame skyriuje bandysime šiek tiek palengvinti jūsų gyvenimą." + } + } }, "customize": { + "caption": "Pritaikymai", "picker": { "documentation": "Tinkinimo dokumentacija", "header": "Pritaikymas" + }, + "warning": { + "include_link": "įtraukti customize.yaml" } }, "devices": { "automation": { "actions": { + "caption": "Kai kažkas suveikia...", "no_actions": "Nėra veiksmų", "unknown_action": "Nežinomas veiksmas" }, "automations": "Automatizavimas", "conditions": { + "caption": "Daryti ką nors tik tuo atveju, jei...", "no_conditions": "Nėra sąlygų", "unknown_condition": "Nežinoma sąlyga" }, @@ -580,11 +1194,13 @@ "no_automations": "Nėra automatizavimų", "no_device_automations": "Šiam įrenginiui nėra automatizavimo įrankių", "triggers": { + "caption": "Daryti ką nors, kai...", "no_triggers": "Nėra paleidiklių", "unknown_trigger": "Nežinomas paleidiklis" }, "unknown_automation": "Nežinomas automatizavimas" }, + "caption": "Įrenginiai", "confirm_delete": "Ar tikrai norite ištrinti šį įrenginį?", "data_table": { "area": "Sritis", @@ -628,7 +1244,8 @@ "create_disable": "Negalima sukurti skripto su išjungtu įrenginiu" }, "unknown_error": "Nežinoma klaida", - "unnamed_device": "Bevardis įrenginys" + "unnamed_device": "Bevardis įrenginys", + "update_device_error": "Nepavyko atnaujinti įrenginio" }, "entities": { "caption": "Subjektų registras", @@ -639,38 +1256,160 @@ }, "header": "Subjektų registras", "headers": { - "area": "Sritis" + "area": "Sritis", + "status": "Būsena" }, - "introduction2": "Naudokite subjekto registrą, kad perrašytumėte pavadinimą, pakeiskite subjekto ID arba pašalintumėte įrašą iš namų asistento. Atminkite, kad pašalindami registro įrašą tai nepanaikins pačio subjekto. Norėdami tai padaryti, sekite toliau pateiktą nuorodą ir pašalinkite ją iš integracijos puslapio." + "introduction2": "Naudokite subjekto registrą, kad perrašytumėte pavadinimą, pakeiskite subjekto ID arba pašalintumėte įrašą iš namų asistento. Atminkite, kad pašalindami registro įrašą tai nepanaikins pačio subjekto. Norėdami tai padaryti, sekite toliau pateiktą nuorodą ir pašalinkite ją iš integracijos puslapio.", + "selected": "{number} pasirinkta", + "status": { + "disabled": "Išjungta", + "ok": "Gerai" + } } }, + "filtering": { + "clear": "Išvalyti" + }, "header": "Konfigūruoti Home Assistant", "helpers": { + "dialog": { + "create": "Sukurti" + }, + "picker": { + "headers": { + "editable": "Redaguojamas", + "name": "Pavadinimas", + "type": "Tipas" + } + }, "types": { "counter": "Skaitiklis", + "input_boolean": "Perjungėjas", + "input_datetime": "Data ir (arba) laikas", + "input_number": "Skaičius", + "input_select": "Išskleidžiamas meniu", + "input_text": "Tekstas", "timer": "Laikmatis" } }, "info": { + "caption": "Informacija", "copy_github": "GitHub'ui", - "copy_raw": "Neapdorotas tekstas" + "copy_raw": "Neapdorotas tekstas", + "description": "Versija, sistemos būklė ir nuorodos į dokumentaciją", + "home_assistant_logo": "Home Assistant logotipas", + "server": "serveris", + "setup_time": "Nustatyti laiką", + "source": "Šaltinis:", + "system_health": { + "manage": "Tvarkyti", + "more_info": "daugiau informacijos" + } }, "integrations": { + "add_integration": "Pridėti integraciją", + "caption": "Integracijos", "config_entry": { + "check_the_logs": "Patikrinkite žurnalus", + "configure": "Konfigūruoti", + "delete": "Ištrinti", + "documentation": "Dokumentacija", + "firmware": "Programinė įranga: {versija}", "hub": "Prijungtas per", + "logs": "žurnalai", + "manuf": "sukūrė {manufacturer}", "no_area": "Nėra srities", - "provided_by_custom_integration": "Teikiama naudojant pasirinktinę integraciją" + "not_loaded": "Nepakrauta", + "provided_by_custom_integration": "Teikiama naudojant pasirinktinę integraciją", + "rename": "Pervardyti", + "state": { + "failed_unload": "Įkrauti nepavyko", + "loaded": "Įkrauta", + "migration_error": "Perkėlimo klaida", + "not_loaded": "Nepakrauta" + } }, "config_flow": { "aborted": "Nutraukta", "close": "Uždaryti", + "external_step": { + "description": "Šiam veiksmui atlikti reikia apsilankyti išorinėje svetainėje.", + "open_site": "Atidaryti svetainę" + }, "finish": "Baigti", + "next": "Kitas", "submit": "Pateikti" }, - "details": "Integravimo informacija" + "configured": "Sukonfigūruota", + "details": "Integravimo informacija", + "disable": { + "show": "Rodyti" + }, + "discovered": "Atrasta", + "home_assistant_website": "Home Assistant svetainė", + "ignore": { + "ignore": "Nepaisyti", + "ignored": "Nepaisoma" + }, + "integration": "integracija" }, "introduction": "Šiame vaizde galima sukonfigūruoti savo komponentus ir Home Assistant. Dar ne viską galima sukonfigūruoti iš vartotojo sąsajos (UI ), tačiau mes prie to dirbame.", + "logs": { + "caption": "Žurnalai", + "clear": "Išvalyti", + "description": "Peržiūrėti Home Assistant žurnalus", + "level": { + "info": "INFO" + }, + "loading_log": "Įkeliamas klaidų žurnalas...", + "no_errors": "Apie klaidas nepranešta", + "refresh": "Atnaujinti" + }, + "lovelace": { + "dashboards": { + "caption": "Prietaisų skydeliai", + "confirm_delete": "Ar jūs tikrai norite ištrinti šį prietaisų skydelį?", + "detail": { + "create": "Sukurti", + "delete": "Ištrinti", + "dismiss": "Uždaryti", + "edit_dashboard": "Redaguoti prietaisų skydelį", + "icon": "Piktograma", + "new_dashboard": "Pridėti naują prietaisų skydelį", + "require_admin": "Tik administratoriui", + "title": "Pavadinimas", + "update": "Atnaujinti", + "url": "URL", + "url_error_msg": "URL turi būti raidė - ir jame negali būti tarpų ar specialiųjų simbolių, išskyrus _ ir -" + }, + "picker": { + "add_dashboard": "Pridėti prietaisų skydelį", + "headers": { + "filename": "Failo pavadinimas", + "title": "Pavadinimas" + }, + "open": "Atidaryti" + } + }, + "resources": { + "caption": "Ištekliai", + "picker": { + "headers": { + "type": "Tipas", + "url": "URL" + } + }, + "types": { + "css": "Stilių rinkinys", + "html": "HTML (nebenaudojama)", + "js": "JavaScript failas (nebenaudojama)", + "module": "JavaScript modulis" + } + } + }, "mqtt": { + "button": "Konfigūruoti", + "publish": "Paskelbti", "title": "MQTT" }, "ozw": { @@ -679,6 +1418,7 @@ "wakeup_instructions": "Pažadinimo instrukcijos" }, "navigation": { + "network": "Tinklas", "node": { "config": "Konfigūracija", "dashboard": "Valdymo skydas" @@ -687,6 +1427,10 @@ "network_status": { "unknown": "Nežinoma" }, + "network": { + "header": "Tinklo valdymas", + "introduction": "Tvarkykite viso tinklo funkcijas." + }, "node_config": { "header": "Mazgo konfigūracija", "help_source": "Konfigūracijos parametrų aprašymai ir žinyno tekstas pateikiami OpenZWave projekto.", @@ -694,17 +1438,38 @@ }, "node_metadata": { "product_manual": "Gaminio vadovas" + }, + "nodes_table": { + "id": "ID", + "manufacturer": "Gamintojas", + "model": "Modelis" + }, + "refresh_node": { + "step": "Žingsnis" + }, + "services": { + "cancel_command": "Atšaukti komandą" } }, "person": { + "add_person": "Pridėti asmenį", "caption": "Asmenys", + "confirm_delete": "Ar jūs tikrai norite ištrinti šį asmenį?", + "confirm_delete2": "Visi šiam asmeniui priklausantys įrenginiai taps nepriskirti.", + "create_person": "Sukurti asmenį", "detail": { + "admin": "Administratorius", "allow_login": "Leisti asmeniui prisijungti", "confirm_delete_user": "Ar tikrai norite panaikinti {name} vartotojo abonementą? Jūs vis dar galėsite sekti vartotoją, bet asmuo nebegalės prisijungti.", + "create": "Sukurti", + "delete": "Ištrinti", "device_tracker_intro": "Pasirinkite įrenginius, priklausančius šiam asmeniui.", "device_tracker_pick": "Pasirinkite įrenginį, kurį norite stebėti", "device_tracker_picked": "Stebėti įrenginį", - "name": "Vardas" + "linked_user": "Susietas vartotojas", + "name": "Vardas", + "new_person": "Naujas asmuo", + "update": "Atnaujinti" }, "learn_more": "Sužinokite daugiau apie žmones", "person_not_found": "Nepavyko rasti asmens, kurį bandėte redaguoti.", @@ -718,52 +1483,117 @@ "delete": "Pašalinti įrenginį", "header": "Įrenginiai" }, + "icon": "Piktograma", "load_error_not_editable": "Redaguoti galima tik scenas, esančias scenes.yaml." }, "picker": { + "add_scene": "Pridėti sceną", + "delete_confirm": "Ar jūs tikrai norite ištrinti šią sceną?", + "delete_scene": "Ištrinti sceną", + "edit_scene": "Redaguoti sceną", "learn_more": "Sužinokite daugiau apie scenas", "no_scenes": "Neradome jokių redaguojamų scenų", - "only_editable": "Redaguoti galima tik scenas, esančias scenes.yaml." + "only_editable": "Redaguoti galima tik scenas, esančias scenes.yaml.", + "pick_scene": "Pasirinkite sceną, kurią norite redaguoti", + "show_info_scene": "Rodyti informaciją apie sceną" } }, "script": { + "caption": "Scenarijai", + "description": "Atlikite veiksmų seką", "editor": { - "save_script": "Įrašyti scenarijų" + "default_name": "Naujas scenarijus", + "delete_confirm": "Ar tikrai norite ištrinti šį scenarijų?", + "header": "Scenarijus: {name}", + "modes": { + "label": "Režimas" + }, + "save_script": "Įrašyti scenarijų", + "sequence": "Seka", + "sequence_sentence": "Šio scenarijaus veiksmų seka." }, "picker": { + "add_script": "Pridėti scenarijų", "duplicate": "Dubliuoti", "duplicate_script": "Dubliuoti skriptą", "run_script": "Vykdyti scenarijų" } }, "server_control": { + "description": "Paleisti iš naujo ir sustabdyti Home Assistant serverį", "section": { "reloading": { - "scene": "Perkraukite scenas" + "homekit": "HomeKit", + "person": "Žmonės", + "reload": "{domain}", + "scene": "Perkraukite scenas", + "telegram": "Telegram pranešimo paslaugos", + "zone": "Zonos" + }, + "server_management": { + "confirm_stop": "Ar jūs tikrai norite sustabdyti Home Assistant?", + "heading": "Serverio valdymas", + "introduction": "Valdykite Home Assistant serverį... iš Home Assistant." + }, + "validation": { + "heading": "Konfigūracijos patvirtinimas", + "introduction": "Patikrinkite konfigūraciją, jei neseniai atlikote kai kuriuos konfigūracijos pakeitimus ir įsitikinkite, kad visa konfigūracija teisinga.", + "invalid": "Konfigūracija neteisinga", + "valid": "Konfigūracija teisinga!" } } }, "tag": { + "add_tag": "Pridėti žymą", + "caption": "Žymos", "detail": { "companion_apps": "papildomos programos", + "create": "Sukurti", + "create_and_write": "Sukurti ir įrašyti", + "delete": "Ištrinti", + "description": "Aprašymas", + "tag_id": "Žymos ID", + "update": "Atnaujinti", "usage": "Nuskaitant žymą galima suaktyvinti automatizavimą, galite naudoti NFC žymes, QR kodus ar bet kokios kitos rūšies žymą. Naudokite mūsų {companion_link}, jei norite parašyti šią žymą į programuojamą NFC žymę arba sukurti QR kodą žemiau." }, - "learn_more": "Sužinokite daugiau apie žymas" + "edit": "Redaguoti", + "learn_more": "Sužinokite daugiau apie žymas", + "no_tags": "Nėra žymų" }, "users": { "add_user": { "caption": "Pridėti vartotoją", "create": "Sukurti", - "password": "Slaptažodis" + "password": "Slaptažodis", + "password_not_match": "Slaptažodžiai nesutampa" }, + "caption": "Vartotojai", + "description": "Tvarkykite Home Assistant vartotojų paskyras", "editor": { + "activate_user": "Suaktyvinti vartotoją", + "active": "Aktyvus", "active_tooltip": "Tikrina, ar vartotojas gali prisijungti", + "admin": "Administratorius", "caption": "Peržiūrėti vartotoją", + "change_password": "Pakeisti slaptažodį", + "confirm_user_deletion": "Ar jūs tikrai norite ištrinti {vardą}?", + "deactivate_user": "Išjungti vartotoją", + "delete_user": "Ištrinti vartotoją", + "group": "Grupė", + "id": "ID", + "name": "Rodomas pavadinimas", + "new_password": "Naujas slaptažodis", + "owner": "Savininkas", + "password_changed": "Slaptažodis sėkmingai pakeistas", + "system_generated": "Sugeneruota sistemos", + "unnamed_user": "Bevardis vartotojas", + "update_user": "Atnaujinti", "username": "Vartotojo vardas" }, "picker": { "add_user": "Pridėti vartotoją", "headers": { + "group": "Grupė", "is_active": "Aktyvus", "is_owner": "Savininkas", "username": "Vartotojo vardas" @@ -775,6 +1605,10 @@ "add_device_page": { "spinner": "Ieškoma ZHA Zigbee įrenginių..." }, + "button": "Konfigūruoti", + "configuration_page": { + "update_button": "Atnaujinti konfigūraciją" + }, "device_pairing_card": { "CONFIGURED": "Konfigūracija baigta", "CONFIGURED_status_text": "Inicijuojama", @@ -783,17 +1617,116 @@ "INTERVIEW_COMPLETE_status_text": "Konfigūruojama", "PAIRED": "Rastas įrenginys" }, + "group_binding": { + "bind_button_label": "Susieti grupę", + "header": "Grupės susiejimas", + "introduction": "Susieti ir atsieti grupes." + }, "groups": { - "add_group": "Pridėti grupę" + "add_group": "Pridėti grupę", + "add_members": "Pridėti narių", + "caption": "Grupės", + "create": "Sukurti grupę", + "group_details": "Čia pateikiama visa informacija apie pasirinktą Zigbee grupę.", + "group_id": "Grupės ID", + "group_info": "Grupės informacija", + "group_name_placeholder": "Grupės pavadinimas", + "group_not_found": "Grupė nerasta!", + "groups": "Grupės", + "members": "Nariai", + "remove_members": "Pašalinti narius" + }, + "network": { + "caption": "Tinklas" }, "visualization": { "caption": "Vizualizacija", "header": "Tinklo vizualizacija" } }, - "zwave": { + "zone": { + "add_zone": "Pridėti zoną", + "caption": "Zonos", + "confirm_delete": "Ar jūs tikrai norite ištrinti šią zoną?", + "create_zone": "Sukurti zoną", + "detail": { + "create": "Sukurti", + "delete": "Ištrinti", + "icon": "Piktograma", + "icon_error_msg": "Piktograma turi būti tokio formato: „prefix: iconname“, pvz .: „mdi: home“", + "latitude": "Platuma", + "longitude": "Ilguma", + "new_zone": "Nauja zona", + "passive": "Pasyvus", + "radius": "Spindulys", + "required_error_msg": "Šis laukas yra privalomas", + "update": "Atnaujinti" + } + }, + "zwave_js": { + "common": { + "reconfigure_server": "Iš naujo sukonfigūruoti serverį" + }, + "dashboard": { + "driver_version": "Tvarkyklės versija", + "dump_not_ready_confirm": "Atsisiųsti", + "server_version": "Serverio versija" + }, + "device_info": { + "device_config": "Konfigūruoti įrenginį" + }, + "logs": { + "log_level": "Žurnalo lygis", + "log_level_changed": "Žurnalo lygis pakeistas į: {level}" + }, + "navigation": { + "logs": "Žurnalai" + }, + "network_status": { + "connected": "Prisijungęs", + "connecting": "Jungiasi", + "unknown": "Nežinoma" + }, "node_config": { - "set_config_parameter": "Nustatykite parametrą „Config“" + "attribution": "Įrenginio konfigūracijos parametrus ir aprašymus pateikia {device_database}", + "battery_device_notice": "Įrenginiai su baterijomis turi būti pažadinti, kad būtų galima atnaujinti jų konfigūraciją. Instrukcijas, kaip pažadinti įrenginį, rasite įrenginio vadove.", + "error_device_not_found": "Įrenginys nerastas", + "set_param_accepted": "Parametras buvo atnaujintas.", + "set_param_error": "Įvyko klaida.", + "set_param_queued": "Parametro pakeitimas buvo įrašytas į eilę ir bus atnaujintas, kai įrenginys pabus." + }, + "node_status": { + "alive": "Gyvas", + "asleep": "Miega", + "awake": "Budi", + "dead": "Miręs", + "unknown": "Nežinoma" + } + }, + "zwave": { + "button": "Konfigūruoti", + "common": { + "wakeup_interval": "Žadinimo intervalas" + }, + "node_config": { + "false": "Netiesa", + "seconds": "sekundės", + "set_config_parameter": "Nustatykite parametrą „Config“", + "set_wakeup": "Nustatyti žadinimo intervalą", + "true": "Tiesa" + }, + "node_management": { + "add_to_group": "Pridėti prie grupės", + "group": "Grupė", + "protection": "Apsauga", + "set_protection": "Nustatyti apsaugą" + }, + "services": { + "save_config": "Išsaugoti konfigūraciją", + "soft_reset": "Švelnus nustatymas iš naujo", + "start_network": "Paleisti tinklą", + "stop_network": "Sustabdyti tinklą", + "test_network": "Tikrinti tinklą" } } }, @@ -807,23 +1740,34 @@ "developer-tools": { "tabs": { "events": { + "documentation": "Įvykių dokumentacija", "title": "Įvykiai" }, "services": { + "no_template_ui_support": "Vartotojo sąsaja nepalaiko šablonų, bet jūs vis tiek galite naudoti YAML redaktorių.", "title": "Paslaugos" }, "states": { "last_changed": "Pakeista", "last_updated": "Atnaujinta", + "more_info": "Daugiau informacijos", "title": "Būsenos" }, "templates": { + "domain": "Domenas", "result_type": "Rezultato tipas", "time": "Šis šablonas atnaujinamas kiekvienos minutės pradžioje.", "title": "Šablonas" } } }, + "error": { + "go_back": "Grįžti atgal", + "supervisor": { + "ask": "Prašyti pagalbos", + "system_health": "Patikrinti sistemos būklę" + } + }, "history": { "ranges": { "today": "Šiandien", @@ -837,9 +1781,21 @@ }, "lovelace": { "cards": { + "confirm_delete": "Ar tikrai norite ištrinti šią kortelę?", "empty_state": { "go_to_integrations_page": "Į integracijų puslapį", "title": "Sveiki sugrįžę namo" + }, + "picture-elements": { + "hold": "Laikykite:", + "navigate_to": "Eikite į {location}", + "tap": "Palieskite:", + "toggle": "Perjungti {name}" + }, + "shopping-list": { + "add_item": "Pridėti elementą", + "checked_items": "Patikrinti elementai", + "clear_items": "Išvalyti patikrintus elementus" } }, "editor": { @@ -852,14 +1808,37 @@ "none": "Nėra veiksmų", "toggle": "Perjungti", "url": "Internetinis adresas" - } + }, + "navigation_path": "Navigacijos kelias", + "url_path": "URL kelias" }, "card": { "button": { - "default_action_help": "Numatytasis veiksmas priklauso nuo objekto galimybių, jis bus perjungtas arba bus rodoma daugiau informacijos." + "default_action_help": "Numatytasis veiksmas priklauso nuo objekto galimybių, jis bus perjungtas arba bus rodoma daugiau informacijos.", + "name": "Mygtukas" + }, + "calendar": { + "description": "Kalendoriaus kortelėje rodomas kalendorius, įskaitant dienos, savaitės ir sąrašo rodinius", + "inital_view": "Pradinis vaizdas", + "name": "Kalendorius", + "views": { + "dayGridDay": "Diena", + "dayGridMonth": "Mėnuo", + "listWeek": "Sąrašas" + } + }, + "conditional": { + "card": "Kortelė" + }, + "config": { + "optional": "Neprivaloma", + "required": "Privaloma" }, "entities": { "entity_row_editor": "Objekto eilučių rengyklė", + "entity_row": { + "button": "Mygtukas" + }, "secondary_info_values": { "brightness": "Ryškumas", "entity-id": "Objekto ID", @@ -869,14 +1848,56 @@ "none": "Nėra antrinės informacijos", "position": "Padėtis", "tilt-position": "Pakreipimo padėtis" + }, + "show_header_toggle": "Rodyti antraštės perjungiklį?" + }, + "gauge": { + "severity": { + "green": "Žalia", + "red": "Raudona", + "yellow": "Geltona" } }, + "generic": { + "icon": "Piktograma", + "icon_height": "Piktogramos aukštis", + "image": "Vaizdo kelias", + "no_theme": "Nėra temos", + "refresh_interval": "Atnaujinimo intervalas", + "show_icon": "Rodyti piktogramą?", + "show_name": "Rodyti pavadinimą?", + "theme": "Tema", + "title": "Pavadinimas", + "unit": "Vienetas" + }, + "glance": { + "columns": "Stulpeliai" + }, + "grid": { + "description": "Tinklelio kortelė leidžia rodyti kelias korteles tinklelyje.", + "name": "Tinklelis" + }, "logbook": { "description": "Veiksmų žurnalo kortelėje rodomas įvykių sąrašas.", "name": "Veiksmų žurnalas" }, "picture-glance": { "state_entity": "Būsenos objektas" + }, + "plant-status": { + "name": "Augalo būklė" + }, + "sensor": { + "name": "Jutiklis" + }, + "shopping-list": { + "name": "Pirkinių sąrašas" + }, + "thermostat": { + "name": "Termostatas" + }, + "weather-forecast": { + "name": "Orų prognozė" } }, "common": { @@ -891,12 +1912,16 @@ "edit_card": { "add": "Pridėti kortelę", "clear": "Išvalyti", + "confirm_cancel": "Ar jūs tikrai norite atšaukti?", "delete": "Ištrinti", "edit": "Redaguoti", + "header": "Kortelės konfigūracija", "move": "Perkelti", "move_after": "Perkelti kortelę po", "move_before": "Perkelti kortelę prieš", - "pick_card": "Pasirinkite kortelę, kurią norite pridėti." + "pick_card": "Pasirinkite kortelę, kurią norite pridėti.", + "toggle_editor": "Perjungti redaktorių", + "unsaved_changes": "Turite neišsaugotų pakeitimų" }, "edit_lovelace": { "edit_title": "Redaguoti pavadinimą" @@ -930,6 +1955,7 @@ "raw_editor": "Konfigūracijos redaktorius" }, "migrate": { + "header": "Konfigūracija nesuderinama", "migrate": "Perkelti konfigūraciją" }, "raw_editor": { @@ -945,6 +1971,7 @@ }, "save_config": { "cancel": "Nesvarbu", + "empty_config": "Pradėti nuo tuščio prietaisų skydelio", "header": "Valdykite savo „Lovelace“ vartotojo sąsają", "para_sure": "Ar tikrai norite kontroliuoti savo vartotojo sąsają?", "save": "Kontroliuoti" @@ -955,6 +1982,11 @@ "header": "Antraštės rengyklė", "row": "Objekto eilučių rengyklė" } + }, + "view": { + "panel_mode": { + "warning_multiple_cards": "Šiame rodinyje yra daugiau nei viena kortelė, tačiau skydelio rodinyje gali būti rodoma tik 1 kortelė." + } } }, "menu": { @@ -964,6 +1996,7 @@ "help": "Pagalba", "start_conversation": "Pradėti pokalbį" }, + "reload_lovelace": "Perkrauti vartotojo sąsają", "unused_entities": { "domain": "Domenas", "entity": "Subjektas", @@ -981,8 +2014,13 @@ "empty": "Neturite jokių pranešimų", "playback_title": "Pranešimų atkūrimas" }, + "my": { + "error": "Įvyko nežinoma klaida" + }, "page-authorize": { + "abort_intro": "Prisijungimas nutrauktas", "form": { + "error": "Klaida: {error}", "providers": { "command_line": { "error": { @@ -1002,11 +2040,97 @@ } } } + }, + "homeassistant": { + "error": { + "invalid_auth": "Neteisingas vartotojo vardas arba slaptažodis" + }, + "step": { + "init": { + "data": { + "password": "Slaptažodis", + "username": "Vartotojo vardas" + } + } + } + }, + "legacy_api_password": { + "error": { + "invalid_auth": "Neteisingas API slaptažodis" + }, + "step": { + "init": { + "data": { + "password": "API slaptažodis" + } + } + } + }, + "trusted_networks": { + "step": { + "init": { + "data": { + "user": "Vartotojas" + } + } + } + } + }, + "start_over": "Pradėti iš naujo", + "unknown_error": "Kažkas nutiko ne taip", + "working": "Prašome palaukti" + }, + "initializing": "Inicijuojama", + "logging_in_with": "Prisijungiama naudojant **{authProviderName}**.", + "pick_auth_provider": "Arba prisijunkite naudodami" + }, + "page-demo": { + "cards": { + "demo": { + "demo_by": "pateikė {name}", + "learn_more": "Sužinokite daugiau apie Home Assistant", + "next_demo": "Kita demonstracija" + } + }, + "config": { + "arsaboo": { + "labels": { + "activity": "Veikla", + "entertainment": "Pramogos", + "hdmi_input": "HDMI įvestis", + "hdmi_switcher": "HDMI perjungiklis", + "information": "Informacija", + "lights": "Šviesos", + "turn_tv_off": "Išjunkite televizorių" + }, + "names": { + "family_room": "Šeimos kambarys", + "hallway": "Prieškambaris", + "kitchen": "Virtuvė", + "master_bedroom": "Pagrindinis miegamasis", + "upstairs": "Viršuje" + }, + "unit": { + "minutes_abbr": "min" } } } }, "page-onboarding": { + "analytics": { + "finish": "Kitas" + }, + "core-config": { + "button_detect": "Aptikti", + "finish": "Kitas", + "location_name_default": "Namai" + }, + "finish": "Baigti", + "integration": { + "finish": "Baigti", + "more_integrations": "Daugiau" + }, + "next": "Kitas", "restore": { "description": "Taip pat galite atkurti iš ankstesnės momentinės kopijos.", "hide_log": "Slėpti visą žurnalą", @@ -1014,42 +2138,96 @@ "show_log": "Rodyti visą žurnalą" }, "user": { + "create_account": "Sukurti paskyrą", "data": { - "password_confirm": "Patvirtinti slaptažodį" + "name": "Vardas", + "password": "Slaptažodis", + "password_confirm": "Patvirtinti slaptažodį", + "username": "Vartotojo vardas" }, "error": { - "password_not_match": "Slaptažodžiai nesutampa" - } + "password_not_match": "Slaptažodžiai nesutampa", + "required_fields": "Užpildykite visus privalomus laukus" + }, + "intro": "Pradėkime nuo vartotojo paskyros sukūrimo.", + "required_field": "Būtina" } }, "profile": { + "advanced_mode": { + "description": "Atrakina išplėstines funkcijas.", + "title": "Išplėstinis režimas" + }, "change_password": { "current_password": "Dabartinis slaptažodis", "error_new_is_old": "Naujas slaptažodis turi skirtis nuo dabartinio slaptažodžio", "error_new_mismatch": "Nesutampa naujojo slaptažodžio laukai", + "error_required": "Privaloma", "header": "Keisti slaptažodį", "new_password": "Naujas slaptažodis", + "submit": "Pateikti", "success": "Slaptažodis pakeistas sėkmingai" }, + "current_user": "Šiuo metu esate prisijungęs kaip {fullName}.", + "dashboard": { + "header": "Prietaisų skydelis" + }, + "enable_shortcuts": { + "description": "Įjunkite arba išjunkite sparčiuosius klaviatūros klavišus, skirtus atlikti įvairius veiksmus vartotojo sąsajoje.", + "header": "Spartieji klaviatūros klavišai" + }, + "force_narrow": { + "header": "Visada slėpti šoninę juostą" + }, + "is_owner": "Jūs esate savininkas.", "language": { "dropdown_label": "Kalba", - "header": "Kalba" + "header": "Kalba", + "link_promo": "Padėkite versti" + }, + "logout": "Atsijungti", + "logout_text": "Ar tikrai norite atsijungti?", + "logout_title": "Atsijungti?", + "long_lived_access_tokens": { + "created": "Sukurta {date}" }, "mfa_setup": { "close": "Uždaryti", - "title_aborted": "Nutraukta" + "step_done": "{step} sąranka atlikta", + "submit": "Pateikti", + "title_aborted": "Nutraukta", + "title_success": "Sėkmė!" + }, + "mfa": { + "confirm_disable": "Ar jūs tikrai norite išjungti {name}?", + "disable": "Išjungti", + "enable": "Įgalinti" }, "number_format": { + "description": "Pasirinkite, kaip formatuojami skaičiai.", "dropdown_label": "Skaičių formatas", "formats": { + "comma_decimal": "1,234,567.89", + "decimal_comma": "1.234.567,89", "language": "Automatinis (naudoti kalbos nustatymą)", "none": "Joks", + "space_comma": "1 234 567,89", "system": "Naudoti sistemos lokalę" }, "header": "Skaičių formatas" }, "push_notifications": { - "description": "Siųsti pranešimus į šį įrenginį." + "add_device_prompt": { + "input_label": "Įrenginio pavadinimas" + }, + "description": "Siųsti pranešimus į šį įrenginį.", + "header": "\"Push\" pranešimai", + "link_promo": "Sužinokite daugiau", + "push_notifications": "\"Push\" pranešimai" + }, + "refresh_tokens": { + "created_at": "Sukurta {date}", + "last_used": "Paskutinį kartą naudota {date} iš {location}" }, "themes": { "accent_color": "Akcento spalva", @@ -1059,11 +2237,14 @@ "light": "Šviesi" }, "dropdown_label": "Tema", + "error_no_theme": "Temų nėra.", "header": "Tema", + "link_promo": "Sužinokite apie temas", "primary_color": "Pagrindinė spalva", "reset": "Atstatyti" }, "time_format": { + "description": "Pasirinkite, kaip formatuojami laikai.", "dropdown_label": "Laiko formatas", "formats": { "12": "12 valandų (AM/PM)", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index b611bf919d..639463d622 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -2965,6 +2965,7 @@ "home_id": "ID дома", "network": "Сеть", "node_id": "ID узла", + "reconfigure_server": "Перенастроить сервер", "remove_node": "Удалить узел" }, "dashboard": { diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index a2d807aa69..3c0917b41d 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -2965,6 +2965,7 @@ "home_id": "家庭 ID", "network": "网络", "node_id": "节点 ID", + "reconfigure_server": "重新配置服务", "remove_node": "删除节点" }, "dashboard": { From 45436731e2843f216aeefaf555b49f6e6b600318 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 25 Jun 2021 06:36:23 +0200 Subject: [PATCH 51/73] Fix select entity disabled when no item selected (#9465) --- src/panels/lovelace/entity-rows/hui-select-entity-row.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts index 7133db16f8..ddf98be900 100644 --- a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts @@ -17,7 +17,7 @@ import { computeDomain } from "../../../common/entity/compute_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; import "../../../components/entity/state-badge"; import "../../../components/ha-paper-dropdown-menu"; -import { UNAVAILABLE_STATES } from "../../../data/entity"; +import { UNAVAILABLE } from "../../../data/entity"; import { forwardHaptic } from "../../../data/haptics"; import { SelectEntity, setSelectOption } from "../../../data/select"; import { ActionHandlerEvent } from "../../../data/lovelace"; @@ -87,7 +87,7 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow { > From 4ec9c9c16ea6fb2e13e73a23ab2ecef7bd4f656f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 26 Jun 2021 00:46:57 +0000 Subject: [PATCH 52/73] Translation update --- translations/frontend/ca.json | 1 + translations/frontend/es.json | 2 +- translations/frontend/fr.json | 36 ++++++++++++++++++++++- translations/frontend/it.json | 1 + translations/frontend/ja.json | 47 ++++++++++++++++++++++++++++-- translations/frontend/nb.json | 1 + translations/frontend/nl.json | 1 + translations/frontend/ru.json | 10 +++---- translations/frontend/zh-Hant.json | 1 + 9 files changed, 90 insertions(+), 10 deletions(-) diff --git a/translations/frontend/ca.json b/translations/frontend/ca.json index c15932954c..46336463ad 100644 --- a/translations/frontend/ca.json +++ b/translations/frontend/ca.json @@ -2965,6 +2965,7 @@ "home_id": "ID principal", "network": "Xarxa", "node_id": "ID del node", + "reconfigure_server": "Torna a configurar el servidor", "remove_node": "Elimina node" }, "dashboard": { diff --git a/translations/frontend/es.json b/translations/frontend/es.json index 4ad16212b8..3446d51222 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -197,7 +197,7 @@ "backup": "copia de seguridad", "default": "predeterminado", "homeassistant": "homeassistant", - "manager": "gerente" + "manager": "Administrador" }, "stage": { "description": "Los complementos pueden tener una de tres etapas: \n\n {icon_stable} ** Estable **: estos son complementos listos para usarse en producción. \n\n {icon_experimental} ** Experimental **: estos pueden contener errores y pueden estar inacabados. \n\n {icon_deprecated} ** Obsoleto **: estos complementos ya no recibirán actualizaciones.", diff --git a/translations/frontend/fr.json b/translations/frontend/fr.json index 8955807461..b0d41ac16e 100644 --- a/translations/frontend/fr.json +++ b/translations/frontend/fr.json @@ -318,6 +318,14 @@ "no_addons": "Vous n'avez pas encore installé de modules complémentaires. Rendez-vous dans la boutique des modules complémentaires pour commencer!" }, "dialog": { + "hardware": { + "attributes": "Attributs", + "device_path": "Chemin du dispositif", + "id": "Identifiant", + "search": "Recherche de matériel", + "subsystem": "Sous-système", + "title": "Matériel informatique" + }, "network": { "connected_to": "Connecté à {ssid}", "dhcp": "DHCP", @@ -368,6 +376,8 @@ "error": "Une erreur inconnue s'est produite", "error_addon_no_ingress": "L’add-on demandé ne prend pas en charge l’entrée", "error_addon_not_found": "Module complémentaire introuvable", + "error_addon_not_installed": "Le module complémentaire demandé n'est pas installé. Veuillez l'installer d'abord", + "error_addon_not_started": "Le module complémentaire demandé n'est pas en cours d'exécution. Veuillez le lancer d'abord", "faq_link": "FAQ de My Home Assistant", "not_supported": "Cette redirection n'est pas prise en charge par votre instance Home Assistant. Vérifiez le {link} pour les redirections prises en charge et la version dans laquelle elles ont été introduites." }, @@ -386,8 +396,13 @@ "create_blocked_not_running": "La création d’un instantané n’est pas possible en ce moment car le système est en état {state}.", "create_snapshot": "Créer un instantané", "created": "créé", + "delete_selected": "Supprimer les instantanés sélectionnés", + "delete_snapshot_confirm": "Supprimer", + "delete_snapshot_text": "Voulez-vous supprimer {number} {number, plural,\n one {entité}\n other {entités}\n} ?", + "delete_snapshot_title": "Supprimer l'instantané", "description": "Les instantanés vous permettent de sauvegarder et de restaurer facilement toutes les données de votre instance Home Assistant.", "enter_password": "Veuillez entrer un mot de passe.", + "failed_to_delete": "Échec de la suppression du fichier: %@", "folder": { "addons/local": "Modules complémentaires locaux", "homeassistant": "Configuration Home Assistant", @@ -405,6 +420,8 @@ "password_protection": "Protection par mot de passe", "passwords_not_matching": "Les mots de passe ne correspondent pas", "security": "Sécurité", + "select_type": "Sélectionnez ce qu'il faut restaurer", + "selected": "{number} sélectionné", "type": "Type", "upload_snapshot": "Téléverser un instantané" }, @@ -722,6 +739,9 @@ "no_match": "Aucune pièce correspondante trouvée", "show_areas": "Afficher les pièces" }, + "attributes": { + "expansion_header": "Attributs" + }, "blueprint-picker": { "add_user": "Ajouter un utilisateur", "remove_user": "Supprimer l'utilisateur", @@ -924,6 +944,9 @@ "config_entry_system_options": { "enable_new_entities_description": "Si désactivé, les nouvelles entités découvertes pour {integration} ne seront pas ajoutées automatiquement à Home Assistant.", "enable_new_entities_label": "Activer les entités nouvellement ajoutées.", + "enable_polling_description": "Si Home Assistant doit interroger automatiquement les entités {integration} pour les mises à jour.", + "enable_polling_label": "Activez l'interrogation pour les mises à jour.", + "restart_home_assistant": "Vous devez redémarrer Home Assistant pour que vos modifications soient prises en compte.", "title": "Options système pour {integration}", "update": "Mise à jour" }, @@ -1722,6 +1745,7 @@ "title": "Alexa" }, "connected": "Connecté", + "connecting": "Connexion...", "connection_status": "État de la connexion cloud", "fetching_subscription": "Récupération de l'abonnement...", "google": { @@ -2065,7 +2089,8 @@ "scripts": "Scripts", "unknown_error": "Erreur inconnue", "unnamed_device": "Appareil sans nom", - "update": "Mettre à jour" + "update": "Mettre à jour", + "update_device_error": "Échec de la mise à jour de l’appareil" }, "entities": { "caption": "Entités", @@ -2198,6 +2223,7 @@ "depends_on_cloud": "Dépend du cloud", "device_unavailable": "Appareil non disponible", "devices": "{count} {count, plural,\n one {appareil}\n other {appareils}\n}", + "disable_error": "Échec de l’activation ou de la désactivation de l’intégration", "disable_restart_confirm": "Redémarrez Home Assistant pour terminer la désactivation de cette intégration", "disable": { "disable_confirm": "Voulez-vous vraiment désactiver cette entrée de configuration? Ses appareils et entités seront désactivés.", @@ -2209,6 +2235,7 @@ }, "disabled_cause": "Désactivé par {cause}" }, + "disabled_polling": "Francais", "documentation": "Documentation", "enable_restart_confirm": "Redémarrez Home Assistant pour terminer l'activation de cette intégration", "entities": "{count} {count, plural,\n one {entity}\n other {entities}\n}", @@ -2591,6 +2618,8 @@ "add_scene": "Ajouter une scène", "delete_confirm": "Êtes-vous sûr de vouloir supprimer cette scène?", "delete_scene": "Supprimer la scène", + "duplicate": "Dupliquer", + "duplicate_scene": "Dupliquée la scène", "edit_scene": "Éditer la scène", "header": "Éditeur de scène", "headers": { @@ -2919,6 +2948,8 @@ "follow_device_instructions": "Suivez les instructions fournies avec votre appareil pour déclencher l'appairage sur l'appareil.", "inclusion_failed": "Le nœud n'a pas pu être ajouté. Veuillez consulter les journaux pour plus d'informations.", "inclusion_finished": "Le nœud a été ajouté. Quelques minutes peuvent s'écouler avant que toutes les entités n'apparaissent, alors que nous terminons la mise en place du nœud en arrière-plan.", + "interview_failed": "L'interrogation de l'appareil a échoué. Des informations additionnelles peuvent être disponibles dans les journaux.", + "interview_started": "L'appareil est en cours d'interrogation. Cela peut prendre du temps.", "introduction": "Cet assistant vous guidera dans l'ajout d'un nœud à votre réseau Z-Wave.", "secure_inclusion_warning": "Les dispositifs sécurisés nécessitent une bande passante supplémentaire ; un trop grand nombre de dispositifs sécurisés peut ralentir votre réseau Z-Wave. Nous recommandons de n'utiliser l'inclusion sécurisée que pour les dispositifs qui en ont besoin, comme les serrures ou les ouvre-portes de garage.", "start_inclusion": "Commencer l'inclusion", @@ -2934,6 +2965,7 @@ "home_id": "ID de la maison", "network": "Réseau", "node_id": "ID du nœud", + "reconfigure_server": "Reconfigurer le serveur", "remove_node": "Supprimer le nœud" }, "dashboard": { @@ -2958,6 +2990,7 @@ }, "logs": { "log_level": "Niveau du journal", + "log_level_changed": "Niveau de journal modifié en : {level}", "subscribed_to_logs": "S'abonner aux messages du journal Z-Wave JS", "title": "Journaux Z-Wave JS" }, @@ -4022,6 +4055,7 @@ "formats": { "12": "12 heures (AM / PM)", "24": "24 heures", + "language": "Auto (utiliser le paramètre de langue)", "system": "Utiliser les paramètres régionaux du système" }, "header": "Format de l'heure" diff --git a/translations/frontend/it.json b/translations/frontend/it.json index ee8c41af03..d2ddb9ca09 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -2965,6 +2965,7 @@ "home_id": "ID Home", "network": "Rete", "node_id": "ID Nodo", + "reconfigure_server": "Riconfigurare il server", "remove_node": "Rimuovi Nodo" }, "dashboard": { diff --git a/translations/frontend/ja.json b/translations/frontend/ja.json index 839f80267b..aae44f3386 100644 --- a/translations/frontend/ja.json +++ b/translations/frontend/ja.json @@ -313,7 +313,12 @@ }, "dialog": { "hardware": { - "search": "ハードウェアの検索" + "attributes": "属性", + "device_path": "デバイスパス", + "id": "ID", + "search": "ハードウェアの検索", + "subsystem": "サブシステム", + "title": "ハードウェア" }, "network": { "connected_to": "{ssid}に接続しました", @@ -365,6 +370,7 @@ "error": "不明なエラーが発生しました", "error_addon_no_ingress": "要求されたアドオンは入力をサポートしていません", "error_addon_not_found": "アドオンが見つかりません", + "error_addon_not_installed": "要求されたアドオンがインストールされていません。先にインストールしてください。", "error_addon_not_started": "要求されたアドオンは実行されていません。最初に起動してください", "faq_link": "マイホームアシスタントFAQ", "not_supported": "このリダイレクトは、HomeAssistantインスタンスではサポートされていません。 サポートされているリダイレクトとそれらが導入されたバージョンについては、{link}を確認してください。" @@ -408,6 +414,7 @@ "password_protection": "パスワード保護", "passwords_not_matching": "パスワードが一致しません", "security": "セキュリティ", + "select_type": "復元する対象を選択する", "selected": "{number}が選択されました", "type": "タイプ", "upload_snapshot": "スナップショットのアップロード" @@ -568,9 +575,11 @@ }, "light": { "brightness": "明るさ", + "cold_white_value": "冷たい白い明るさ", "color_brightness": "色の明るさ", "color_temperature": "色温度", "effect": "効果", + "warm_white_value": "暖かい白い明るさ", "white_value": "白さの値" }, "lock": { @@ -890,6 +899,7 @@ } }, "service-control": { + "integration_doc": "統合ドキュメント", "required": "この項目は必須です", "service_data": "サービスデータ", "target": "ターゲット", @@ -918,6 +928,9 @@ "config_entry_system_options": { "enable_new_entities_description": "無効にするには、 {integration} から検出された新しいエンティティは Home Assistant に自動的に追加されません。", "enable_new_entities_label": "新しく追加されたエンティティを有効にします。", + "enable_polling_description": "ホームアシスタントが{integration}エンティティの更新情報を自動的にポーリングする場合。", + "enable_polling_label": "更新のポーリングを有効にします。", + "restart_home_assistant": "変更を有効にするには、HomeAssistantを再起動する必要があります。", "title": "{integration} のシステムオプション", "update": "更新" }, @@ -1197,13 +1210,20 @@ }, "zha_reconfigure_device": { "attribute": "属性", + "battery_device_warning": "再構成プロセスを開始する前に、バッテリ駆動デバイスをスリープ解除する必要があります。デバイスのスリープ解除方法については、デバイスのマニュアルを参照してください。", + "bind_header": "バインディング", "button_hide": "詳細を非表示", "button_show": "詳細を表示", + "cluster_header": "クラスター", "configuration_complete": "デバイスの再構成が完了しました。", "configuration_failed": "デバイスの再構成に失敗しました。追加情報はログで入手できる場合があります。", "configuring_alt": "設定", "heading": "デバイスを再設定", "in_progress": "デバイスを再構成中です。これには時間がかかる場合があります。", + "introduction": "Zigbee ネットワーク上のデバイスを再構成します。デバイスが正常に機能していない場合は、この機能を使用します。", + "min_max_change": "最小/最大/変更", + "reporting_header": "報告", + "run_in_background": "このダイアログを閉じても、再設定はバックグラウンドで行われます。", "start_reconfiguration": "再構成を開始" } }, @@ -1283,6 +1303,7 @@ "linked_entities_caption": "エンティティ", "name": "名前", "name_required": "名前は必須です", + "no_linked_entities": "このエリアにリンクしているエンティティはありません。", "unknown_error": "不明なエラー", "update": "更新" }, @@ -1738,6 +1759,7 @@ "remote": { "access_is_being_prepared": "リモート アクセスの準備中です。準備ができたらお知らせします。", "certificate_info": "証明書情報", + "connected": "接続", "info": "Home Assistant Cloud は、自宅の外からインスタンスへの安全なリモート接続を提供します。", "instance_is_available": "インスタンスは次の場所にあります", "instance_will_be_available": "インスタンスは次の時点で利用可能になります。", @@ -2177,10 +2199,13 @@ "caption": "インテグレーション", "config_entry": { "area": "{area}", + "check_the_logs": "ログの確認", + "configure": "設定", "delete": "削除", "delete_confirm": "この統合を削除しますか?", "device_unavailable": "デバイスを利用できません", "devices": "{count} {count, plural,\n one {デバイス}\n other {デバイス}\n}", + "disable_error": "統合の有効化または無効化に失敗しました", "disable_restart_confirm": "Homeassistantを再起動して、このintegrationを無効にします。", "disable": { "disable_confirm": "この設定項目を無効にしてよろしいですか?そのデバイスやエンティティは無効になります。", @@ -2192,6 +2217,7 @@ }, "disabled_cause": "{cause}によって無効化" }, + "disabled_polling": "更新されたデータの自動ポーリングが無効", "documentation": "ドキュメント", "enable_restart_confirm": "Home Assistantを再起動して、このintegrationを有効にします", "entities": "{count} {count, plural,\n one {エンティティ}\n other {エントリー}\n}", @@ -2203,6 +2229,7 @@ "no_area": "エリアなし", "not_loaded": "読み込まれていない場合は{logs_link} を確認してください", "options": "オプション", + "provided_by_custom_integration": "カスタムインテグレーションによる提供", "reload": "再読込", "reload_confirm": "インテグレーションが再読み込みされました", "reload_restart_confirm": "ホームアシスタントを再起動してこのインテグレーションの再読み込みを完了してください。\n", @@ -2210,7 +2237,9 @@ "restart_confirm": "ホーム アシスタントを再起動して、この統合の削除を完了します。", "services": "{count} {count, plural,\n one {サービス}\n other {サービス}\n}", "state": { + "failed_unload": "アンロードに失敗しました。", "loaded": "読み込み", + "migration_error": "移行エラー", "not_loaded": "読み込まれていません", "setup_retry": "設定をやり直す" }, @@ -2570,6 +2599,7 @@ "add_scene": "シーンを追加", "delete_confirm": "このシーンを削除してもよろしいですか?", "delete_scene": "シーンを削除", + "duplicate": "複製", "duplicate_scene": "シーンの複製", "edit_scene": "シーンを編集", "header": "シーンエディター", @@ -2804,9 +2834,12 @@ "value": "バリュー" }, "configuration_page": { + "shortcuts_title": "ショートカット", + "update_button": "構成の更新", "zha_options": { "default_light_transition": "デフォルトのライト遷移時間(秒)", - "enable_identify_on_join": "デバイスがネットワークに参加する際に、識別効果を有効にする" + "enable_identify_on_join": "デバイスがネットワークに参加する際に、識別効果を有効にする", + "title": "グローバルオプション" } }, "device_pairing_card": { @@ -2913,6 +2946,7 @@ "home_id": "ホームID", "network": "ネットワーク", "node_id": "ノードID", + "reconfigure_server": "サーバーの再設定", "remove_node": "ノードの削除" }, "dashboard": { @@ -2936,7 +2970,10 @@ "zwave_info": "Z-Wave情報" }, "logs": { - "log_level_changed": "ログレベルが変更されました。{level}に変更されました。" + "log_level": "ログレベル", + "log_level_changed": "ログレベルが変更されました。{level}に変更されました。", + "subscribed_to_logs": "Z-WaveJSログメッセージを購読しました...", + "title": "Z-WaveJSログ" }, "navigation": { "logs": "ログ", @@ -2954,6 +2991,9 @@ "header": "Z-Waveデバイスの設定", "introduction": "選択したデバイスのデバイス(ノード)固有の設定パラメータを管理および調整する", "parameter_is_read_only": "このパラメータは読み取り専用です。", + "set_param_accepted": "パラメータが更新されました。", + "set_param_error": "エラーが発生しました。", + "set_param_queued": "パラメーターの変更はキューに入れられており、デバイスがスリープ解除されると更新されます。", "zwave_js_device_database": "Z-Wave JSデバイスデータベース" }, "node_status": { @@ -2968,6 +3008,7 @@ "in_progress": "デバイスがインタビュー中です。これには時間がかかる場合があります。", "interview_complete": "デバイスのインタビューが完了しました。", "interview_failed": "デバイスのインタビューに失敗しました。追加情報がログに残っている場合があります。", + "introduction": "Z-Wave ネットワーク上のデバイスに再インタビューします。デバイスの機能が不足している場合や、機能が正しくない場合は、この機能を使用します。", "run_in_background": "このダイアログを閉じても、インタビューはバックグラウンドで継続されます。", "start_reinterview": "再インタビューを開始", "title": "Z-Waveデバイスへの再インタビュー" diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index ca09cccc72..cf43e1e937 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -2965,6 +2965,7 @@ "home_id": "Hjem-ID", "network": "Nettverk", "node_id": "Node-ID", + "reconfigure_server": "Konfigurer server på nytt", "remove_node": "Fjern node" }, "dashboard": { diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 149728e21e..ca8aa52bd0 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -2965,6 +2965,7 @@ "home_id": "Home ID", "network": "Netwerk", "node_id": "Knooppunt-ID", + "reconfigure_server": "Herconfigureer server", "remove_node": "Knooppunt verwijderen" }, "dashboard": { diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 639463d622..f710c5c02c 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -540,11 +540,11 @@ "climate": { "aux_heat": "Дополнительный нагрев", "away_mode": "Режим \"не дома\"", - "cooling": "{name} охлаждение", - "current_temperature": "{name} текущая температура", + "cooling": "Охлаждение {name}", + "current_temperature": "Текущая температура {name}", "currently": "Сейчас", "fan_mode": "Режим вентиляции", - "heating": "{name} обогрев", + "heating": "Обогрев {name}", "high": "высокий", "low": "низкий", "on_off": "Вкл / Выкл", @@ -553,8 +553,8 @@ "swing_mode": "Режим качания воздушных шторок", "target_humidity": "Заданная влажность", "target_temperature": "Заданная температура", - "target_temperature_entity": "{name} заданная температура", - "target_temperature_mode": "{name} заданная температура {mode}" + "target_temperature_entity": "Заданная температура {name}", + "target_temperature_mode": "Заданная температура {name} в режиме {mode}" }, "counter": { "actions": { diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index ff4f4f9cfb..cf81b2140b 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -2965,6 +2965,7 @@ "home_id": "家庭 ID", "network": "網路", "node_id": "節點 ID", + "reconfigure_server": "重新設定伺服器", "remove_node": "移除節點" }, "dashboard": { From 97312577829cf8c417324ef5479ca2ed40871dd4 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 27 Jun 2021 00:47:51 +0000 Subject: [PATCH 53/73] Translation update --- translations/frontend/de.json | 1 + translations/frontend/he.json | 3 ++- translations/frontend/ko.json | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/translations/frontend/de.json b/translations/frontend/de.json index 89fa98cd1d..620215d570 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -2965,6 +2965,7 @@ "home_id": "Heim-ID", "network": "Netzwerk", "node_id": "Knoten-ID", + "reconfigure_server": "Server neu konfigurieren", "remove_node": "Knoten entfernen" }, "dashboard": { diff --git a/translations/frontend/he.json b/translations/frontend/he.json index 995c0e25a3..d2a5d123bf 100644 --- a/translations/frontend/he.json +++ b/translations/frontend/he.json @@ -2003,7 +2003,7 @@ } }, "devices": { - "add_prompt": "אף {name} לא נוסף באמצעות מכשיר זה. אתה יכול להוסיף אחד על ידי לחיצה על כפתור + למעלה.", + "add_prompt": "אף {name} לא נוסף באמצעות התקן זה. ניתן להוסיף אחד על ידי לחיצה על כפתור + למעלה.", "automation": { "actions": { "caption": "כשמשהו מופעל...", @@ -2965,6 +2965,7 @@ "home_id": "מזהה בית", "network": "רשת", "node_id": "מזהה צומת", + "reconfigure_server": "קביעת תצורה מחדש של שרת", "remove_node": "הסר צומת" }, "dashboard": { diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index 819ce983e3..6df6cb3d6f 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -2965,6 +2965,7 @@ "home_id": "집 ID", "network": "네트워크", "node_id": "노드 ID", + "reconfigure_server": "서버 재구성", "remove_node": "노드 제거하기" }, "dashboard": { From 62228ef1445439d6d9746803ee16e23028277b18 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 28 Jun 2021 00:47:17 +0000 Subject: [PATCH 54/73] Translation update --- translations/frontend/es.json | 2 +- translations/frontend/hu.json | 245 ++++++++++++++++++++++++++++++++-- 2 files changed, 235 insertions(+), 12 deletions(-) diff --git a/translations/frontend/es.json b/translations/frontend/es.json index 3446d51222..cacfdbf8ea 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -197,7 +197,7 @@ "backup": "copia de seguridad", "default": "predeterminado", "homeassistant": "homeassistant", - "manager": "Administrador" + "manager": "administrador" }, "stage": { "description": "Los complementos pueden tener una de tres etapas: \n\n {icon_stable} ** Estable **: estos son complementos listos para usarse en producción. \n\n {icon_experimental} ** Experimental **: estos pueden contener errores y pueden estar inacabados. \n\n {icon_deprecated} ** Obsoleto **: estos complementos ya no recibirán actualizaciones.", diff --git a/translations/frontend/hu.json b/translations/frontend/hu.json index b4e93321d6..7d62d2a650 100644 --- a/translations/frontend/hu.json +++ b/translations/frontend/hu.json @@ -126,12 +126,14 @@ }, "dashboard": { "action_error": { + "go_to_config": "Nem sikerült elindítani a bővítményt - a konfiguráció ellenőrzése nem sikerült!", "install": "A bővítmény telepítése sikertelen", "restart": "A bővítmény újraindítása sikertelen", "start": "A bővítmény indítása sikertelen", "start_invalid_config": "Ugrás a konfigurációra", "stop": "A bővítmény leállítása sikertelen", - "uninstall": "A bővítmény törlése sikertelen" + "uninstall": "A bővítmény törlése sikertelen", + "validate_config": "Nem sikerült ellenőrizni a kiegészítő konfigurációját" }, "capability": { "apparmor": { @@ -141,13 +143,25 @@ "title": "Home Assistant Hitelesítés" }, "docker_api": { + "description": "A kiegészítő szerzője kérte a hozzáférését a rendszeren futó Docker-példányhoz. Ez a mód teljes hozzáférést és vezérlést biztosít a kiegészítőnek az egész Home Assistant rendszerhez, ami biztonsági kockázatokat jelent, és visszaélés esetén károsíthatja a rendszert. Ezért ez a szolgáltatás negatívan befolyásolja a Home assistant biztonságát\n\nEzt a hozzáférési szintet a program nem kapja meg automatikusan, ezt Önnek kell megerősítenie. Ehhez manuálisan le kell tiltania a kiegészítő védelmi módját. Csak akkor tiltsa le a védelmi módot, ha tudja, szükség van ÉS megbízik a kiegészítő forrásában.", "title": "Teljes Docker hozzáférés" }, + "full_access": { + "description": "Ez a kiegészítő teljes hozzáférést biztosít a rendszer hardveréhez, a kiegészítő szerzőének kérésére. A hozzáférés összehasonlítható a Docker privilegizált módjával. Mivel ez lehetséges biztonsági kockázatokat tár fel, ez a szolgáltatás negatívan befolyásolja a Home assistant biztonságát. \n\nEzt a hozzáférési szintet a program nem kapja meg automatikusan, ezt Önnek kell megerősítenie. Ehhez manuálisan le kell tiltania a kiegészítő védelmi módját. Csak akkor tiltsa le a védelmi módot, ha tudja, szükség van ÉS megbízik a kiegészítő forrásában.", + "title": "Teljes hozzáférés a hardverhez" + }, "hassio_api": { "title": "Supervisor API hozzáférés" }, + "homeassistant_api": { + "title": "Home Assistant API-hozzáférés" + }, "host_network": { - "description": "A bővítmények általában a saját elszigetelt hálózati rétegükben futnak, ami megakadályozza, hogy hozzáférjenek a gazdagép operációs rendszer hálózatához. Bizonyos esetekben ez a hálózati elkülönítés korlátozhatja a bővítményeket a szolgáltatásaik nyújtásában, ezért az elkülönítést a bővítmény szerzője feloldhatja, így a bővítmény teljes hozzáférést biztosít a gazdaszámítógép hálózati képességeihez. Ez több hálózati lehetőséget biztosít a bővítménynek, de csökkenti a biztonságot, ezért a bővítmény biztonsági besorolása csökken, ha ezt a beállítást a bővítmény használja." + "description": "A bővítmények általában a saját elszigetelt hálózati rétegükben futnak, ami megakadályozza, hogy hozzáférjenek a gazdagép operációs rendszer hálózatához. Bizonyos esetekben ez a hálózati elkülönítés korlátozhatja a bővítményeket a szolgáltatásaik nyújtásában, ezért az elkülönítést a bővítmény szerzője feloldhatja, így a bővítmény teljes hozzáférést biztosít a gazdaszámítógép hálózati képességeihez. Ez több hálózati lehetőséget biztosít a bővítménynek, de csökkenti a biztonságot, ezért a bővítmény biztonsági besorolása csökken, ha ezt a beállítást a bővítmény használja.", + "title": "Gazdahálózat" + }, + "host_pid": { + "description": "Általában a kiegészítő futtatásának folyamatait elkülönítik az összes többi rendszerfolyamattól. A kiegészítő szerzője azt kérte, hogy a kiegészítő hozzáférjen a gazda rendszerpéldányon futó rendszerfolyamatokhoz, és engedélyezze a kiegészítő számára a folyamatok futtatását a fogadó rendszeren is. Ez a mód teljes hozzáférést és vezérlést biztosít a kiegészítőnek az egész Home Assistant rendszerhez, ami biztonsági kockázatokat jelent, és visszaélés esetén károsíthatja a rendszert. Ezért ez a szolgáltatás negatívan befolyásolja a Home assistant biztonságát.\n\nEzt a hozzáférési szintet a program nem kapja meg automatikusan, ezt Önnek kell megerősítenie. Ehhez manuálisan le kell tiltania a kiegészítő védelmi módját. Csak akkor tiltsa le a védelmi módot, ha tudja, szükség van ÉS megbízik a kiegészítő forrásában." }, "label": { "apparmor": "apparmor", @@ -161,6 +175,9 @@ "rating": "értékelés", "stage": "szakasz" }, + "rating": { + "title": "Kiegészítő biztonsági besorolása" + }, "role": { "admin": "admin", "backup": "biztonsági mentés", @@ -176,6 +193,7 @@ "cpu_usage": "Bővítmény CPU-használat", "hostname": "Gazdagép neve", "install": "telepítés", + "new_update_available": "{name} {version} elérhető", "not_available_version": "A(z) {core_version_installed} otthoni segédet futtatja, hogy frissítse az Otthoni segéd legalább {core_version_needed} verzióját.", "open_web_ui": "Webes felhasználói felület megnyitása", "option": { @@ -198,7 +216,13 @@ "title": "Watchdog" } }, + "protection_mode": { + "content": "A kiegészítő védelmi módja le van tiltva! Ez a kiegészítő számára teljes hozzáférést biztosít a teljes rendszerhez, ami növeli a biztonsági kockázatokat, és helytelen használat esetén károsíthatja a rendszert. Csak akkor tiltsa le a védelmi módot, ha tudja, szükség van ÉS megbízik a kiegészítő forrásában.", + "enable": "Védelmi mód engedélyezése", + "title": "Figyelem: A védelmi mód ki van kapcsolva!" + }, "ram_usage": "Bővítmény RAM-használat", + "rebuild": "Újjraépít", "restart": "újraindítás", "start": "indítás", "stop": "leállítás", @@ -276,6 +300,14 @@ "no_addons": "Még nincs telepítve egyetlen bővítmény sem. A kezdéshez menjen át a bővítmény boltba!" }, "dialog": { + "hardware": { + "attributes": "Attribútumok", + "device_path": "Eszköz útvonala", + "id": "ID", + "search": "Hardver keresése", + "subsystem": "Alrendszer", + "title": "Hardver" + }, "network": { "connected_to": "Csatlakozva a következőhöz: {ssid}", "dhcp": "DHCP", @@ -293,7 +325,11 @@ "wpa": "wpa-psk" }, "registries": { + "add_new_registry": "Hozzáadás új rendszerleíró adatbázishoz", + "add_registry": "Hozzáadás a rendszerleíró adatbázishoz", + "failed_to_add": "Nem sikerült hozzáadni a rendszerleíró adatbázishoz", "password": "Jelszó", + "registry": "Regisztrálás", "remove": "Eltávolítás", "username": "Felhasználónév" }, @@ -315,6 +351,8 @@ "my": { "error": "Ismeretlen hiba történt", "error_addon_not_found": "A bővítmény nem található", + "error_addon_not_installed": "A kért kiegészítő nincs telepítve. Kérjük, először telepítse", + "error_addon_not_started": "A kért bővítmény nem fut. Kérjük, először indítsa el", "faq_link": "My Home Assistant GYIK" }, "panel": { @@ -326,13 +364,19 @@ "snapshot": { "addons": "Bővítmények", "available_snapshots": "Rendelkezésreálló pillanatképek", + "confirm_password": "Pillanatkép jelszó megerősítése", "could_not_create": "Nem lehet pillanatképet létrehozni", "create": "Létrehozás", "create_blocked_not_running": "Jelenleg nem lehet pillanatképet létrehozni, mivel a rendszer {state} állapotban van.", "create_snapshot": "Pillanatkép létrehozása", + "created": "Létrehozva", + "delete_selected": "A kijelölt pillanatképek törlése", "delete_snapshot_confirm": "törlés", + "delete_snapshot_text": "Törölni szeretné a {szám} {szám, többes szám,\n egy {pillanatkép}\n egyéb {pillanatképek}\n}?", + "delete_snapshot_title": "Pillanatkép törlése", "description": "A pillanatképekkel könnyen hozhatsz létre vagy tölthetsz vissza mentést a teljes Home Assistant példányodról.", "enter_password": "Add meg a jelszót", + "failed_to_delete": "Nem sikerült törölni", "folder": { "addons/local": "Helyi bővítmények", "homeassistant": "Home Assistant konfiguráció", @@ -348,7 +392,10 @@ "password": "Pillanatkép jelszava", "password_protected": "jelszóval védett", "password_protection": "Jelszóvédelem", + "passwords_not_matching": "A jelszavak nem egyeznek", "security": "Biztonság", + "select_type": "Válassza ki, hogy mit szeretne visszaállítani", + "selected": "{number} kiválasztva", "type": "Pillanatkép típusa", "upload_snapshot": "Pillanatkép feltöltése" }, @@ -384,7 +431,8 @@ "used_space": "Felhasznált terület" }, "log": { - "get_logs": "Nem sikerült lekérni a(z) {provider} naplókat, {error}" + "get_logs": "Nem sikerült lekérni a(z) {provider} naplókat, {error}", + "log_provider": "Naplószolgáltató" }, "supervisor": { "beta_backup": "A szolgáltatás aktiválása előtt győződj meg arról, hogy rendelkezel biztonsági másolattal az adatokról.", @@ -401,6 +449,7 @@ "leave_beta_description": "Stabil frissítések a Home Assistanthoz, a Supervisorhoz és a gazdagéphez", "ram_usage": "Supervisor RAM használat", "reload_supervisor": "Supervisor újratöltése", + "search": "Keresés", "share_diagnostics": "Diagnosztika megosztása", "share_diagnostics_description": "Összeomlási jelentések és diagnosztikai információk megosztása.", "share_diagonstics_title": "Segíts a Home Assistant fejlesztésében", @@ -412,6 +461,7 @@ }, "unhealthy_title": "A telepítés nem megfelelő", "unsupported_reason": { + "apparmor": "Az AppArmor nincs engedélyezve a gazdagépen", "container": "Konténerek, amelyekről ismert, hogy problémákat okoznak", "dbus": "DBUS", "docker_configuration": "Docker konfiguráció", @@ -496,8 +546,11 @@ }, "light": { "brightness": "Fényerő", + "cold_white_value": "Hideg fehér fény", + "color_brightness": "Színes fény", "color_temperature": "Színhőmérséklet", "effect": "Hatás", + "warm_white_value": "Meleg fehér fény", "white_value": "Fehér fényerő" }, "lock": { @@ -624,6 +677,9 @@ "addon-picker": { "addon": "Bővítmény", "error": { + "fetch_addons": { + "title": "Hiba történt a bővítmények beolvasása közben" + }, "no_supervisor": { "title": "Nincs Supervisor" } @@ -657,6 +713,9 @@ "today": "Ma" }, "data-table": { + "clear": "Tiszta", + "filtering_by": "Szűrés", + "hidden": "{number} rejtve", "no-data": "Nincs adat", "search": "Keresés" }, @@ -720,7 +779,9 @@ "was_unlocked": "fel lett oldva", "was_unplugged": "ki lett húzva", "was_unsafe": "nem volt biztonságos" - } + }, + "retrieval_error": "Hiba a naplóbejegyzés beolvasása során", + "show_trace": "Nyomkövetés megjelenítése" }, "media-browser": { "audio_not_supported": "A böngésződ nem támogatja az audio elemet.", @@ -769,6 +830,14 @@ "label": "Kép", "unsupported_format": "Nem támogatott formátum, válassz JPEG, PNG vagy GIF képet." }, + "related-filter-menu": { + "filter_by_area": "Szűrés terület szerint", + "filter_by_device": "Szűrés eszköz szerint", + "filter_by_entity": "Szűrés entitás szerint", + "filtered_by_area": "terület: {area_name}", + "filtered_by_device": "eszköz: {device_name}", + "filtered_by_entity": "entitás: {entity_name}" + }, "related-items": { "area": "Terület", "automation": "A következő automatizálások része", @@ -835,6 +904,8 @@ "config_entry_system_options": { "enable_new_entities_description": "Ha le van tiltva, akkor az újonnan felfedezett {integration} entitások nem lesznek automatikusan hozzáadva a Home Assistant-hoz.", "enable_new_entities_label": "Újonnan hozzáadott entitások engedélyezése.", + "enable_polling_label": "A frissítések lekérdezésének engedélyezése.", + "restart_home_assistant": "A módosítások életbe lépéséhez újra kell indítania a Home Assistant alkalmazást.", "title": "{integration} rendszerbeállításai", "update": "Frissítés" }, @@ -844,6 +915,7 @@ }, "entity_registry": { "control": "Ellenőrzés", + "customize_link": "entitás testreszabása", "dismiss": "Elvetés", "editor": { "advanced": "Haladó beállítások", @@ -1060,6 +1132,11 @@ "perform_action": "{action} szerver", "restart": "Újraindítás", "stop": "Leállítás" + }, + "types": { + "navigation": "Navigál", + "reload": "Újratöltés", + "server_control": "Szerver" } }, "filter_placeholder": "Entitásszűrő" @@ -1076,6 +1153,7 @@ "buttons": { "add": "Eszközök hozzáadása ezen az eszközön keresztül", "clusters": "Klaszterek Kezelése", + "device_children": "Aleszközök megtekintése", "reconfigure": "Eszköz újrakonfigurálása", "remove": "Eszköz eltávolítása", "view_in_visualization": "Megtekintés a Vizualizációban", @@ -1084,6 +1162,7 @@ "confirmations": { "remove": "Biztosan el szeretnéd távolítani az eszközt?" }, + "device_children": "Zigbee aleszköz", "device_signature": "Zigbee eszköz aláírása", "last_seen": "Utolsó jelentés", "manuf": "{manufacturer} által", @@ -1100,6 +1179,21 @@ "zha_device_card": { "device_name_placeholder": "Eszköznév módosítása" } + }, + "zha_reconfigure_device": { + "attribute": "Attribútum", + "bind_header": "Kötés", + "button_hide": "Részletek elrejtése", + "button_show": "Részletek megjelenítése", + "cluster_header": "Klaszter", + "configuration_complete": "Az eszköz újrakonfigurálása befejeződött.", + "configuration_failed": "Az eszköz újrakonfigurálása nem sikerült. További információk elérhetők a naplókban.", + "configuring_alt": "Konfigurálás", + "heading": "Eszköz újrakonfigurálása", + "in_progress": "Az eszköz újrakonfigurálása folyamatban van. Ez eltarthat egy ideig.", + "min_max_change": "min/max/változás", + "reporting_header": "Jelentés", + "start_reconfiguration": "Újrakonfigurálás indítása" } }, "duration": { @@ -1118,6 +1212,10 @@ "key_missing": "A (z) \" {key}\" szükséges kulcs hiányzik.", "key_not_expected": "A(z) \"{key}\" kulcs nem várt, vagy a vizuális szerkesztő nem támogatja.", "no_type_provided": "Nincs megadva típus." + }, + "supervisor": { + "reboot": "Próbálja újraindítani a gazdagépet", + "system_health": "Rendszerállapot ellenőrzése" } }, "login-form": { @@ -1135,10 +1233,12 @@ "notification_toast": { "connection_lost": "A kapcsolat megszakadt. Újracsatlakozás…", "dismiss": "Elvetés", + "integration_starting": "{integration} indítása folyamatban van, nem lesz elérhető, amíg ez be nem fejeződik.", "service_call_failed": "Nem sikerült meghívni a(z) {service} szolgáltatást.", "started": "A Home Assistant indítása befejeződött!", "starting": "A Home Assistant indítása folyamatban van. Nem lesz minden elérhető, amíg ez be nem fejeződik.", - "triggered": "Aktiválva {name}" + "triggered": "Aktiválva {name}", + "wrapping_up_startup": "Az indítás folyamatban. A folyamat befejezéséig nem minden lesz elérhető." }, "panel": { "config": { @@ -1150,7 +1250,8 @@ "caption": "Területek", "data_table": { "area": "Terület", - "devices": "Eszközök" + "devices": "Eszközök", + "entities": "Entitások" }, "delete": { "confirmation_text": "Minden ebben a területben lévő eszköz hozzárendelés nélküli lesz.", @@ -1227,6 +1328,7 @@ "extra_fields": { "brightness_pct": "Fényerő", "code": "Kód", + "flash": "Villogás", "humidity": "Páratartalom", "message": "Üzenet", "mode": "Üzemmód", @@ -1392,6 +1494,7 @@ "move_down": "Le", "move_up": "Fel", "save": "Mentés", + "show_trace": "Nyomkövetés megjelenítése", "triggers": { "add": "Eseményindító hozzáadása", "delete": "Törlés", @@ -1500,6 +1603,7 @@ "add_automation": "Automatizálás hozzáadása", "delete_automation": "Automatizálás törlése", "delete_confirm": "Biztosan törölni szeretnéd ezt az automatizálást?", + "dev_automation": "Hibakeresési automatizálás", "duplicate": "Duplikálás", "duplicate_automation": "Automatizálás duplikálása", "edit_automation": "Automatizálás szerkesztése", @@ -1599,6 +1703,7 @@ "info": "A Google Asszisztens integrációval a Home Assistant Felhő lehetőséget nyújt minden Home Assistant eszköz vezérlésére bármely Google Asszisztens képes eszközzel.", "info_state_reporting": "Ha engedélyezed az állapotjelentést, akkor a Home Assistant minden állapotváltozást el fog küldeni a feltárt entitásokról a Google-nak. Ez lehetővé teszi, hogy mindig láthasd a legfrissebb állapotokat a Google alkalmazásban.", "manage_entities": "Entitások kezelése", + "not_configured_title": "A Google Assistant nincs aktiválva", "security_devices": "Biztonsági eszközök", "sync_entities": "Entitások szinkronizálása a Google-lal", "sync_entities_404_message": "Nem sikerült szinkronizálni az entitásokat a Google-lal. A szinkronizáláshoz kérd meg a Google-t a következőre: \"Hey Google, sync my devices\"", @@ -1614,10 +1719,15 @@ "remote": { "access_is_being_prepared": "A távoli hozzáférés előkészítése folyamatban van. Értesíteni fogunk, ha készen áll.", "certificate_info": "Tanúsítvány infó", + "connected": "Csatlakoztatva", "info": "A Home Assistant Felhő biztonságos távoli kapcsolatot nyújt a példányodhoz, miközben távol vagy.", "instance_is_available": "A példányod itt elérhető:", "instance_will_be_available": "A példányod itt lesz elérhető:", "link_learn_how_it_works": "Tudd meg, hogyan működik", + "not_connected": "Nincs csatlakoztatva", + "remote_enabled": { + "caption": "Automatikus csatlakozás" + }, "title": "Távoli vezérlés" }, "sign_out": "Kijelentkezés", @@ -1631,6 +1741,9 @@ "target": "Cél", "target_browser": "Böngésző" }, + "female": "Nő", + "male": "Férfi", + "title": "Szövegről beszédre", "try": "Próbálja meg" }, "webhooks": { @@ -1757,6 +1870,30 @@ "description": "Egységrendszer, hely, időzóna és egyéb általános paraméterek", "section": { "core": { + "analytics": { + "header": "Analitika", + "instance_id": "Példányazonosító: {huuid}", + "preference": { + "base": { + "description": "Példányazonosító, verzió és telepítési típus.", + "title": "Alapvető elemzés" + }, + "diagnostics": { + "title": "Diagnosztika" + }, + "statistics": { + "title": "Felhasználási statisztikák" + }, + "usage_supervisor": { + "description": "Nevek, verziók és képességek.", + "title": "Használt integrációk és kiegészítők" + }, + "usage": { + "description": "Nevek és verzióinformációk.", + "title": "Használt integrációk" + } + } + }, "core_config": { "edit_requires_storage": "A szerkesztő le van tiltva, mert a konfiguráció a configuration.yaml fájlban van tárolva.", "elevation": "Magasság", @@ -1886,7 +2023,8 @@ "scripts": "Szkriptek", "unknown_error": "Ismeretlen hiba", "unnamed_device": "Névtelen eszköz", - "update": "Frissítés" + "update": "Frissítés", + "update_device_error": "A készülék frissítése sikertelen" }, "entities": { "caption": "Entitások", @@ -1943,6 +2081,9 @@ "filtering_by": "Szűrés", "show": "Megmutat" }, + "hassio": { + "button": "Konfigurál" + }, "header": "Home Assistant beállítása", "helpers": { "caption": "Segítők", @@ -1990,6 +2131,7 @@ "license": "Megjelent az Apache 2.0 licenc alatt", "path_configuration": "A configuration.yaml fájl elérési útja: {path}", "server": "server", + "setup_time": "Beállítási idő", "source": "Forrás:", "system_health_error": "A rendszerállapot összetevő nincs betöltve. Add hozzá a 'system_health:' sort a configuration.yaml fájlhoz.", "system_health": { @@ -2008,10 +2150,13 @@ "caption": "Integrációk", "config_entry": { "area": "Terület: {area}", + "check_the_logs": "Ellenőrizze a naplókat", + "configure": "Konfigurál", "delete": "Törlés", "delete_confirm": "Biztosan törölni szeretnéd ezt az integrációt?", "device_unavailable": "Eszköz nem érhető el", "devices": "{count} {count, plural,\n one {eszköz}\n other {eszköz}\n}", + "disable_error": "Az integráció engedélyezése vagy letiltása sikertelen volt", "disable_restart_confirm": "Indítsa újra a Home Assistant programot az integráció lekapcsolásának befejezéséhez", "disable": { "disable_confirm": "Biztosan letiltja ezt a konfigurációs bejegyzést? Eszközeit és entitásait letiltjuk.", @@ -2023,14 +2168,17 @@ }, "disabled_cause": "Letiltva ez által: {cause}" }, + "disabled_polling": "A frissített adatok automatikus lekérdezése le van tiltva", "documentation": "Dokumentáció", "enable_restart_confirm": "Indítsa újra a Home Assistant programot az integráció bekapcsolásának befejezéséhez", "entities": "{count} {count, plural,\n one {entitás}\n other {entitás}\n}", "entity_unavailable": "Entitás nem érhető el", "firmware": "Firmware: {version}", "hub": "Kapcsolódva", + "logs": "naplók", "manuf": "{manufacturer} által", "no_area": "Nincs Terület", + "not_loaded": "Nincs betöltve", "options": "Opciók", "reload": "Újratöltés", "reload_confirm": "Az integráció újra lett töltve", @@ -2038,6 +2186,11 @@ "rename": "Átnevezés", "restart_confirm": "Indítsd újra a Home Assistant-ot az integráció törlésének befejezéséhez", "services": "{count} {count, plural,\n one {szolgáltatás}\n other {szolgáltatás}\n}", + "state": { + "loaded": "Betöltve", + "not_loaded": "Nincs betöltve", + "setup_error": "Nem sikerült beállítani" + }, "system_options": "Rendszerbeállítások", "unnamed_entry": "Névtelen bejegyzés" }, @@ -2057,6 +2210,7 @@ "loading_first_time": "Kérlek várj, amíg az integráció telepítésre kerül", "next": "Következő", "not_all_required_fields": "Nincs kitöltve minden szükséges mező.", + "not_loaded": "Az integrációt nem sikerült betölteni. Próbálja meg újraindítani a Home Assistantot.", "pick_flow_step": { "title": "Felfedeztük ezeket, be akarod állítani őket?" }, @@ -2070,6 +2224,7 @@ "disable": { "disabled_integrations": "{number} letiltva", "hide_disabled": "A letiltott integrációk elrejtése", + "show": "Mutat", "show_disabled": "A letiltott integrációk megjelenítése" }, "discovered": "Felfedezett", @@ -2103,8 +2258,16 @@ "logs": { "caption": "Napló", "clear": "Törlés", + "custom_integration": "egyedi integráció", "description": "A Home Assistant naplófájlok megtekintése", "details": "Naplóbejegyzés részletei ({level})", + "level": { + "critical": "KRITIKUS HIBA", + "debug": "DEBUG", + "error": "HIBA", + "info": "INFÓ", + "warning": "FIGYELMEZTETÉS" + }, "load_full_log": "Teljes Home Assistant napló betöltése", "loading_log": "Hibanapló betöltése...", "multiple_messages": "az üzenet először a következő időpontban fordult elő: {time}, majd később {counter} alkalommal ismétlődött", @@ -2382,6 +2545,8 @@ "add_scene": "Jelenet hozzáadása", "delete_confirm": "Biztosan törölni szeretnéd ezt a jelenetet?", "delete_scene": "Jelenet törlése", + "duplicate": "Másolás", + "duplicate_scene": "Jelenet duplikálása", "edit_scene": "Jelenet szerkesztése", "header": "Jelenet szerkesztő", "headers": { @@ -2703,24 +2868,41 @@ }, "zwave_js": { "add_node": { + "inclusion_finished": "A csomópont hozzá lett adva.", + "title": "Adjon hozzá egy Z-Wave csomópontot", "view_device": "Eszköz megtekintése" }, "button": "Konfigurálja", "common": { "add_node": "Node hozzáadása", "close": "Bezárás", + "home_id": "Otthon azonosító", "network": "Hálózat", "node_id": "Node azonosító", + "reconfigure_server": "Kiszolgáló újrakonfigurálása", "remove_node": "Node eltávolítása" }, "dashboard": { + "driver_version": "Illesztőprogram verzió", "dump_not_ready_confirm": "Letöltés", + "header": "Kezelje Z-Wave hálózatát", + "home_id": "Otthon azonosító", + "nodes_ready": "Csomópontok készen állnak", "server_version": "Szerver verzió" }, "device_info": { - "device_config": "Eszköz beállítása" + "device_config": "Eszköz beállítása", + "node_ready": "Csomópont készen áll", + "node_status": "Csomópont állapota", + "zwave_info": "Z-Wave infó" + }, + "logs": { + "log_level": "Naplószint", + "log_level_changed": "A naplószint megváltozott erre: {level}", + "title": "Z-Wave JS naplók" }, "navigation": { + "logs": "Naplók", "network": "Hálózat" }, "network_status": { @@ -2732,10 +2914,21 @@ "error_device_not_found": "Az eszköz nem található", "header": "Z-Wave eszköz konfigurálása", "parameter_is_read_only": "Ez a paraméter csak olvasható", - "set_param_error": "Hiba történt." + "set_param_accepted": "A paraméter frissült.", + "set_param_error": "Hiba történt.", + "zwave_js_device_database": "Z-Wave JS eszközadatbázis" }, "node_status": { + "alive": "Él", + "asleep": "Alszik", + "awake": "Ébren", + "dead": "Halott", "unknown": "Ismeretlen" + }, + "remove_node": { + "cancel_exclusion": "A kizárás megszakítása", + "start_exclusion": "Kizárás indítása", + "title": "Z-Wave csomópont eltávolítása" } }, "zwave": { @@ -2942,7 +3135,11 @@ "cards": { "actions": { "action_confirmation": "Biztosan futtatod a(z) \"{action}\" műveletet?", - "no_service": "Nincs megadva futtatandó szolgáltatás" + "no_entity_more_info": "A további információkhoz nincs megadva entitás", + "no_entity_toggle": "A váltáshoz nincs megadva entitás", + "no_navigation_path": "Nincs megadva navigációs útvonal", + "no_service": "Nincs megadva futtatandó szolgáltatás", + "no_url": "Nincs megadva megnyitandó URL" }, "confirm_delete": "Biztosan törölni szeretnéd ezt a kártyát?", "empty_state": { @@ -3554,6 +3751,9 @@ } }, "page-onboarding": { + "analytics": { + "finish": "Következő" + }, "core-config": { "button_detect": "Észlelés", "finish": "Tovább", @@ -3563,17 +3763,28 @@ "location_name": "A Home Assistant rendszered neve", "location_name_default": "Otthon" }, + "finish": "Befejezés", "integration": { "finish": "Befejezés", "intro": "Az eszközöket és szolgáltatásokat a Home Assistant integrációként kezeli. Beállíthatod őket most, vagy később a konfigurációs képernyőn.", "more_integrations": "Több" }, "intro": "Készen állsz arra, hogy felébreszd az otthonod, visszaszerezd a magánéleted és csatlakozz egy világhálós közösséghez?", + "next": "Következő", "restore": { + "addons": "Kiegészítők", + "confirm_password": "Erősítse meg a Pillanatkép jelszavát", "description": "Alternatív megoldásként visszaállíthatsz egy korábbi pillanatképet.", + "folders": "Mappák", + "full_snapshot": "Teljes pillanatkép", "hide_log": "Teljes napló elrejtése", "in_progress": "Visszaállítás folyamatban", - "show_log": "Teljes napló megjelenítése" + "partial_snapshot": "Részleges pillanatkép", + "password": "Snapshot jelszó", + "password_protection": "Jelszóvédelem", + "select_type": "Válassza ki a visszaállítandó elemeket", + "show_log": "Teljes napló megjelenítése", + "type": "Pillanatkép típus" }, "user": { "create_account": "Fiók Létrehozása", @@ -3663,6 +3874,18 @@ "enable": "Engedélyez", "header": "Többfaktoros Hitelesítési Modulok" }, + "number_format": { + "dropdown_label": "Számformátum", + "formats": { + "comma_decimal": "1 234 567,89", + "decimal_comma": "1.234.567,89", + "language": "Automatikus (nyelvi beállítás használata)", + "none": "Nincs", + "space_comma": "1 234 567,89", + "system": "Használja a rendszer területi beállításait" + }, + "header": "Számformátum" + }, "push_notifications": { "add_device_prompt": { "input_label": "Eszköz neve", From 08de941c902d5c482b36bf4700ed38159ce7a86e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 29 Jun 2021 00:47:16 +0000 Subject: [PATCH 55/73] Translation update --- translations/frontend/ja.json | 12 +++++++++++- translations/frontend/pl.json | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/translations/frontend/ja.json b/translations/frontend/ja.json index aae44f3386..a1c7643e4e 100644 --- a/translations/frontend/ja.json +++ b/translations/frontend/ja.json @@ -862,6 +862,12 @@ "label": "画像", "unsupported_format": "サポートされていない形式です。JPEG、PNG、またはGIF画像を選択してください。" }, + "related-filter-menu": { + "filter_by_area": "エリアで絞り込む", + "filter_by_device": "デバイスで絞り込む", + "filtered_by_area": "エリア: {area_name}", + "filtered_by_device": "デバイス: {device_name}" + }, "related-items": { "area": "エリア", "automation": "次の自動化の一部", @@ -1164,7 +1170,8 @@ }, "types": { "navigation": "ナビゲート", - "reload": "リロード" + "reload": "リロード", + "server_control": "サーバー" } }, "filter_placeholder": "エンティティフィルター" @@ -2203,6 +2210,7 @@ "configure": "設定", "delete": "削除", "delete_confirm": "この統合を削除しますか?", + "depends_on_cloud": "クラウドに依存", "device_unavailable": "デバイスを利用できません", "devices": "{count} {count, plural,\n one {デバイス}\n other {デバイス}\n}", "disable_error": "統合の有効化または無効化に失敗しました", @@ -2241,6 +2249,7 @@ "loaded": "読み込み", "migration_error": "移行エラー", "not_loaded": "読み込まれていません", + "setup_error": "セットアップに失敗しました。", "setup_retry": "設定をやり直す" }, "system_options": "システムオプション", @@ -3152,6 +3161,7 @@ "column_parameter": "パラメータ", "description": "サービス開発ツールを使用すると、ホームアシスタントで利用可能なサービスを呼び出すことができます。", "fill_example_data": "データ記入例", + "no_template_ui_support": "UIはテンプレートをサポートしていませんが、YAMLエディタを使用することができます。", "title": "サービス", "ui_mode": "UIモードに移動します", "yaml_mode": "YAMLモードに移動します", diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index 56f387bf39..53a5147026 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -2965,6 +2965,7 @@ "home_id": "Identyfikator domu", "network": "Sieć", "node_id": "Identyfikator węzła", + "reconfigure_server": "Ponownie skonfiguruj serwer", "remove_node": "Usuń węzeł" }, "dashboard": { From 0a83a704f1b40fc512fd143c0072c5a5f3917480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Tue, 29 Jun 2021 14:57:25 +0200 Subject: [PATCH 56/73] Ignore previous versions in add-on changelog (#9474) --- hassio/src/addon-view/info/hassio-addon-info.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts index 0fe37230bb..42b6969dbc 100644 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ b/hassio/src/addon-view/info/hassio-addon-info.ts @@ -892,10 +892,19 @@ class HassioAddonInfo extends LitElement { private async _openChangelog(): Promise { try { - const content = await fetchHassioAddonChangelog( - this.hass, - this.addon.slug - ); + let content = await fetchHassioAddonChangelog(this.hass, this.addon.slug); + if ( + content.includes(`# ${this.addon.version}`) && + content.includes(`# ${this.addon.version_latest}`) + ) { + const newcontent = content.split(`# ${this.addon.version}`)[0]; + if (newcontent.includes(`# ${this.addon.version_latest}`)) { + // Only change the content if the new version still exist + // if the changelog does not have the newests version on top + // this will not be true, and we don't modify the content + content = newcontent; + } + } showHassioMarkdownDialog(this, { title: this.supervisor.localize("addon.dashboard.changelog"), content, From 43503ba0858ebd06a66f3d4dd4f2875120278079 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 29 Jun 2021 14:57:39 +0200 Subject: [PATCH 57/73] Fix number entity row availability when state unknown (#9475) --- src/panels/lovelace/entity-rows/hui-number-entity-row.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/panels/lovelace/entity-rows/hui-number-entity-row.ts b/src/panels/lovelace/entity-rows/hui-number-entity-row.ts index 97360e0192..84fe752862 100644 --- a/src/panels/lovelace/entity-rows/hui-number-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-number-entity-row.ts @@ -11,7 +11,7 @@ import { customElement, property, state } from "lit/decorators"; import { computeStateDisplay } from "../../../common/entity/compute_state_display"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; import "../../../components/ha-slider"; -import { UNAVAILABLE_STATES } from "../../../data/entity"; +import { UNAVAILABLE } from "../../../data/entity"; import { setValue } from "../../../data/input_text"; import { HomeAssistant } from "../../../types"; import { hasConfigOrEntityChanged } from "../common/has-changed"; @@ -75,7 +75,7 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow { ? html`
Date: Tue, 29 Jun 2021 15:00:27 +0200 Subject: [PATCH 58/73] Fix integration card rename dialog logic (#9467) --- .../config/integrations/ha-integration-card.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index 85663de87d..6549558047 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -303,7 +303,7 @@ export class HaIntegrationCard extends LitElement { > - + ${this.hass.localize( "ui.panel.config.integrations.config_entry.rename" )} @@ -420,6 +420,15 @@ export class HaIntegrationCard extends LitElement { showOptionsFlowDialog(this, ev.target.closest("ha-card").configEntry); } + private _handleRename(ev: CustomEvent): void { + if (!shouldHandleRequestSelectedEvent(ev)) { + return; + } + this._editEntryName( + ((ev.target as HTMLElement).closest("ha-card") as any).configEntry + ); + } + private _handleReload(ev: CustomEvent): void { if (!shouldHandleRequestSelectedEvent(ev)) { return; @@ -578,8 +587,7 @@ export class HaIntegrationCard extends LitElement { }); } - private async _editEntryName(ev) { - const configEntry = ev.target.closest("ha-card").configEntry; + private async _editEntryName(configEntry: ConfigEntry) { const newName = await showPromptDialog(this, { title: this.hass.localize("ui.panel.config.integrations.rename_dialog"), defaultValue: configEntry.title, From 42606062675aefa310af0b60b0db01e4cf9bdbcc Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 29 Jun 2021 15:01:18 +0200 Subject: [PATCH 59/73] Set minimum = 1 hours to show (#9466) --- .../lovelace/editor/config-elements/hui-graph-footer-editor.ts | 1 + .../lovelace/editor/config-elements/hui-logbook-card-editor.ts | 1 + .../lovelace/editor/config-elements/hui-sensor-card-editor.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/src/panels/lovelace/editor/config-elements/hui-graph-footer-editor.ts b/src/panels/lovelace/editor/config-elements/hui-graph-footer-editor.ts index 65b591c164..88277bc588 100644 --- a/src/panels/lovelace/editor/config-elements/hui-graph-footer-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-graph-footer-editor.ts @@ -81,6 +81,7 @@ export class HuiGraphFooterEditor "ui.panel.lovelace.editor.card.config.optional" )})" .value=${this._hours_to_show} + min="1" .configValue=${"hours_to_show"} @value-changed=${this._valueChanged} > diff --git a/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts index ae710c5dbf..83f99d944b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts @@ -85,6 +85,7 @@ export class HuiLogbookCardEditor "ui.panel.lovelace.editor.card.config.optional" )})" .value=${this._hours_to_show} + min="1" .configValue=${"hours_to_show"} @value-changed=${this._valueChanged} > diff --git a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts index 3f707cc1fe..c39f907677 100644 --- a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts @@ -177,6 +177,7 @@ export class HuiSensorCardEditor )})" type="number" .value=${this._hours_to_show} + min="1" .configValue=${"hours_to_show"} @value-changed=${this._valueChanged} > From ba0be927ed4d0e19dd40f58d3a27ca970b00aafe Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 29 Jun 2021 15:01:42 +0200 Subject: [PATCH 60/73] Set min value for history graph card rendered hours (#9464) --- .../editor/config-elements/hui-history-graph-card-editor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/panels/lovelace/editor/config-elements/hui-history-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-history-graph-card-editor.ts index 6f07551a19..766fda9dd5 100644 --- a/src/panels/lovelace/editor/config-elements/hui-history-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-history-graph-card-editor.ts @@ -79,6 +79,7 @@ export class HuiHistoryGraphCardEditor "ui.panel.lovelace.editor.card.config.optional" )})" .value="${this._hours_to_show}" + min="1" .configValue=${"hours_to_show"} @value-changed="${this._valueChanged}" > From a3d1a3566ddefc2b2df4baf975a1f22f5c132760 Mon Sep 17 00:00:00 2001 From: uvjustin <46082645+uvjustin@users.noreply.github.com> Date: Tue, 29 Jun 2021 21:44:18 +0800 Subject: [PATCH 61/73] Fix ha-hls-player cleanup for lit 2 (#9388) Co-authored-by: Bram Kragten --- src/components/ha-hls-player.ts | 50 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/components/ha-hls-player.ts b/src/components/ha-hls-player.ts index 6120e5aa91..17d3157884 100644 --- a/src/components/ha-hls-player.ts +++ b/src/components/ha-hls-player.ts @@ -7,7 +7,7 @@ import { PropertyValues, TemplateResult, } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { nextRender } from "../common/util/render-status"; import { getExternalConfig } from "../external_app/external_config"; @@ -42,27 +42,23 @@ class HaHLSPlayer extends LitElement { // don't cache this, as we remove it on disconnects @query("video") private _videoEl!: HTMLVideoElement; - @state() private _attached = false; - private _hlsPolyfillInstance?: HlsLite; - private _useExoPlayer = false; + private _exoPlayer = false; public connectedCallback() { super.connectedCallback(); - this._attached = true; + if (this.hasUpdated) { + this._startHls(); + } } public disconnectedCallback() { super.disconnectedCallback(); - this._attached = false; + this._cleanUp(); } protected render(): TemplateResult { - if (!this._attached) { - return html``; - } - return html`
- ${this.showAdvanced - ? html` -

- ${this.hass.localize( - "ui.panel.config.integrations.note_about_integrations" - )}
- ${this.hass.localize( - "ui.panel.config.integrations.note_about_website_reference" - )}${this.hass.localize( - "ui.panel.config.integrations.home_assistant_website" - )}. -

- ` - : ""} `; } @@ -193,9 +193,6 @@ class StepFlowPickHandler extends LitElement { div { max-height: calc(100vh - 134px); } - div.advanced { - max-height: calc(100vh - 250px); - } } paper-icon-item { cursor: pointer; diff --git a/src/translations/en.json b/src/translations/en.json index dfb95a0586..c5bc152a6a 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2121,7 +2121,7 @@ "confirm_new": "Do you want to set up {integration}?", "add_integration": "Add integration", "no_integrations": "Seems like you don't have any integrations configured yet. Click on the button below to add your first integration!", - "note_about_integrations": "Not all integrations can be configured via the UI yet.", + "note_about_integrations": "No integrations matched your search, the integration you want to set up might not be available to set up via the UI yet.", "note_about_website_reference": "More are available on the ", "home_assistant_website": "Home Assistant website", "configure": "Configure", From ed4052365cc5887467edddeec6be55159c277926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Wed, 30 Jun 2021 01:09:18 +0200 Subject: [PATCH 67/73] Allow placeholders in config and option flows (#9314) --- src/dialogs/config-flow/show-dialog-config-flow.ts | 5 ++++- src/dialogs/config-flow/show-dialog-options-flow.ts | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dialogs/config-flow/show-dialog-config-flow.ts b/src/dialogs/config-flow/show-dialog-config-flow.ts index fc49d0bf1f..86cf77be2d 100644 --- a/src/dialogs/config-flow/show-dialog-config-flow.ts +++ b/src/dialogs/config-flow/show-dialog-config-flow.ts @@ -90,7 +90,10 @@ export const showConfigFlowDialog = ( }, renderShowFormStepFieldError(hass, step, error) { - return hass.localize(`component.${step.handler}.config.error.${error}`); + return hass.localize( + `component.${step.handler}.config.error.${error}`, + step.description_placeholders + ); }, renderExternalStepHeader(hass, step) { diff --git a/src/dialogs/config-flow/show-dialog-options-flow.ts b/src/dialogs/config-flow/show-dialog-options-flow.ts index 536ead8026..dc508ee30e 100644 --- a/src/dialogs/config-flow/show-dialog-options-flow.ts +++ b/src/dialogs/config-flow/show-dialog-options-flow.ts @@ -88,9 +88,10 @@ export const showOptionsFlowDialog = ( ); }, - renderShowFormStepFieldError(hass, _step, error) { + renderShowFormStepFieldError(hass, step, error) { return hass.localize( - `component.${configEntry.domain}.options.error.${error}` + `component.${configEntry.domain}.options.error.${error}`, + step.description_placeholders ); }, From 9594c8106e531314e0c5e04d27acbacb51dcdb69 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 30 Jun 2021 00:47:15 +0000 Subject: [PATCH 68/73] Translation update --- translations/frontend/en.json | 15 ++++++++++++++- translations/frontend/es.json | 13 +++++++++++++ translations/frontend/et.json | 13 +++++++++++++ translations/frontend/ru.json | 17 +++++++++++++++-- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/translations/frontend/en.json b/translations/frontend/en.json index c105428f82..dda85e0b25 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -2319,7 +2319,7 @@ "none": "Nothing configured yet", "none_found": "No integrations found", "none_found_detail": "Adjust your search criteria.", - "note_about_integrations": "Not all integrations can be configured via the UI yet.", + "note_about_integrations": "No integrations matched your search, the integration you want to set up might not be available to set up via the UI yet.", "note_about_website_reference": "More are available on the ", "reconfigure": "Reconfigure", "rename_dialog": "Edit the name of this config entry", @@ -2962,6 +2962,7 @@ "common": { "add_node": "Add Node", "close": "Close", + "heal_network": "Heal Network", "home_id": "Home ID", "network": "Network", "node_id": "Node ID", @@ -2988,6 +2989,18 @@ "node_status": "Node Status", "zwave_info": "Z-Wave Info" }, + "heal_network": { + "healing_cancelled": "Network healing has been cancelled.", + "healing_complete": "Network healing is complete.", + "healing_failed": "Healing failed. Additional information may be available in the logs.", + "in_progress": "Network healing is in progress. This will take some time.", + "introduction": "Start a network heal on your Z-Wave network. A network heal will cause all devices to re-calculate their routes back to the controller and is recommended if you have recently moved devices or your controller.", + "run_in_background": "You can close this dialog and the network healing will continue in the background.", + "start_heal": "Start Healing", + "stop_heal": "Stop Healing", + "title": "Heal your Z-Wave Network", + "traffic_warning": "The healing process generates a large amount of traffic on the Z-Wave network. This may cause devices to respond slowly (or not at all) while the heal is in progress." + }, "logs": { "log_level": "Log Level", "log_level_changed": "Log Level changed to: {level}", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index cacfdbf8ea..946be9169b 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -2962,6 +2962,7 @@ "common": { "add_node": "Añadir Nodo", "close": "Cerrar", + "heal_network": "Sanar red", "home_id": "ID de casa", "network": "Red", "node_id": "ID del Nodo", @@ -2988,6 +2989,18 @@ "node_status": "Estado del Nodo", "zwave_info": "Información de Z-Wave" }, + "heal_network": { + "healing_cancelled": "Se ha cancelado la curación en red.", + "healing_complete": "La curación de la red se ha completado.", + "healing_failed": "La curación falló. Puede haber información adicional disponible en los registros.", + "in_progress": "La curación de la red está en curso. Esto llevará algún tiempo.", + "introduction": "Inicia una cura de red en tu red Z-Wave. Una curación de la red hará que todos los dispositivos vuelvan a calcular sus rutas de regreso al controlador y se recomienda si has movido dispositivos o tu controlador recientemente.", + "run_in_background": "Puedes cerrar este cuadro de diálogo y la curación de la red continuará en segundo plano.", + "start_heal": "Iniciar la curación", + "stop_heal": "Detener la curación", + "title": "Sana tu red Z-Wave", + "traffic_warning": "El proceso de curación genera una gran cantidad de tráfico en la red Z-Wave. Esto puede hacer que los dispositivos respondan lentamente (o no respondan en absoluto) mientras la curación está en curso." + }, "logs": { "log_level": "Nivel de registro", "log_level_changed": "Nivel de registro cambiado a: {level}", diff --git a/translations/frontend/et.json b/translations/frontend/et.json index 2f47fa463a..f3e6c180cf 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -2962,6 +2962,7 @@ "common": { "add_node": "Lisa sõlm", "close": "Sulge", + "heal_network": "Paranda võrgustikku", "home_id": "Kodu ID", "network": "Võrk", "node_id": "Sõlme ID", @@ -2988,6 +2989,18 @@ "node_status": "Sõlme olek", "zwave_info": "Z-Wave teave" }, + "heal_network": { + "healing_cancelled": "Võrgu parandamine on tühistatud.", + "healing_complete": "Võrgu parandamine on lõpule viidud.", + "healing_failed": "Parandamine nurjus. Lisateave võib olla saadaval logides.", + "in_progress": "Võrgu parandamine on pooleli. See võtab aega.", + "introduction": "Alusta oma Z-Wave võrgu parandamist. Võrgu parandamine põhjustab kõigi seadmete marsruudi kontrollerisse tagasi arvutamise ja on soovitatav, kui oled hiljuti seadmeid või oma kontrollerit teisaldanud.", + "run_in_background": "Saad selle dialoogi sulgeda ja võrgu parandamine jätkub taustal.", + "start_heal": "Alusta parandamist", + "stop_heal": "Peata parandamine", + "title": "Paranda oma Z-Wave võrku", + "traffic_warning": "Parandamissprotsess tekitab Z-Wave võrgus palju liiklust. See võib põhjustada seadmete aeglast reageerimise (või üldse mitte) kuni parandamine on pooleli." + }, "logs": { "log_level": "Logimise tase", "log_level_changed": "Silumisteave on muudetud: {level}", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index f710c5c02c..61e3e07537 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -2962,6 +2962,7 @@ "common": { "add_node": "Добавить узел", "close": "Закрыть", + "heal_network": "Перенастройка сети", "home_id": "ID дома", "network": "Сеть", "node_id": "ID узла", @@ -2988,6 +2989,18 @@ "node_status": "Статус узла", "zwave_info": "Информация о Z-Wave" }, + "heal_network": { + "healing_cancelled": "Перенастройка сети была отменена.", + "healing_complete": "Перенастройка сети завершена.", + "healing_failed": "Не удалось завершить перенастройку сети. Дополнительная информация может быть доступна в журналах.", + "in_progress": "Идет перенастройка сети. Это займет некоторое время.", + "introduction": "Перенастройка сети заставит все устройства пересчитать свои маршруты к контроллеру. Эта процедура рекомендуется, если Вы переместили в другое место устройства или контроллер.", + "run_in_background": "Вы можете закрыть это диалоговое окно, перенастройка сети продолжится в фоновом режиме.", + "start_heal": "Начать перенастройку", + "stop_heal": "Остановить перенастройку", + "title": "Перенастройка сети Z-Wave", + "traffic_warning": "Во время перенастройки генерируется большой объем трафика в сети Z-Wave. В связи с этим, устройства могут отвечать с задержками (или вообще не отвечать)." + }, "logs": { "log_level": "Уровень", "log_level_changed": "Уровень журнала изменен на: {level}", @@ -3114,8 +3127,8 @@ "add_node": "Добавить узел", "add_node_secure": "Добавить защищенный узел", "cancel_command": "Отменить команду", - "heal_network": "Исправить сеть", - "heal_node": "Исправить узел", + "heal_network": "Перенастройка сети", + "heal_node": "Перенастроить узел", "node_info": "Информация об узле", "print_node": "Показать узел", "refresh_entity": "Обновить объект", From 76daeb7e55743461932f1490febf969288804182 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 30 Jun 2021 11:50:49 +0200 Subject: [PATCH 69/73] Fix wait for not loaded panel (#9478) --- src/layouts/partial-panel-resolver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/partial-panel-resolver.ts b/src/layouts/partial-panel-resolver.ts index 6035c27713..612ced46c5 100644 --- a/src/layouts/partial-panel-resolver.ts +++ b/src/layouts/partial-panel-resolver.ts @@ -43,7 +43,7 @@ const COMPONENTS = { class PartialPanelResolver extends HassRouterPage { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public narrow?: boolean; + @property({ type: Boolean }) public narrow?: boolean; private _waitForStart = false; @@ -206,7 +206,7 @@ class PartialPanelResolver extends HassRouterPage { this._currentPage && !this.hass.panels[this._currentPage] ) { - if (this.hass.config.state !== STATE_NOT_RUNNING) { + if (this.hass.config.state === STATE_NOT_RUNNING) { this._waitForStart = true; if (this.lastChild) { this.removeChild(this.lastChild); From 805f5ff9b6754c47925911b5791784b9fc7cbc69 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 30 Jun 2021 11:52:36 +0200 Subject: [PATCH 70/73] Recreate columns if cards change (#9480) --- src/panels/lovelace/views/hui-masonry-view.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/panels/lovelace/views/hui-masonry-view.ts b/src/panels/lovelace/views/hui-masonry-view.ts index 908d32e818..5ce2edf13e 100644 --- a/src/panels/lovelace/views/hui-masonry-view.ts +++ b/src/panels/lovelace/views/hui-masonry-view.ts @@ -127,6 +127,10 @@ export class MasonryView extends LitElement implements LovelaceViewElement { public willUpdate(changedProperties: PropertyValues) { super.willUpdate(changedProperties); + if (this.lovelace?.editMode) { + import("./default-view-editable"); + } + if (changedProperties.has("hass")) { const oldHass = changedProperties.get("hass") as | HomeAssistant @@ -140,14 +144,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement { if (changedProperties.has("narrow")) { this._updateColumns(); - } - } - - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); - - if (this.lovelace?.editMode) { - import("./default-view-editable"); + return; } const oldLovelace = changedProperties.get("lovelace") as @@ -155,10 +152,11 @@ export class MasonryView extends LitElement implements LovelaceViewElement { | undefined; if ( - changedProperties.has("lovelace") && - oldLovelace && - (oldLovelace.config !== this.lovelace?.config || - oldLovelace.editMode !== this.lovelace?.editMode) + changedProperties.has("cards") || + (changedProperties.has("lovelace") && + oldLovelace && + (oldLovelace.config !== this.lovelace!.config || + oldLovelace.editMode !== this.lovelace!.editMode)) ) { this._createColumns(); } From be244b3d00c1878afd085ac7397529196d1a5f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Wed, 30 Jun 2021 12:00:33 +0200 Subject: [PATCH 71/73] Rename hassos -> haos (#9477) --- hassio/src/dashboard/hassio-update.ts | 2 +- hassio/src/system/hassio-host-info.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hassio/src/dashboard/hassio-update.ts b/hassio/src/dashboard/hassio-update.ts index 21836b1c1a..7947a5372c 100644 --- a/hassio/src/dashboard/hassio-update.ts +++ b/hassio/src/dashboard/hassio-update.ts @@ -86,7 +86,7 @@ export class HassioUpdate extends LitElement { "hassio/supervisor/update", `https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}` )} - ${this.supervisor.host.features.includes("hassos") + ${this.supervisor.host.features.includes("haos") ? this._renderUpdateCard( "Operating System", "os", diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts index 1381bf291a..60256bbe64 100644 --- a/hassio/src/system/hassio-host-info.ts +++ b/hassio/src/system/hassio-host-info.ts @@ -113,7 +113,7 @@ class HassioHostInfo extends LitElement { ` : ""} - ${!this.supervisor.host.features.includes("hassos") + ${!this.supervisor.host.features.includes("haos") ? html` ${this.supervisor.localize("system.host.docker_version")} @@ -190,7 +190,7 @@ class HassioHostInfo extends LitElement { ${this.supervisor.localize("system.host.hardware")} - ${this.supervisor.host.features.includes("hassos") + ${this.supervisor.host.features.includes("haos") ? html` ${this.supervisor.localize("system.host.import_from_usb")} ` From 8141f78a9287f65464ab5670f140bbb0193effb3 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 30 Jun 2021 12:02:01 +0200 Subject: [PATCH 72/73] Use ES5 build for Safari 12 and below (#9482) --- build-scripts/gulp/webpack.js | 9 +++++---- src/html/_js_base.html.template | 1 + src/html/authorize.html.template | 17 ++++++++++------- src/html/index.html.template | 15 +++++++++------ src/html/onboarding.html.template | 17 ++++++++++------- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/build-scripts/gulp/webpack.js b/build-scripts/gulp/webpack.js index e7083cd578..bb72b0479d 100644 --- a/build-scripts/gulp/webpack.js +++ b/build-scripts/gulp/webpack.js @@ -86,10 +86,11 @@ const prodBuild = (conf) => gulp.task("webpack-watch-app", () => { // This command will run forever because we don't close compiler - webpack(createAppConfig({ isProdBuild: false, latestBuild: true })).watch( - { ignored: /build-translations/, poll: isWsl }, - doneHandler() - ); + webpack( + process.env.ES5 + ? bothBuilds(createAppConfig, { isProdBuild: false }) + : createAppConfig({ isProdBuild: false, latestBuild: true }) + ).watch({ ignored: /build-translations/, poll: isWsl }, doneHandler()); gulp.watch( path.join(paths.translations_src, "en.json"), gulp.series("build-translations", "copy-translations-app") diff --git a/src/html/_js_base.html.template b/src/html/_js_base.html.template index 08cc3ce65a..f8dc4835c9 100644 --- a/src/html/_js_base.html.template +++ b/src/html/_js_base.html.template @@ -20,4 +20,5 @@ "content" in document.createElement("template"))) { document.write(" diff --git a/src/html/authorize.html.template b/src/html/authorize.html.template index 555aea9e0e..4b7fbc9c53 100644 --- a/src/html/authorize.html.template +++ b/src/html/authorize.html.template @@ -43,13 +43,16 @@ <%= renderTemplate('_preload_roboto') %> diff --git a/src/html/index.html.template b/src/html/index.html.template index 0bcd77307f..f758aa5e33 100644 --- a/src/html/index.html.template +++ b/src/html/index.html.template @@ -67,12 +67,15 @@ <%= renderTemplate('_preload_roboto') %> From f5dcf0b76019d4669c228d734352aa8b6ec32be8 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 30 Jun 2021 12:03:07 +0200 Subject: [PATCH 73/73] Bumped version to 20210630.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cdb54db937..4ac42a4d05 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20210603.0", + version="20210630.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors",