fix: close beta 2 polish gaps

Issue: #406
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-01 16:32:25 +00:00
committed by claude[bot]
parent 8273af59ca
commit 372d838ec2
37 changed files with 612 additions and 267 deletions
+17 -1
View File
@@ -65,7 +65,7 @@ export function markerAreaSnapshotOf(value: unknown): MarkerAreaSnapshot {
if (!value || typeof value !== 'object' || Array.isArray(value)) return {};
const result: MarkerAreaSnapshot = {};
for (const [id, raw] of Object.entries(value as Record<string, unknown>)
.slice(0, MARKER_AREA_SNAPSHOT_LIMIT)) {
.slice(-MARKER_AREA_SNAPSHOT_LIMIT)) {
if (!validText(id) || !raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
const binding = (raw as { binding?: unknown }).binding;
const area = (raw as { area?: unknown }).area;
@@ -142,6 +142,22 @@ export function resolveDeviceAreaRelocations(
if (!options.authoritative) return { decisions, relocateIds };
const snapshot = markerAreaSnapshotOf(options.snapshot);
const liveIds = new Set<string>();
const liveBindings = new Set<MarkerAreaBinding>();
for (const device of options.devices) {
if (validText(device.id)) liveIds.add(device.id);
if (validText(device.marker?.id)) liveIds.add(device.marker.id);
if ((device.bindingKind === 'device' || device.bindingKind === 'entity')
&& validText(device.bindingRef)) {
liveBindings.add(`${device.bindingKind}:${device.bindingRef}`);
}
if (validBinding(device.marker?.binding)) liveBindings.add(device.marker.binding);
}
for (const [id, entry] of Object.entries(snapshot)) {
if (!liveIds.has(id) && !liveBindings.has(entry.binding)) decisions.push({
...unresolved(id, 'registry-unverified'), removeSnapshot: true,
});
}
const scale = Number.isFinite(options.coordinateScale) && Number(options.coordinateScale) > 0
? Number(options.coordinateScale) : 1000;
const targets = new Map<string, Array<{ space: SpaceModel; room: RoomCfg }>>();
+4 -1
View File
@@ -33,14 +33,17 @@ export class HpConfirm extends LitElement {
const request = this.request;
if (!request) return null;
const destructive = request.kind === 'destructive';
const descriptionId = `hp-confirm-description-${this.token}`;
return html`<hp-dialog class="danger-confirm-dialog"
.hass=${this.hass}
.title=${request.title}
.alert=${true}
.describedBy=${descriptionId}
.icon=${request.icon || (destructive
? 'mdi:alert-outline' : 'mdi:lock-open-alert-outline')}
dismiss-on-scrim
@hp-close=${() => this._decide(false)}>
<div class="body danger-confirm-body" data-confirm-key=${request.key}>
<div id=${descriptionId} class="body danger-confirm-body" data-confirm-key=${request.key}>
${request.objectName
? html`<strong class="danger-confirm-object">${request.objectName}</strong>`
: null}
+19 -8
View File
@@ -24,9 +24,10 @@ let dialogSequence = 0;
/**
* Shared modal shell for Houseplan.
*
* Home Assistant provides the visual surface and focus trap through ha-dialog.
* The native dialog branch keeps the standalone demo usable without mocking HA
* frontend internals. Both branches expose the same `hp-close` contract and
* Home Assistant provides the visual surface and focus trap through ha-dialog
* for ordinary dialogs. Alert confirmations deliberately use the native branch:
* the pinned HA component exposes an alert type but does not forward its role
* to the actual dialog. Both branches expose the same `hp-close` contract and
* restore focus to the control that opened the dialog.
*/
export class HpDialog extends LitElement {
@@ -34,6 +35,8 @@ export class HpDialog extends LitElement {
title: { type: String },
icon: { type: String },
wide: { type: Boolean, reflect: true },
alert: { type: Boolean, reflect: true },
describedBy: { type: String, attribute: 'described-by' },
dismissOnScrim: { type: Boolean, attribute: 'dismiss-on-scrim' },
hass: { attribute: false },
};
@@ -218,6 +221,8 @@ export class HpDialog extends LitElement {
title = '';
icon = '';
wide = false;
alert = false;
describedBy = '';
dismissOnScrim = false;
hass: any = null;
@@ -228,6 +233,10 @@ export class HpDialog extends LitElement {
private _overlays: OverlayEntry[] = [];
private readonly _titleId = `hp-dialog-title-${++dialogSequence}`;
private _usesHaDialog(): boolean {
return this._useHaDialog && !this.alert;
}
connectedCallback(): void {
super.connectedCallback();
this._opener = this._deepActiveElement();
@@ -274,7 +283,7 @@ export class HpDialog extends LitElement {
protected firstUpdated(changed: PropertyValues): void {
super.firstUpdated(changed);
if (!this._useHaDialog) {
if (!this._usesHaDialog()) {
const dialog = this.renderRoot.querySelector('dialog');
if (dialog && !dialog.open) dialog.showModal();
}
@@ -340,7 +349,7 @@ export class HpDialog extends LitElement {
const focusable = this._focusableElements();
const autofocus = focusable.find((el) => el.hasAttribute('autofocus'));
const target = autofocus || focusable[0]
|| (!this._useHaDialog ? this.renderRoot.querySelector<HTMLElement>('.close') : null)
|| (!this._usesHaDialog() ? this.renderRoot.querySelector<HTMLElement>('.close') : null)
|| this.renderRoot.querySelector<HTMLElement>('.surface')
|| this.renderRoot.querySelector<HTMLElement>('ha-dialog');
target?.focus({ preventScroll: true });
@@ -405,7 +414,7 @@ export class HpDialog extends LitElement {
this._requestClose();
return;
}
if (event.key !== 'Tab' || this._useHaDialog) return;
if (event.key !== 'Tab' || this._usesHaDialog()) return;
const close = this.renderRoot.querySelector<HTMLElement>('.close');
const focusable = close ? [close, ...this._focusableElements()] : this._focusableElements();
if (!focusable.length) {
@@ -440,13 +449,14 @@ export class HpDialog extends LitElement {
<span class="title-text">${this.title}</span>
</span>`;
if (this._useHaDialog) {
if (this._usesHaDialog()) {
return html`<ha-dialog
.hass=${this.hass}
.open=${true}
width=${this.wide ? 'medium' : 'small'}
.preventScrimClose=${!this.dismissOnScrim}
.ariaLabelledBy=${this._titleId}
.ariaDescribedBy=${this.describedBy || undefined}
@opened=${this._focusInitial}
@closed=${this._requestClose}
>
@@ -457,9 +467,10 @@ export class HpDialog extends LitElement {
}
return html`<dialog
role="dialog"
role=${this.alert ? 'alertdialog' : 'dialog'}
aria-modal="true"
aria-labelledby=${this._titleId}
aria-describedby=${this.describedBy || nothing}
@cancel=${this._onFallbackCancel}
@click=${this._onFallbackClick}
>
-13
View File
@@ -28,7 +28,6 @@
"history.draft_segment": "Raum-Entwurfsegment hinzufügen",
"history.draft_merge": "Unvollständige Raumumrisse verbinden",
"history.draft_segment_delete": "Raum-Entwurfssegment entfernen",
"history.partition_add": "Trennwand hinzufügen",
"history.column_add": "Säule hinzufügen",
"history.physical_edit": "Physisches Objekt ändern",
"history.physical_delete": "Physisches Objekt löschen",
@@ -37,8 +36,6 @@
"history.wall_chain_finish": "Wandkette fertigstellen",
"history.wall_face_batch": "Räume aus Wänden erstellen",
"toast.column_duplicate": "Eine Säule mit demselben Zentrum und äußerer Größe existiert bereits",
"confirm.delete_draft": "Sofort den gesamten unvollständigen Raumumriss löschen?",
"confirm.delete_draft_segment": "Dieses Entwurfssegment löschen? Der verbleibende Umriss könnte sich in zwei teilen.",
"confirm.delete_draft_title": "Unvollständigen Umriss löschen?",
"confirm.delete_draft_body": "Der gesamte unvollständige Raumumriss wird gelöscht. Beim Abbrechen wird nichts geändert.",
"confirm.delete_draft_segment_title": "Umrisssegment löschen?",
@@ -76,7 +73,6 @@
"title.zoom_in": "Zoomen",
"title.zoom_out": "Herauszoomen",
"title.zoom_fit": "Alles anpassen",
"title.markup": "Raum-Markierung: Gitter, Linien, Konturen",
"title.configure_space": "Bereich konfigurieren",
"title.add_space": "Bereich hinzufügen",
"title.markup_add": "Wände: eine durchgehende Kette zeichnen; Shift sperrt auf 45°. Werkzeugwechsel oder Verlassen des Editors beendet die Kette und wandelt sie in unabhängige Wände",
@@ -121,7 +117,6 @@
"history.edit_opening": "Öffnung bearbeiten",
"history.move_opening": "Öffnung verschieben",
"history.delete_opening": "Öffnung löschen",
"history.delete_room": "Raum löschen",
"history.delete_room_keep_walls": "Raum löschen, Wände behalten",
"history.delete_room_with_walls": "Raum und Wände löschen",
"history.decor_add": "Dekorobjekt hinzufügen",
@@ -163,7 +158,6 @@
"confirm.delete_partition_openings_title": "Wand und Öffnungen löschen?",
"confirm.delete_partition_openings_body": "Diese Wand enthält {count} Öffnung(en). Sie werden zusammen gelöscht.",
"confirm.delete_partition_openings_item": "• {type}, {length}",
"markup.delete": "Löschen",
"markup.hint_points": "Punkte: {n} · Shift — 45° Schritte · Esc — Kette beenden · Ctrl+Z — Punkt rückgängig machen · Schließen eines Bereichs erstellt einen Raum",
"markup.hint_start": "Klicken Sie auf einen Rasterpunkt, um eine Wandkette zu starten",
"tip.lqi": "durchschnittliches Zigbee-Signal:",
@@ -192,9 +186,7 @@
"display.badge": "Symbol + Zustand",
"display.icon_ripple": "Symbol + Zustand und Aktivität",
"display.static_icon": "Immer statisches Symbol",
"marker.display_hint": "Symbol + Zustand ändert die Platte für die Zustände Arbeit, geöffnet, Alarm und nicht verfügbar. Symbol + Zustand und Aktivität zeigt zusätzlich einen kurzen Impuls für Ereignisse und einen kontinuierlichen Impuls für laufende Arbeit, Bewegung oder Präsenz. Wert + Zustand ersetzt das Symbol durch einen eindeutigen HA-Wert. Ein statisches Symbol reagiert niemals auf Gerätezustände.",
"marker.display_hint_badge": "Das Symbol und die dynamische Platte zeigen den Gerätezustand ohne den üblichen Aktivitätspuls. Rote Alarme bleiben sichtbar.",
"marker.display_hint_icon": "Das Symbol und die dynamische Platte zeigen den Gerätezustand ohne den üblichen Aktivitätspuls. Rote Alarme bleiben sichtbar.",
"marker.display_hint_icon_ripple": "Das Symbol, die dynamische Platte und der Puls zeigen einen kurzen Puls für Ereignisse und einen kontinuierlichen Puls für Arbeit, Bewegung oder Anwesenheit. Rote Alarme haben eine separate Priorität.",
"marker.display_hint_value": "Ein ausgewählter oder automatisch ermittelter Home Assistant-Wert ersetzt das Symbol, während die Platte weiterhin den Zustand anzeigt. Rote Alarme bleiben sichtbar.",
"marker.display_hint_static_icon": "Die themenabhängige Hülle und das Symbol bleiben immer gleich. Zustand, Aktivität, Nichtverfügbarkeit und Alarme verändern nicht das Erscheinungsbild.",
@@ -293,14 +285,11 @@
"device.light_group": "Lichtgruppe",
"device.fallback": "Gerät",
"device.virtual": "Virtuelles Gerät",
"confirm.delete_room": "Raum \"{name}\" löschen?",
"confirm.delete_room_title": "Raum \"{name}\" löschen?",
"confirm.delete_room_body": "Festlegen, ob die ausschließlich zu diesem Raum gehörenden physischen Wände erhalten bleiben. Mit einem anderen Raum geteilte Wände bleiben immer erhalten.",
"confirm.remove_marker": "„{name}“ aus dem Plan löschen? Das Gerät verschwindet vollständig und trägt nicht mehr zu den Plandaten bei. Es kann später erneut hinzugefügt werden.",
"confirm.remove_marker_title": "Gerät aus dem Plan löschen?",
"confirm.remove_marker_body": "Das Gerät verschwindet vollständig und trägt nicht mehr zu den Plandaten bei. Es kann später erneut hinzugefügt werden.",
"confirm.erase_decor": "Das Objekt „{kind}“ löschen? Diese Aktion kann im Editor rückgängig gemacht werden.",
"confirm.delete_space": "Bereich „{title}“ mit allen Räumen und Markierungen löschen?",
"confirm.delete_space_title": "Bereich löschen?",
"confirm.delete_space_body": "Der Bereich, alle seine Räume und die gesamte Planmarkierung werden gelöscht.",
"space.delete_blocked": "Dieser Bereich wird noch von {n} Gerät(en) verwendet. Die Geräte zuerst in einen anderen Bereich verschieben oder löschen.",
@@ -737,7 +726,6 @@
"marker.control_passive": "passive Quelle",
"toast.marker_control_cycle": "Dieser Link würde eine kreisförmige Kette von Lichtsteuerungen erzeugen.",
"toast.marker_binding_required": "Wählen Sie ein Home Assistant-Gerät, bevor Sie eine andere Lichtquelle verlinken.",
"confirm.unlock": "„{name}“ entsperren?",
"confirm.unlock_title": "Schloss öffnen?",
"confirm.unlock_body": "House Plan sendet einen Befehl zum Öffnen an dieses Schloss.",
"toast.files_migrate_failed": "Anhänge konnten nicht zur neuen Bindung verschoben werden, Links zeigen weiterhin auf die alten Dateien: {err}",
@@ -748,7 +736,6 @@
"space.used_by": "in Benutzung: {list}",
"space.in_use": "Ein Bereich verwendet diesen Plan noch — zuerst die Verknüpfung lösen",
"btn.use": "Verwenden",
"confirm.delete_plan": "Plandatei „{name}“ vom Server löschen? Dies kann nicht rückgängig gemacht werden.",
"confirm.delete_plan_title": "Plandatei löschen?",
"confirm.delete_plan_body": "Die Datei wird vom Server gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden.",
"toast.plans_list_failed": "Konnte die gespeicherten Pläne nicht auflisten: {err}",
-13
View File
@@ -28,7 +28,6 @@
"history.draft_segment": "Add room-draft segment",
"history.draft_merge": "Join unfinished room outlines",
"history.draft_segment_delete": "Remove room-draft segment",
"history.partition_add": "Add partition",
"history.column_add": "Add column",
"history.physical_edit": "Change physical object",
"history.physical_delete": "Delete physical object",
@@ -37,8 +36,6 @@
"history.wall_chain_finish": "Finish wall chain",
"history.wall_face_batch": "Create rooms from walls",
"toast.column_duplicate": "A column with the same centre and outer size already exists",
"confirm.delete_draft": "Delete the whole unfinished room contour?",
"confirm.delete_draft_segment": "Delete this draft segment? The remaining contour may split in two.",
"confirm.delete_draft_title": "Delete unfinished contour?",
"confirm.delete_draft_body": "The entire unfinished room contour will be deleted. Cancelling makes no changes.",
"confirm.delete_draft_segment_title": "Delete contour segment?",
@@ -76,7 +73,6 @@
"title.zoom_in": "Zoom in",
"title.zoom_out": "Zoom out",
"title.zoom_fit": "Fit all",
"title.markup": "Room markup: grid, lines, outlines",
"title.configure_space": "Configure space",
"title.add_space": "Add space",
"title.markup_add": "Walls: draw a continuous chain; Shift locks to 45°. Changing tool or leaving the editor finishes it as independent walls",
@@ -121,7 +117,6 @@
"history.edit_opening": "Edit opening",
"history.move_opening": "Move opening",
"history.delete_opening": "Delete opening",
"history.delete_room": "Delete room",
"history.delete_room_keep_walls": "Delete room, keep walls",
"history.delete_room_with_walls": "Delete room and walls",
"history.decor_add": "Add decor object",
@@ -163,7 +158,6 @@
"confirm.delete_partition_openings_title": "Delete wall and openings?",
"confirm.delete_partition_openings_body": "This wall contains {count} opening(s). They will be deleted together.",
"confirm.delete_partition_openings_item": "• {type}, {length}",
"markup.delete": "Delete",
"markup.hint_points": "points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room",
"markup.hint_start": "click a grid dot to start a wall chain",
"tip.lqi": "average zigbee signal:",
@@ -192,9 +186,7 @@
"display.badge": "Icon + state",
"display.icon_ripple": "Icon + state and activity",
"display.static_icon": "Always static icon",
"marker.display_hint": "Icon + state changes the plate for work, open, alarm and unavailable states. Icon + state and activity additionally shows a short pulse for events and a continuous pulse for ongoing work, movement or presence. Value + state replaces the icon with one unambiguous HA value. A static icon never reacts to device states.",
"marker.display_hint_badge": "The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.",
"marker.display_hint_icon": "The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.",
"marker.display_hint_icon_ripple": "The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.",
"marker.display_hint_value": "A selected or automatically resolved Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.",
"marker.display_hint_static_icon": "The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.",
@@ -293,14 +285,11 @@
"device.light_group": "light group",
"device.fallback": "device",
"device.virtual": "virtual device",
"confirm.delete_room": "Delete room \"{name}\"?",
"confirm.delete_room_title": "Delete room \"{name}\"?",
"confirm.delete_room_body": "Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.",
"confirm.remove_marker": "Delete \"{name}\" from the plan? The device will disappear completely and stop contributing to plan data. You can add it again later.",
"confirm.remove_marker_title": "Delete device from the plan?",
"confirm.remove_marker_body": "The device will disappear completely and stop contributing to plan data. You can add it again later.",
"confirm.erase_decor": "Erase the {kind} object? You can undo this action from the editor history.",
"confirm.delete_space": "Delete space \"{title}\" with all its rooms and markup?",
"confirm.delete_space_title": "Delete space?",
"confirm.delete_space_body": "The space, all its rooms and all its plan markup will be deleted.",
"space.delete_blocked": "This space is still used by {n} device(s). Move them to another space or delete them first.",
@@ -737,7 +726,6 @@
"marker.control_passive": "passive source",
"toast.marker_control_cycle": "This link would create a circular chain of light controls.",
"toast.marker_binding_required": "Choose a Home Assistant device before linking another light source.",
"confirm.unlock": "Unlock “{name}”?",
"confirm.unlock_title": "Unlock?",
"confirm.unlock_body": "House Plan will send an unlock command to this lock.",
"toast.files_migrate_failed": "Attachments could not be moved to the new binding, links keep pointing at the old files: {err}",
@@ -748,7 +736,6 @@
"space.used_by": "in use: {list}",
"space.in_use": "A space still uses this plan — detach it first",
"btn.use": "Use",
"confirm.delete_plan": "Delete the plan file \"{name}\" from the server? This cannot be undone.",
"confirm.delete_plan_title": "Delete plan file?",
"confirm.delete_plan_body": "The file will be deleted from the server. This action cannot be undone.",
"toast.plans_list_failed": "Could not list the stored plans: {err}",
-13
View File
@@ -28,7 +28,6 @@
"history.draft_segment": "Ajouter un segment de brouillon de pièce",
"history.draft_merge": "Relier des contours de pièce inachevés",
"history.draft_segment_delete": "Supprimer un segment de brouillon de pièce",
"history.partition_add": "Ajouter une cloison",
"history.column_add": "Ajouter une colonne",
"history.physical_edit": "Modifier l’objet physique",
"history.physical_delete": "Supprimer l’objet physique",
@@ -37,8 +36,6 @@
"history.wall_chain_finish": "Terminer la chaîne de murs",
"history.wall_face_batch": "Créer des pièces à partir des murs",
"toast.column_duplicate": "Une colonne avec le même centre et la même dimension extérieure existe déjà",
"confirm.delete_draft": "Supprimer tout le contour de pièce inachevé ?",
"confirm.delete_draft_segment": "Supprimer ce segment de brouillon ? Le contour restant peut se scinder en deux.",
"confirm.delete_draft_title": "Supprimer le contour inachevé ?",
"confirm.delete_draft_body": "Tout le contour de pièce inachevé sera supprimé. L’annulation ne modifie rien.",
"confirm.delete_draft_segment_title": "Supprimer le segment de contour ?",
@@ -76,7 +73,6 @@
"title.zoom_in": "Zoomer",
"title.zoom_out": "Dézoomer",
"title.zoom_fit": "Tout ajuster",
"title.markup": "Traçage des pièces : grille, lignes, contours",
"title.configure_space": "Configurer l’espace",
"title.add_space": "Ajouter un espace",
"title.markup_add": "Murs : tracez une chaîne continue ; Maj verrouille à 45°. Changer d’outil ou quitter l’éditeur termine la chaîne en murs indépendants",
@@ -121,7 +117,6 @@
"history.edit_opening": "Modifier l’ouverture",
"history.move_opening": "Déplacer l’ouverture",
"history.delete_opening": "Supprimer l’ouverture",
"history.delete_room": "Supprimer la pièce",
"history.delete_room_keep_walls": "Supprimer la pièce, conserver les murs",
"history.delete_room_with_walls": "Supprimer la pièce et les murs",
"history.decor_add": "Ajouter un objet décoratif",
@@ -163,7 +158,6 @@
"confirm.delete_partition_openings_title": "Supprimer le mur et les ouvertures ?",
"confirm.delete_partition_openings_body": "Ce mur contient {count} ouverture(s). Elles seront supprimées avec lui.",
"confirm.delete_partition_openings_item": "• {type}, {length}",
"markup.delete": "Supprimer",
"markup.hint_points": "points : {n} · Maj — pas de 45° · Échap — terminer la chaîne · Ctrl+Z — annuler un point · fermer une zone propose de créer une pièce",
"markup.hint_start": "cliquez sur un point de la grille pour commencer une chaîne de murs",
"tip.lqi": "signal Zigbee moyen :",
@@ -192,9 +186,7 @@
"display.badge": "Icône + état",
"display.icon_ripple": "Icône + état et activité",
"display.static_icon": "Icône toujours statique",
"marker.display_hint": "Icône + état modifie le fond pour les états en fonctionnement, ouvert, alarme et indisponible. Icône + état et activité ajoute une brève pulsation pour les événements et une pulsation continue pour une activité, un mouvement ou une présence en cours. Valeur + état remplace l’icône par une valeur HA non ambiguë. Une icône statique ne réagit jamais aux états de l’appareil.",
"marker.display_hint_badge": "L’icône et le fond dynamique affichent l’état de l’appareil sans la pulsation d’activité habituelle. Les alarmes rouges restent visibles.",
"marker.display_hint_icon": "L’icône et le fond dynamique affichent l’état de l’appareil sans la pulsation d’activité habituelle. Les alarmes rouges restent visibles.",
"marker.display_hint_icon_ripple": "L’icône, le fond dynamique et la pulsation affichent une brève animation pour les événements et une animation continue pour le fonctionnement, le mouvement ou la présence. Les alarmes rouges restent prioritaires.",
"marker.display_hint_value": "Une valeur Home Assistant sélectionnée ou résolue automatiquement remplace l’icône tandis que le fond continue d’indiquer l’état. Les alarmes rouges restent visibles.",
"marker.display_hint_static_icon": "Le contour adapté au thème et l’icône restent toujours identiques. L’état, l’activité, l’indisponibilité et les alarmes ne modifient pas l’apparence.",
@@ -293,14 +285,11 @@
"device.light_group": "groupe de lumières",
"device.fallback": "appareil",
"device.virtual": "appareil virtuel",
"confirm.delete_room": "Supprimer la pièce « {name} » ?",
"confirm.delete_room_title": "Supprimer la pièce « {name} » ?",
"confirm.delete_room_body": "Choisissez si les murs physiques propres à la pièce doivent être conservés. Les murs partagés avec une autre pièce sont toujours conservés.",
"confirm.remove_marker": "Supprimer « {name} » du plan ? L’appareil disparaîtra complètement et ne contribuera plus aux données du plan. Vous pourrez l’ajouter de nouveau plus tard.",
"confirm.remove_marker_title": "Supprimer l’appareil du plan ?",
"confirm.remove_marker_body": "L’appareil disparaîtra complètement et ne contribuera plus aux données du plan. Vous pourrez l’ajouter de nouveau plus tard.",
"confirm.erase_decor": "Effacer l’objet {kind} ? Vous pouvez annuler cette action depuis l’historique de l’éditeur.",
"confirm.delete_space": "Supprimer l’espace « {title} » avec toutes ses pièces et son tracé ?",
"confirm.delete_space_title": "Supprimer l’espace ?",
"confirm.delete_space_body": "L’espace, toutes ses pièces et tout le tracé du plan seront supprimés.",
"space.delete_blocked": "Cet espace est encore utilisé par {n} appareil(s). Déplacez-les vers un autre espace ou supprimez-les d’abord.",
@@ -737,7 +726,6 @@
"marker.control_passive": "source passive",
"toast.marker_control_cycle": "Ce lien créerait une chaîne circulaire de contrôles de lumière.",
"toast.marker_binding_required": "Choisissez un appareil Home Assistant avant de lier une autre source lumineuse.",
"confirm.unlock": "Déverrouiller « {name} » ?",
"confirm.unlock_title": "Déverrouiller ?",
"confirm.unlock_body": "House Plan enverra une commande de déverrouillage à cette serrure.",
"toast.files_migrate_failed": "Les pièces jointes n’ont pas pu être déplacées vers la nouvelle association ; les liens continuent de pointer vers les anciens fichiers : {err}",
@@ -748,7 +736,6 @@
"space.used_by": "utilisé par : {list}",
"space.in_use": "Un espace utilise encore ce plan — dissociez-le d’abord",
"btn.use": "Utiliser",
"confirm.delete_plan": "Supprimer le fichier de plan « {name} » du serveur ? Cette action est irréversible.",
"confirm.delete_plan_title": "Supprimer le fichier du plan ?",
"confirm.delete_plan_body": "Le fichier sera supprimé du serveur. Cette action est irréversible.",
"toast.plans_list_failed": "Impossible de lister les plans stockés : {err}",
-13
View File
@@ -28,7 +28,6 @@
"history.draft_segment": "Добавление сегмента черновика комнаты",
"history.draft_merge": "Соединение незавершённых контуров комнаты",
"history.draft_segment_delete": "Удаление сегмента черновика комнаты",
"history.partition_add": "Добавление перегородки",
"history.column_add": "Добавление колонны",
"history.physical_edit": "Изменение физического объекта",
"history.physical_delete": "Удаление физического объекта",
@@ -37,8 +36,6 @@
"history.wall_chain_finish": "Завершение цепочки стен",
"history.wall_face_batch": "Создание комнат из стен",
"toast.column_duplicate": "Колонна с тем же центром и внешним размером уже существует",
"confirm.delete_draft": "Удалить весь незавершённый контур комнаты?",
"confirm.delete_draft_segment": "Удалить этот сегмент черновика? Оставшийся контур может разделиться на два.",
"confirm.delete_draft_title": "Удалить незавершённый контур?",
"confirm.delete_draft_body": "Весь незавершённый контур комнаты будет удалён. При отмене ничего не изменится.",
"confirm.delete_draft_segment_title": "Удалить сегмент контура?",
@@ -76,7 +73,6 @@
"title.zoom_in": "Приблизить",
"title.zoom_out": "Отдалить",
"title.zoom_fit": "Вписать всё",
"title.markup": "Разметка комнат: сетка, линии, контуры",
"title.configure_space": "Настроить пространство",
"title.add_space": "Добавить пространство",
"title.markup_add": "Стены: рисуйте непрерывную цепочку; Shift фиксирует 45°. Смена инструмента или выход завершает её как независимые стены",
@@ -121,7 +117,6 @@
"history.edit_opening": "Изменение проёма",
"history.move_opening": "Перемещение проёма",
"history.delete_opening": "Удаление проёма",
"history.delete_room": "Удаление комнаты",
"history.delete_room_keep_walls": "Удаление комнаты с сохранением стен",
"history.delete_room_with_walls": "Удаление комнаты и её стен",
"history.decor_add": "Добавление объекта декора",
@@ -163,7 +158,6 @@
"confirm.delete_partition_openings_title": "Удалить стену и проёмы?",
"confirm.delete_partition_openings_body": "В стене есть проёмы: {count}. Они будут удалены вместе со стеной.",
"confirm.delete_partition_openings_item": "• {type}, {length}",
"markup.delete": "Удалить",
"markup.hint_points": "точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната",
"markup.hint_start": "кликните точку сетки, чтобы начать цепочку стен",
"tip.lqi": "средний сигнал zigbee:",
@@ -192,9 +186,7 @@
"display.badge": "Значок + состояние",
"display.icon_ripple": "Значок + состояние и активность",
"display.static_icon": "Всегда статичный значок",
"marker.display_hint": "Значок + состояние меняет подложку при работе, открытии, тревоге и недоступности. Значок + состояние и активность дополнительно показывает короткую пульсацию для событий и постоянную — для работы, движения или присутствия. Значение + состояние заменяет значок одним однозначным значением HA. Статичный значок не реагирует на состояния устройства.",
"marker.display_hint_badge": "Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.",
"marker.display_hint_icon": "Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.",
"marker.display_hint_icon_ripple": "Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.",
"marker.display_hint_value": "Значок заменяется выбранным или автоматически найденным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.",
"marker.display_hint_static_icon": "Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.",
@@ -293,14 +285,11 @@
"device.light_group": "группа света",
"device.fallback": "устройство",
"device.virtual": "виртуальное устройство",
"confirm.delete_room": "Удалить комнату «{name}»?",
"confirm.delete_room_title": "Удалить комнату «{name}»?",
"confirm.delete_room_body": "Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.",
"confirm.remove_marker": "Удалить «{name}» с плана? Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.",
"confirm.remove_marker_title": "Удалить устройство с плана?",
"confirm.remove_marker_body": "Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.",
"confirm.erase_decor": "Стереть объект «{kind}»? Действие можно отменить из истории редактора.",
"confirm.delete_space": "Удалить пространство «{title}» со всеми комнатами и разметкой?",
"confirm.delete_space_title": "Удалить пространство?",
"confirm.delete_space_body": "Пространство, все его комнаты и вся разметка плана будут удалены.",
"space.delete_blocked": "Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.",
@@ -737,7 +726,6 @@
"marker.control_passive": "пассивный источник",
"toast.marker_control_cycle": "Такая связь создаст циклическую цепочку управления светом.",
"toast.marker_binding_required": "Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.",
"confirm.unlock": "Открыть замок «{name}»?",
"confirm.unlock_title": "Открыть замок?",
"confirm.unlock_body": "House Plan отправит этому замку команду открытия.",
"toast.files_migrate_failed": "Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}",
@@ -748,7 +736,6 @@
"space.used_by": "используется: {list}",
"space.in_use": "План используется пространством — сначала отцепите его",
"btn.use": "Выбрать",
"confirm.delete_plan": "Удалить файл плана «{name}» с сервера? Действие необратимо.",
"confirm.delete_plan_title": "Удалить файл плана?",
"confirm.delete_plan_body": "Файл будет удалён с сервера. Это действие нельзя отменить.",
"toast.plans_list_failed": "Не удалось получить список планов: {err}",