217 files
This commit is contained in:
1 parent
d43a63ad29
commit
7b5e46e702
217 files changed
+15978
-3912
No files matched your search
@@ -47,6 +47,7 @@ from .const import (
|
|||||||
CONF_BUDGET_MONTHLY,
|
CONF_BUDGET_MONTHLY,
|
||||||
CONF_BUDGET_YEARLY,
|
CONF_BUDGET_YEARLY,
|
||||||
CONF_GROUPS,
|
CONF_GROUPS,
|
||||||
|
CONF_INSTALL_ASSIST_SENTENCES,
|
||||||
CONF_OBJECT,
|
CONF_OBJECT,
|
||||||
CONF_PANEL_ENABLED,
|
CONF_PANEL_ENABLED,
|
||||||
CONF_TASKS,
|
CONF_TASKS,
|
||||||
@@ -58,6 +59,11 @@ from .const import (
|
|||||||
GLOBAL_UNIQUE_ID,
|
GLOBAL_UNIQUE_ID,
|
||||||
MAX_COST,
|
MAX_COST,
|
||||||
MAX_DURATION_MINUTES,
|
MAX_DURATION_MINUTES,
|
||||||
|
MAX_LABEL_LENGTH,
|
||||||
|
MAX_LABELS,
|
||||||
|
MAX_NAME_LENGTH,
|
||||||
|
MAX_TEXT_LENGTH,
|
||||||
|
MAX_TYPE_LENGTH,
|
||||||
PLATFORMS,
|
PLATFORMS,
|
||||||
SERVICE_ADD_OBJECT,
|
SERVICE_ADD_OBJECT,
|
||||||
SERVICE_ADD_TASK,
|
SERVICE_ADD_TASK,
|
||||||
@@ -81,10 +87,16 @@ from .const import (
|
|||||||
from .coordinator import MaintenanceCoordinator
|
from .coordinator import MaintenanceCoordinator
|
||||||
from .entity.summary_coordinator import MaintenanceSummaryCoordinator
|
from .entity.summary_coordinator import MaintenanceSummaryCoordinator
|
||||||
from .frontend import async_register_card
|
from .frontend import async_register_card
|
||||||
|
from .helpers.assist_sentences import async_sync as async_sync_assist_sentences
|
||||||
from .helpers.dates import INTERVAL_UNITS
|
from .helpers.dates import INTERVAL_UNITS
|
||||||
from .helpers.documents import DocumentStore
|
from .helpers.documents import DocumentStore
|
||||||
from .helpers.notification_manager import NotificationManager
|
from .helpers.notification_manager import NotificationManager
|
||||||
from .helpers.schedule import normalize_task_storage
|
from .helpers.schedule import normalize_task_storage
|
||||||
|
from .helpers.task_fields import (
|
||||||
|
INTERVAL_DAYS_RANGE,
|
||||||
|
TASK_PRIORITIES,
|
||||||
|
WARNING_DAYS_RANGE,
|
||||||
|
)
|
||||||
from .panel import async_register_panel, async_unregister_panel
|
from .panel import async_register_panel, async_unregister_panel
|
||||||
from .storage import MaintenanceStore, async_migrate_to_store
|
from .storage import MaintenanceStore, async_migrate_to_store
|
||||||
from .websocket import async_register_commands
|
from .websocket import async_register_commands
|
||||||
@@ -158,21 +170,29 @@ SERVICE_ADD_OBJECT_SCHEMA = vol.Schema(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# The service task schemas mirror the WS `task/create` / `task/update` schemas
|
||||||
|
# field-for-field, consuming the SAME constants + ranges (const.py /
|
||||||
|
# helpers.task_fields) rather than restating literals — the service path is
|
||||||
|
# just a third UI onto the same storage, so a value the WS API rejects must not
|
||||||
|
# be reachable from an automation. `vol.Coerce` stays (unlike the WS schemas)
|
||||||
|
# because YAML/templated service data arrives as strings.
|
||||||
SERVICE_ADD_TASK_SCHEMA = vol.Schema(
|
SERVICE_ADD_TASK_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required("entry_id"): cv.string,
|
vol.Required("entry_id"): cv.string,
|
||||||
vol.Required("name"): vol.All(cv.string, vol.Length(min=1, max=255)),
|
vol.Required("name"): vol.All(cv.string, vol.Length(min=1, max=MAX_NAME_LENGTH)),
|
||||||
vol.Optional("task_type"): cv.string,
|
vol.Optional("task_type"): vol.All(cv.string, vol.Length(max=MAX_TYPE_LENGTH)),
|
||||||
vol.Optional("schedule_type"): cv.string,
|
vol.Optional("schedule_type"): vol.All(cv.string, vol.Length(max=MAX_TYPE_LENGTH)),
|
||||||
vol.Optional("interval_days"): vol.All(vol.Coerce(int), vol.Range(min=1)),
|
vol.Optional("interval_days"): vol.All(
|
||||||
|
vol.Coerce(int), vol.Range(min=INTERVAL_DAYS_RANGE[0], max=INTERVAL_DAYS_RANGE[1])
|
||||||
|
),
|
||||||
vol.Optional("interval_unit"): vol.In(INTERVAL_UNITS),
|
vol.Optional("interval_unit"): vol.In(INTERVAL_UNITS),
|
||||||
vol.Optional("due_date"): cv.string,
|
vol.Optional("due_date"): cv.string,
|
||||||
# Nested recurrence for the calendar kinds (weekdays / nth_weekday /
|
# Nested recurrence for the calendar kinds (weekdays / nth_weekday /
|
||||||
# day_of_month); takes precedence over the flat fields above.
|
# day_of_month); takes precedence over the flat fields above.
|
||||||
vol.Optional("schedule"): dict,
|
vol.Optional("schedule"): dict,
|
||||||
vol.Optional("warning_days"): vol.All(vol.Coerce(int), vol.Range(min=0)),
|
vol.Optional("warning_days"): vol.All(vol.Coerce(int), vol.Range(min=WARNING_DAYS_RANGE[0], max=WARNING_DAYS_RANGE[1])),
|
||||||
vol.Optional("enabled"): cv.boolean,
|
vol.Optional("enabled"): cv.boolean,
|
||||||
vol.Optional("notes"): cv.string,
|
vol.Optional("notes"): vol.All(cv.string, vol.Length(max=MAX_TEXT_LENGTH)),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -180,18 +200,20 @@ SERVICE_UPDATE_TASK_SCHEMA = vol.Schema(
|
|||||||
{
|
{
|
||||||
vol.Required("entry_id"): cv.string,
|
vol.Required("entry_id"): cv.string,
|
||||||
vol.Required("task_id"): cv.string,
|
vol.Required("task_id"): cv.string,
|
||||||
vol.Optional("name"): vol.All(cv.string, vol.Length(min=1, max=255)),
|
vol.Optional("name"): vol.All(cv.string, vol.Length(min=1, max=MAX_NAME_LENGTH)),
|
||||||
vol.Optional("task_type"): cv.string,
|
vol.Optional("task_type"): vol.All(cv.string, vol.Length(max=MAX_TYPE_LENGTH)),
|
||||||
vol.Optional("schedule_type"): cv.string,
|
vol.Optional("schedule_type"): vol.All(cv.string, vol.Length(max=MAX_TYPE_LENGTH)),
|
||||||
vol.Optional("interval_days"): vol.All(vol.Coerce(int), vol.Range(min=1)),
|
vol.Optional("interval_days"): vol.All(
|
||||||
|
vol.Coerce(int), vol.Range(min=INTERVAL_DAYS_RANGE[0], max=INTERVAL_DAYS_RANGE[1])
|
||||||
|
),
|
||||||
vol.Optional("interval_unit"): vol.In(INTERVAL_UNITS),
|
vol.Optional("interval_unit"): vol.In(INTERVAL_UNITS),
|
||||||
vol.Optional("due_date"): cv.string,
|
vol.Optional("due_date"): cv.string,
|
||||||
vol.Optional("schedule"): dict,
|
vol.Optional("schedule"): dict,
|
||||||
vol.Optional("warning_days"): vol.All(vol.Coerce(int), vol.Range(min=0)),
|
vol.Optional("warning_days"): vol.All(vol.Coerce(int), vol.Range(min=WARNING_DAYS_RANGE[0], max=WARNING_DAYS_RANGE[1])),
|
||||||
vol.Optional("enabled"): cv.boolean,
|
vol.Optional("enabled"): cv.boolean,
|
||||||
vol.Optional("notes"): cv.string,
|
vol.Optional("notes"): vol.All(cv.string, vol.Length(max=MAX_TEXT_LENGTH)),
|
||||||
vol.Optional("priority"): vol.In(["low", "normal", "high"]),
|
vol.Optional("priority"): vol.In(TASK_PRIORITIES),
|
||||||
vol.Optional("labels"): [cv.string],
|
vol.Optional("labels"): vol.All([vol.All(cv.string, vol.Length(max=MAX_LABEL_LENGTH))], vol.Length(max=MAX_LABELS)),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -702,7 +724,7 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
|||||||
try:
|
try:
|
||||||
if action_type == "complete":
|
if action_type == "complete":
|
||||||
_LOGGER.info("Completing task %s via notification action", task_id)
|
_LOGGER.info("Completing task %s via notification action", task_id)
|
||||||
await runtime_data.coordinator.complete_maintenance(task_id=task_id)
|
await runtime_data.coordinator.complete_maintenance(task_id=task_id, unattended=True)
|
||||||
elif action_type == "skip":
|
elif action_type == "skip":
|
||||||
_LOGGER.info("Skipping task %s via notification action", task_id)
|
_LOGGER.info("Skipping task %s via notification action", task_id)
|
||||||
await runtime_data.coordinator.skip_maintenance(task_id=task_id, reason="Skipped from notification")
|
await runtime_data.coordinator.skip_maintenance(task_id=task_id, reason="Skipped from notification")
|
||||||
@@ -711,6 +733,17 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
|||||||
if nm is not None:
|
if nm is not None:
|
||||||
nm.snooze_task(entry_id, task_id)
|
nm.snooze_task(entry_id, task_id)
|
||||||
return # Snooze: keep notification visible for later reminder
|
return # Snooze: keep notification visible for later reminder
|
||||||
|
except ServiceValidationError as err:
|
||||||
|
# The task demands details a notification button cannot capture.
|
||||||
|
# Not an error in our code — log it plainly and deliberately do
|
||||||
|
# NOT dismiss the notification, so the reminder survives until the
|
||||||
|
# user completes the task properly in the panel.
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Notification completion of task %s rejected: %s",
|
||||||
|
task_id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
return
|
||||||
except Exception:
|
except Exception:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Failed to handle notification action %s for task %s",
|
"Failed to handle notification action %s for task %s",
|
||||||
@@ -755,11 +788,18 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
|||||||
tag_id,
|
tag_id,
|
||||||
)
|
)
|
||||||
user_id = event.context.user_id if event.context else None
|
user_id = event.context.user_id if event.context else None
|
||||||
await runtime_data.coordinator.complete_maintenance(
|
try:
|
||||||
task_id=task_id,
|
await runtime_data.coordinator.complete_maintenance(
|
||||||
completed_by=user_id,
|
task_id=task_id,
|
||||||
notes="Completed via NFC tag",
|
completed_by=user_id,
|
||||||
)
|
notes="Completed via NFC tag",
|
||||||
|
unattended=True,
|
||||||
|
)
|
||||||
|
except ServiceValidationError as err:
|
||||||
|
# A tag tap cannot capture a cost or a photo. Log it
|
||||||
|
# plainly and leave the task open so the user finishes it
|
||||||
|
# in the panel — the honest outcome, not a silent no-op.
|
||||||
|
_LOGGER.warning("NFC completion of task %s rejected: %s", task_id, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
# No match found — not our tag, ignore silently
|
# No match found — not our tag, ignore silently
|
||||||
@@ -1074,6 +1114,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: MaintenanceSupporterConf
|
|||||||
# Listen for options changes (panel toggle)
|
# Listen for options changes (panel toggle)
|
||||||
entry.async_on_unload(entry.add_update_listener(_async_global_options_updated))
|
entry.async_on_unload(entry.add_update_listener(_async_global_options_updated))
|
||||||
|
|
||||||
|
# Keep <config>/custom_sentences/ in step with the opt-in setting. Runs
|
||||||
|
# on every setup, not just on change, so an upgrade that ships new
|
||||||
|
# sentences reaches an install that already opted in.
|
||||||
|
await async_sync_assist_sentences(
|
||||||
|
hass, entry.options.get(CONF_INSTALL_ASSIST_SENTENCES, False)
|
||||||
|
)
|
||||||
|
|
||||||
# Initial orphan check for admin_panel_user_ids (HA users deleted
|
# Initial orphan check for admin_panel_user_ids (HA users deleted
|
||||||
# while the integration was offline land here as repair issues).
|
# while the integration was offline land here as repair issues).
|
||||||
await _check_admin_panel_user_orphans(hass, entry)
|
await _check_admin_panel_user_orphans(hass, entry)
|
||||||
@@ -1305,6 +1352,10 @@ async def _async_global_options_updated(hass: HomeAssistant, entry: ConfigEntry)
|
|||||||
await _check_admin_panel_user_orphans(hass, entry)
|
await _check_admin_panel_user_orphans(hass, entry)
|
||||||
# The notify service may have just been (re)configured — re-check it.
|
# The notify service may have just been (re)configured — re-check it.
|
||||||
_verify_notify_service(hass)
|
_verify_notify_service(hass)
|
||||||
|
# Install or remove the Assist sentence files to match the setting.
|
||||||
|
await async_sync_assist_sentences(
|
||||||
|
hass, entry.options.get(CONF_INSTALL_ASSIST_SENTENCES, False)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
_ORPHAN_ISSUE_PREFIX = "orphan_admin_panel_user_"
|
_ORPHAN_ISSUE_PREFIX = "orphan_admin_panel_user_"
|
||||||
@@ -1466,6 +1517,16 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|||||||
# as a fixable repair issue so the user can restore it (#86).
|
# as a fixable repair issue so the user can restore it (#86).
|
||||||
_sync_missing_global_entry_issue(hass)
|
_sync_missing_global_entry_issue(hass)
|
||||||
return
|
return
|
||||||
|
# #111: hand any shared spare-part pool to a borrower BEFORE the Store goes
|
||||||
|
# — the stock numbers exist nowhere else. Must happen here rather than in
|
||||||
|
# the panel's delete: HA's own Configure-UI removal never reaches that path.
|
||||||
|
from .helpers.shared_parts import async_transfer_pools_on_removal
|
||||||
|
|
||||||
|
try:
|
||||||
|
await async_transfer_pools_on_removal(hass, entry)
|
||||||
|
except Exception:
|
||||||
|
_LOGGER.exception("Could not transfer shared spare parts from %s", entry.title)
|
||||||
|
|
||||||
store = hass.data.get(STORES_CACHE_KEY, {}).pop(entry.entry_id, None)
|
store = hass.data.get(STORES_CACHE_KEY, {}).pop(entry.entry_id, None)
|
||||||
if store is None:
|
if store is None:
|
||||||
store = MaintenanceStore(hass, entry.entry_id)
|
store = MaintenanceStore(hass, entry.entry_id)
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
# Assist-Sätze für Maintenance Supporter (Deutsch).
|
||||||
|
#
|
||||||
|
# Handkopieren ist nicht nötig: Einstellungen -> Allgemein -> "Assist-Sätze
|
||||||
|
# installieren" einschalten, dann schreibt die Integration diese Datei nach
|
||||||
|
# config/custom_sentences/de/maintenance_supporter.yaml und lädt den
|
||||||
|
# Konversations-Agenten neu. Nur aus diesem Verzeichnis liest der klassische
|
||||||
|
# (Nicht-LLM-)Agent Sätze. LLM-basierte Assist-Pipelines brauchen davon
|
||||||
|
# nichts — dort sind die Intents automatisch als Tools verfügbar.
|
||||||
|
#
|
||||||
|
# Eine eigene Bearbeitung ist ausdrücklich vorgesehen: sobald der Inhalt nicht
|
||||||
|
# mehr dem entspricht, was wir geschrieben haben, fassen Aktualisierungen die
|
||||||
|
# Datei nicht mehr an (und das Abschalten der Einstellung ebenso wenig).
|
||||||
|
language: "de"
|
||||||
|
intents:
|
||||||
|
MaintenanceSupporterListTasks:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "welche Wartung[en] (ist|sind) [gerade] (fällig|überfällig)"
|
||||||
|
- "was ist [an Wartung] (fällig|überfällig)"
|
||||||
|
- "steht [eine] Wartung an"
|
||||||
|
- "was muss gewartet werden"
|
||||||
|
# Bezug: die fragende Person. HA übergibt dem Handler, wer gesprochen
|
||||||
|
# hat — damit antwortet dies mit deren Aufgaben (inkl. Rotationsdienst).
|
||||||
|
- sentences:
|
||||||
|
- "was muss ich (machen|erledigen|tun)"
|
||||||
|
- "was sind meine (Aufgaben|Pflichten|Wartungen)"
|
||||||
|
- "(habe|hab) ich [noch] (was|etwas) zu (tun|erledigen)"
|
||||||
|
- "bin ich [gerade] (dran|zuständig)"
|
||||||
|
slots:
|
||||||
|
scope: "mine"
|
||||||
|
# Bezug: der Raum, aus dem gefragt wurde — über den Bereich des
|
||||||
|
# Satelliten aufgelöst, damit ein Wandtablet für seinen Raum antwortet.
|
||||||
|
- sentences:
|
||||||
|
- "was ist hier [drin] (fällig|zu tun)"
|
||||||
|
- "welche Wartung ist (hier|in diesem Raum) fällig"
|
||||||
|
- "(gibt es|steht) hier [drin] (etwas|was) an"
|
||||||
|
slots:
|
||||||
|
scope: "here"
|
||||||
|
MaintenanceSupporterCompleteTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "[die] Wartung[saufgabe] {task_name:name} (erledigen|abschließen)"
|
||||||
|
- "markiere [die] [Wartung[saufgabe]] {task_name:name} als erledigt"
|
||||||
|
- "ich habe [die] {task_name:name} (erledigt|gemacht|abgeschlossen)"
|
||||||
|
MaintenanceSupporterTaskInstructions:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "wie (mache|erledige) ich [die] {task_name:name}"
|
||||||
|
- "(Anleitung|Anweisungen) für [die] {task_name:name}"
|
||||||
|
- "was brauche ich für [die] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskDue:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "wann ist [die] {task_name:name} fällig"
|
||||||
|
- "wann muss ich [die] {task_name:name} (machen|erledigen)"
|
||||||
|
MaintenanceSupporterSnoozeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "[die] {task_name:name} (snoozen|stummschalten)"
|
||||||
|
- "Erinnerungen für [die] {task_name:name} (stummschalten|pausieren)"
|
||||||
|
MaintenanceSupporterPartStock:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "wie viele {part_name:name} haben wir [noch]"
|
||||||
|
- "wie ist der Bestand (von|an) {part_name:name}"
|
||||||
|
MaintenanceSupporterPostponeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "verschiebe [die|das|den] {part_name:name} um {days} Tag[e]"
|
||||||
|
- "[die|das|den] {part_name:name} um {days} Tag[e] verschieben"
|
||||||
|
- "schiebe [die|das|den] {part_name:name} um {days} Tag[e] nach hinten"
|
||||||
|
- sentences:
|
||||||
|
- "verschiebe [die|das|den] {part_name:name} um eine Woche"
|
||||||
|
- "[die|das|den] {part_name:name} um eine Woche verschieben"
|
||||||
|
slots:
|
||||||
|
days: 7
|
||||||
|
MaintenanceSupporterSkipTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "überspringe [die|das|den] {part_name:name} [diesmal]"
|
||||||
|
- "[die|das|den] {part_name:name} [diesmal] überspringen"
|
||||||
|
lists:
|
||||||
|
# NOT called 'name': that is Home Assistant's built-in list of exposed
|
||||||
|
# ENTITY names, and the default agent resolves it against the registry
|
||||||
|
# before the handler runs — every sentence using it answered 'I am not
|
||||||
|
# aware of any device called ...' instead of reaching us. The
|
||||||
|
# {list:slot} alias keeps the value arriving in the 'name' slot.
|
||||||
|
task_name:
|
||||||
|
wildcard: true
|
||||||
|
part_name:
|
||||||
|
wildcard: true
|
||||||
|
days:
|
||||||
|
range:
|
||||||
|
from: 1
|
||||||
|
to: 365
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
# Assist sentences for Maintenance Supporter (English).
|
||||||
|
#
|
||||||
|
# You do not need to copy this by hand: turn on Settings -> General ->
|
||||||
|
# "Install Assist sentences" and the integration writes it to
|
||||||
|
# config/custom_sentences/en/maintenance_supporter.yaml and reloads the
|
||||||
|
# conversation agent. That is the only directory the classic (non-LLM) agent
|
||||||
|
# reads sentences from. LLM-based Assist pipelines need none of this — they
|
||||||
|
# pick the intents up as tools automatically.
|
||||||
|
#
|
||||||
|
# Editing your own copy is fine and expected: once its content no longer
|
||||||
|
# matches what we wrote, upgrades leave it alone (and so does turning the
|
||||||
|
# setting back off).
|
||||||
|
language: "en"
|
||||||
|
intents:
|
||||||
|
MaintenanceSupporterListTasks:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "what maintenance is (due|overdue)"
|
||||||
|
- "which maintenance [tasks] (are|is) (due|overdue|pending)"
|
||||||
|
- "is [there] any maintenance due"
|
||||||
|
- "what needs (maintenance|servicing)"
|
||||||
|
# Scope: the person asking. HA tells the handler who spoke, so this
|
||||||
|
# answers with that user's tasks (and their turn on a rotating chore).
|
||||||
|
- sentences:
|
||||||
|
- "what [maintenance] do I (need to|have to) do"
|
||||||
|
- "what (is|are) my (chores|tasks|maintenance [tasks])"
|
||||||
|
- "(is|are) [there] anything [assigned] for me [to do]"
|
||||||
|
- "what am I (due|responsible) for"
|
||||||
|
slots:
|
||||||
|
scope: "mine"
|
||||||
|
# Scope: the room the request came from, resolved from the satellite's
|
||||||
|
# area — so a wall tablet answers for where it is standing.
|
||||||
|
- sentences:
|
||||||
|
- "what needs (doing|maintenance|servicing) (in here|here)"
|
||||||
|
- "what maintenance is due (in here|here|in this room)"
|
||||||
|
- "is [there] anything [to do] (in here|in this room)"
|
||||||
|
slots:
|
||||||
|
scope: "here"
|
||||||
|
MaintenanceSupporterCompleteTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "complete [the] [maintenance] [task] {task_name:name}"
|
||||||
|
- "mark [the] [maintenance] [task] {task_name:name} [as] (done|completed)"
|
||||||
|
- "I (did|finished) [the] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskInstructions:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "how do I (do|perform) [the] {task_name:name}"
|
||||||
|
- "(instructions|guidance) for [the] {task_name:name}"
|
||||||
|
- "what do I need for [the] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskDue:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "when is [the] {task_name:name} due"
|
||||||
|
- "when do I (need|have) to (do|perform) [the] {task_name:name}"
|
||||||
|
MaintenanceSupporterSnoozeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "snooze [the] [maintenance] [task] {task_name:name}"
|
||||||
|
- "(mute|silence) [the] reminders for [the] {task_name:name}"
|
||||||
|
MaintenanceSupporterPartStock:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "how (many|much) {part_name:name} (do we have|are left|is left)"
|
||||||
|
- "what is the stock of [the] {part_name:name}"
|
||||||
|
MaintenanceSupporterPostponeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "postpone [the] {part_name:name} by {days} day[s]"
|
||||||
|
- "push [the] {part_name:name} back [by] {days} day[s]"
|
||||||
|
- "delay [the] {part_name:name} [by] {days} day[s]"
|
||||||
|
- sentences:
|
||||||
|
- "postpone [the] {part_name:name} by a week"
|
||||||
|
- "push [the] {part_name:name} back [by] a week"
|
||||||
|
slots:
|
||||||
|
days: 7
|
||||||
|
MaintenanceSupporterSkipTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "skip [the] {part_name:name} [this time]"
|
||||||
|
- "skip this (cycle|round) of [the] {part_name:name}"
|
||||||
|
lists:
|
||||||
|
# NOT called 'name': that is Home Assistant's built-in list of exposed
|
||||||
|
# ENTITY names, and the default agent resolves it against the registry
|
||||||
|
# before the handler runs — every sentence using it answered 'I am not
|
||||||
|
# aware of any device called ...' instead of reaching us. The
|
||||||
|
# {list:slot} alias keeps the value arriving in the 'name' slot.
|
||||||
|
task_name:
|
||||||
|
wildcard: true
|
||||||
|
part_name:
|
||||||
|
wildcard: true
|
||||||
|
days:
|
||||||
|
range:
|
||||||
|
from: 1
|
||||||
|
to: 365
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
# Frases de Assist para Maintenance Supporter (español).
|
||||||
|
#
|
||||||
|
# No hace falta copiar este archivo a mano: activa Ajustes -> General ->
|
||||||
|
# «Instalar las frases de Assist» y la integración lo escribe en
|
||||||
|
# config/custom_sentences/es/maintenance_supporter.yaml y recarga el agente de
|
||||||
|
# conversación. Ese es el único directorio del que el agente clásico (sin LLM)
|
||||||
|
# lee sus frases. Las canalizaciones de Assist basadas en un LLM no necesitan
|
||||||
|
# nada de esto: reciben las intenciones como herramientas.
|
||||||
|
#
|
||||||
|
# Puedes editar tu copia: en cuanto su contenido deje de coincidir con lo que
|
||||||
|
# escribimos, las actualizaciones ya no la tocan (y desactivar el ajuste
|
||||||
|
# tampoco la borra).
|
||||||
|
language: "es"
|
||||||
|
intents:
|
||||||
|
MaintenanceSupporterListTasks:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "qué mantenimiento (toca|hay que hacer|está pendiente)"
|
||||||
|
- "qué (tareas|mantenimientos) [de mantenimiento] (hay|están) pendientes"
|
||||||
|
- "hay (algo|algún mantenimiento) pendiente"
|
||||||
|
- "qué hay que (revisar|mantener)"
|
||||||
|
# Ámbito: quien pregunta. HA le indica al gestor quién ha hablado, así
|
||||||
|
# que esto responde con SUS tareas (incluido su turno en la rotación).
|
||||||
|
- sentences:
|
||||||
|
- "qué me toca [a mí] [hacer]"
|
||||||
|
- "qué tengo que hacer [yo]"
|
||||||
|
- "cuáles son mis (tareas|mantenimientos)"
|
||||||
|
- "tengo algo pendiente"
|
||||||
|
slots:
|
||||||
|
scope: "mine"
|
||||||
|
# Ámbito: la habitación desde la que se pregunta, deducida de la zona del
|
||||||
|
# satélite — así una tableta de pared responde por su propia habitación.
|
||||||
|
- sentences:
|
||||||
|
- "qué hay que hacer aquí"
|
||||||
|
- "qué mantenimiento (toca|hay) (aquí|en esta habitación)"
|
||||||
|
- "hay algo pendiente (aquí|en esta habitación)"
|
||||||
|
slots:
|
||||||
|
scope: "here"
|
||||||
|
MaintenanceSupporterCompleteTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "[ya] he (hecho|terminado|completado) [el|la|los|las] {task_name:name}"
|
||||||
|
- "marca [el|la|los|las] {task_name:name} como (hecho|hecha|terminado|terminada|completado|completada)"
|
||||||
|
MaintenanceSupporterTaskInstructions:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "cómo (hago|se hace) [el|la|los|las] {task_name:name}"
|
||||||
|
- "(instrucciones|indicaciones) para [el|la|los|las] {task_name:name}"
|
||||||
|
- "qué necesito para [el|la|los|las] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskDue:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "cuándo toca [el|la|los|las] {task_name:name}"
|
||||||
|
- "cuándo (hay que|tengo que) hacer [el|la|los|las] {task_name:name}"
|
||||||
|
MaintenanceSupporterSnoozeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "(silencia|pausa) [el|la|los|las] {task_name:name}"
|
||||||
|
- "(silencia|pausa) los avisos (de|del|de la) {task_name:name}"
|
||||||
|
MaintenanceSupporterPartStock:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "cuántos {part_name:name} (nos quedan|tenemos|quedan)"
|
||||||
|
- "cuánto stock (hay|tenemos) de {part_name:name}"
|
||||||
|
MaintenanceSupporterPostponeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "(aplaza|retrasa|pospón) [el|la|los|las] {task_name:name} {days} día[s]"
|
||||||
|
- "deja [el|la|los|las] {task_name:name} para dentro de {days} día[s]"
|
||||||
|
- sentences:
|
||||||
|
- "(aplaza|retrasa|pospón) [el|la|los|las] {task_name:name} una semana"
|
||||||
|
slots:
|
||||||
|
days: 7
|
||||||
|
MaintenanceSupporterSkipTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "(salta|sáltate) [el|la|los|las] {task_name:name} [esta vez]"
|
||||||
|
- "(salta|sáltate) esta (ronda|vuelta) (de|del|de la|de los|de las) {task_name:name}"
|
||||||
|
lists:
|
||||||
|
# NO uses «name»: es la lista integrada de nombres de ENTIDADES de Home
|
||||||
|
# Assistant, que el agente por defecto resuelve antes de llamar al gestor —
|
||||||
|
# cualquier frase que la usara respondía «no conozco ningún dispositivo…» en
|
||||||
|
# vez de llegar hasta nosotros. El alias {lista:slot} mantiene el valor en el
|
||||||
|
# slot «name».
|
||||||
|
task_name:
|
||||||
|
wildcard: true
|
||||||
|
part_name:
|
||||||
|
wildcard: true
|
||||||
|
days:
|
||||||
|
range:
|
||||||
|
from: 1
|
||||||
|
to: 365
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
# Phrases Assist pour Maintenance Supporter (français).
|
||||||
|
#
|
||||||
|
# Pas besoin de copier ce fichier à la main : activez Paramètres -> Général ->
|
||||||
|
# « Installer les phrases Assist » et l'intégration l'écrit dans
|
||||||
|
# config/custom_sentences/fr/maintenance_supporter.yaml puis recharge l'agent
|
||||||
|
# conversationnel. C'est le seul dossier où l'agent classique (non-LLM) lit ses
|
||||||
|
# phrases. Les pipelines Assist basées sur un LLM n'en ont pas besoin : elles
|
||||||
|
# récupèrent les intentions comme outils.
|
||||||
|
#
|
||||||
|
# Vous pouvez modifier votre copie : dès que son contenu ne correspond plus à
|
||||||
|
# ce que nous avons écrit, les mises à jour n'y touchent plus (et désactiver le
|
||||||
|
# réglage ne la supprime pas non plus).
|
||||||
|
language: "fr"
|
||||||
|
intents:
|
||||||
|
MaintenanceSupporterListTasks:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "quel[le]s (entretien|entretiens|maintenances|tâches) (est|sont) (dû|due|dues|prévus|prévues)"
|
||||||
|
- "qu'est-ce qui est à (faire|entretenir)"
|
||||||
|
- "y a-t-il [de] l'entretien à faire"
|
||||||
|
# Portée : la personne qui parle. HA transmet au gestionnaire qui a parlé,
|
||||||
|
# donc ceci répond avec SES tâches (y compris son tour de rotation).
|
||||||
|
- sentences:
|
||||||
|
- "qu'est-ce que je dois faire"
|
||||||
|
- "quelles sont mes tâches"
|
||||||
|
- "c'est à moi de faire quelque chose"
|
||||||
|
slots:
|
||||||
|
scope: "mine"
|
||||||
|
# Portée : la pièce d'où vient la demande, résolue via la zone du
|
||||||
|
# satellite — une tablette murale répond ainsi pour sa propre pièce.
|
||||||
|
- sentences:
|
||||||
|
- "qu'est-ce qu'il y a à faire ici"
|
||||||
|
- "quel entretien est (dû|prévu) (ici|dans cette pièce)"
|
||||||
|
slots:
|
||||||
|
scope: "here"
|
||||||
|
MaintenanceSupporterCompleteTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "j'ai (fait|terminé|fini) [le|la|les|l'] {task_name:name}"
|
||||||
|
- "marque [le|la|les|l'] {task_name:name} comme (fait|faite|terminé|terminée)"
|
||||||
|
MaintenanceSupporterTaskInstructions:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "comment (faire|je fais) [le|la|les|l'] {task_name:name}"
|
||||||
|
- "(instructions|consignes) pour [le|la|les|l'] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskDue:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "quand est-ce que [le|la|les|l'] {task_name:name} est (dû|due|prévu|prévue)"
|
||||||
|
- "quand faut-il faire [le|la|les|l'] {task_name:name}"
|
||||||
|
MaintenanceSupporterSnoozeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "mets [le|la|les|l'] {task_name:name} en pause"
|
||||||
|
MaintenanceSupporterPartStock:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "combien de {part_name:name} (reste-t-il|il reste|avons-nous)"
|
||||||
|
MaintenanceSupporterPostponeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "reporte [le|la|les|l'] {task_name:name} de {days} jour[s]"
|
||||||
|
- "repousse [le|la|les|l'] {task_name:name} de {days} jour[s]"
|
||||||
|
- sentences:
|
||||||
|
- "reporte [le|la|les|l'] {task_name:name} d'une semaine"
|
||||||
|
- "repousse [le|la|les|l'] {task_name:name} d'une semaine"
|
||||||
|
slots:
|
||||||
|
days: 7
|
||||||
|
MaintenanceSupporterSkipTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "(saute|passe) [le|la|les|l'] {task_name:name} [cette fois]"
|
||||||
|
lists:
|
||||||
|
# PAS « name » : c'est la liste intégrée des noms d'ENTITÉS de Home Assistant,
|
||||||
|
# que l'agent par défaut résout avant d'appeler le gestionnaire — toute phrase
|
||||||
|
# l'utilisant répondait « je ne connais aucun appareil… » au lieu de nous
|
||||||
|
# atteindre. L'alias {liste:slot} garde la valeur dans le slot « name ».
|
||||||
|
task_name:
|
||||||
|
wildcard: true
|
||||||
|
part_name:
|
||||||
|
wildcard: true
|
||||||
|
days:
|
||||||
|
range:
|
||||||
|
from: 1
|
||||||
|
to: 365
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
# Frasi Assist per Maintenance Supporter (italiano).
|
||||||
|
#
|
||||||
|
# Non serve copiare questo file a mano: attiva Impostazioni -> Generale ->
|
||||||
|
# «Installa le frasi di Assist» e l'integrazione lo scrive in
|
||||||
|
# config/custom_sentences/it/maintenance_supporter.yaml e ricarica l'agente
|
||||||
|
# conversazionale. È l'unica cartella da cui l'agente classico (non LLM) legge
|
||||||
|
# le sue frasi. Le pipeline Assist basate su LLM non ne hanno bisogno: ricevono
|
||||||
|
# gli intent automaticamente come strumenti.
|
||||||
|
#
|
||||||
|
# Modificare la propria copia è previsto: appena il contenuto non corrisponde
|
||||||
|
# più a quello che abbiamo scritto, gli aggiornamenti non lo toccano più (e
|
||||||
|
# nemmeno disattivare l'impostazione lo cancella).
|
||||||
|
language: "it"
|
||||||
|
intents:
|
||||||
|
MaintenanceSupporterListTasks:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "quale manutenzione (è in scadenza|serve|va fatta)"
|
||||||
|
- "quali manutenzioni (sono|ci sono) in scadenza"
|
||||||
|
- "cosa c'è da fare"
|
||||||
|
- "c'è [qualche] manutenzione da fare"
|
||||||
|
- "cosa bisogna (fare|controllare)"
|
||||||
|
# Ambito: chi sta parlando. HA passa al gestore chi ha parlato, quindi
|
||||||
|
# questo risponde con le SUE attività (incluso il suo turno di rotazione).
|
||||||
|
- sentences:
|
||||||
|
- "cosa devo fare [io]"
|
||||||
|
- "quali sono i miei (compiti|lavori|impegni)"
|
||||||
|
- "tocca a me [fare qualcosa]"
|
||||||
|
- "ho qualcosa da fare"
|
||||||
|
slots:
|
||||||
|
scope: "mine"
|
||||||
|
# Ambito: la stanza da cui arriva la richiesta, ricavata dall'area del
|
||||||
|
# satellite — così un tablet a muro risponde per la stanza in cui si trova.
|
||||||
|
- sentences:
|
||||||
|
- "cosa c'è da fare (qui|in questa stanza)"
|
||||||
|
- "quale manutenzione serve (qui|in questa stanza)"
|
||||||
|
- "c'è qualcosa da fare (qui|in questa stanza)"
|
||||||
|
slots:
|
||||||
|
scope: "here"
|
||||||
|
MaintenanceSupporterCompleteTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "ho (fatto|finito|completato) [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
- "segna [il|lo|la|l'|i|gli|le] {task_name:name} come (fatto|fatta|completato|completata)"
|
||||||
|
MaintenanceSupporterTaskInstructions:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "come (faccio|si fa) [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
- "(istruzioni|indicazioni) per [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
- "cosa mi serve per [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskDue:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "quando (scade|va fatto|va fatta) [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
- "quando devo fare [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
MaintenanceSupporterSnoozeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "(silenzia|metti in pausa) [il|lo|la|l'|i|gli|le] {task_name:name}"
|
||||||
|
- "(silenzia|sospendi) i promemoria (di|del|della|dei|delle|per) {task_name:name}"
|
||||||
|
MaintenanceSupporterPartStock:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "quanti {part_name:name} (abbiamo|ci sono|restano)"
|
||||||
|
- "quante scorte di {part_name:name} (abbiamo|ci sono)"
|
||||||
|
MaintenanceSupporterPostponeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "(rimanda|rinvia|posticipa) [il|lo|la|l'|i|gli|le] {task_name:name} di {days} (giorno|giorni)"
|
||||||
|
- sentences:
|
||||||
|
- "(rimanda|rinvia|posticipa) [il|lo|la|l'|i|gli|le] {task_name:name} di una settimana"
|
||||||
|
slots:
|
||||||
|
days: 7
|
||||||
|
MaintenanceSupporterSkipTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "salta [il|lo|la|l'|i|gli|le] {task_name:name} [per questa volta]"
|
||||||
|
- "salta questo giro (di|del|della|dei|delle) {task_name:name}"
|
||||||
|
lists:
|
||||||
|
# NON «name»: è la lista integrata dei nomi delle ENTITÀ di Home Assistant,
|
||||||
|
# che l'agente predefinito risolve prima di chiamare il gestore — ogni frase
|
||||||
|
# che la usava rispondeva «non conosco nessun dispositivo…» invece di
|
||||||
|
# arrivare fino a noi. L'alias {lista:slot} fa comunque arrivare il valore
|
||||||
|
# nello slot «name».
|
||||||
|
task_name:
|
||||||
|
wildcard: true
|
||||||
|
part_name:
|
||||||
|
wildcard: true
|
||||||
|
days:
|
||||||
|
range:
|
||||||
|
from: 1
|
||||||
|
to: 365
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
# Assist-zinnen voor Maintenance Supporter (Nederlands).
|
||||||
|
#
|
||||||
|
# Handmatig kopiëren hoeft niet: zet Instellingen -> Algemeen ->
|
||||||
|
# "Assist-zinnen installeren" aan, dan schrijft de integratie dit bestand naar
|
||||||
|
# config/custom_sentences/nl/maintenance_supporter.yaml en herlaadt de
|
||||||
|
# gespreksagent. Alleen uit die map leest de klassieke (niet-LLM) agent zijn
|
||||||
|
# zinnen. Op een LLM gebaseerde Assist-pijplijnen hebben dit niet nodig: die
|
||||||
|
# krijgen de intents automatisch als tools.
|
||||||
|
#
|
||||||
|
# Je eigen kopie aanpassen mag: zodra de inhoud niet meer overeenkomt met wat
|
||||||
|
# wij geschreven hebben, blijven updates ervan af (en de instelling weer
|
||||||
|
# uitzetten verwijdert hem ook niet).
|
||||||
|
language: "nl"
|
||||||
|
intents:
|
||||||
|
MaintenanceSupporterListTasks:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "welk onderhoud (staat open|moet er gebeuren|is er nodig)"
|
||||||
|
- "wat moet er onderhouden worden"
|
||||||
|
- "is er [nog] onderhoud te doen"
|
||||||
|
- "welke (klusjes|klussen|taken) staan open"
|
||||||
|
# Bereik: degene die vraagt. HA geeft aan de handler door wie er sprak,
|
||||||
|
# dus dit antwoordt met DIENS taken (inclusief zijn beurt in de rotatie).
|
||||||
|
- sentences:
|
||||||
|
- "wat moet ik [nog] doen"
|
||||||
|
- "wat zijn mijn (taken|klusjes|klussen)"
|
||||||
|
- "ben ik aan de beurt"
|
||||||
|
- "heb ik [nog] (iets|wat) te doen"
|
||||||
|
slots:
|
||||||
|
scope: "mine"
|
||||||
|
# Bereik: de kamer waaruit gevraagd wordt, afgeleid uit het gebied van de
|
||||||
|
# satelliet — zo antwoordt een wandtablet voor zijn eigen kamer.
|
||||||
|
- sentences:
|
||||||
|
- "wat moet er hier gebeuren"
|
||||||
|
- "welk onderhoud is (hier|in deze kamer) nodig"
|
||||||
|
- "is hier [nog] (iets|wat) te doen"
|
||||||
|
slots:
|
||||||
|
scope: "here"
|
||||||
|
MaintenanceSupporterCompleteTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "ik heb [de|het] {task_name:name} (gedaan|afgerond)"
|
||||||
|
- "markeer [de|het] {task_name:name} als (gedaan|klaar|afgerond)"
|
||||||
|
- "[de|het] {task_name:name} is (klaar|gedaan)"
|
||||||
|
MaintenanceSupporterTaskInstructions:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "hoe doe ik [de|het] {task_name:name}"
|
||||||
|
- "(instructies|uitleg) voor [de|het] {task_name:name}"
|
||||||
|
- "wat heb ik nodig voor [de|het] {task_name:name}"
|
||||||
|
MaintenanceSupporterTaskDue:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "wanneer moet [de|het] {task_name:name} (gebeuren|gedaan worden)"
|
||||||
|
- "wanneer is [de|het] {task_name:name} aan de beurt"
|
||||||
|
MaintenanceSupporterSnoozeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "zet [de|het] {task_name:name} op stil"
|
||||||
|
- "(pauzeer|stop) de herinneringen voor [de|het] {task_name:name}"
|
||||||
|
MaintenanceSupporterPartStock:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "hoeveel {part_name:name} hebben we [nog]"
|
||||||
|
- "hoeveel {part_name:name} (is|zijn) er nog"
|
||||||
|
- "wat is de voorraad [van] [de|het] {part_name:name}"
|
||||||
|
MaintenanceSupporterPostponeTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "stel [de|het] {task_name:name} {days} dag[en] uit"
|
||||||
|
- "schuif [de|het] {task_name:name} {days} dag[en] op"
|
||||||
|
- "verplaats [de|het] {task_name:name} met {days} dag[en]"
|
||||||
|
- sentences:
|
||||||
|
- "stel [de|het] {task_name:name} een week uit"
|
||||||
|
- "schuif [de|het] {task_name:name} een week op"
|
||||||
|
slots:
|
||||||
|
days: 7
|
||||||
|
MaintenanceSupporterSkipTask:
|
||||||
|
data:
|
||||||
|
- sentences:
|
||||||
|
- "sla [de|het] {task_name:name} [deze keer] over"
|
||||||
|
- "sla deze (ronde|beurt) van [de|het] {task_name:name} over"
|
||||||
|
lists:
|
||||||
|
# NIET "name": dat is de ingebouwde lijst met ENTITEITSnamen van Home
|
||||||
|
# Assistant, die de standaardagent al oplost voordat onze handler draait —
|
||||||
|
# elke zin die hem gebruikte antwoordde "ik ken geen apparaat dat zo heet…"
|
||||||
|
# in plaats van ons te bereiken. Het alias {lijst:slot} laat de waarde
|
||||||
|
# alsnog in het slot "name" aankomen.
|
||||||
|
task_name:
|
||||||
|
wildcard: true
|
||||||
|
part_name:
|
||||||
|
wildcard: true
|
||||||
|
days:
|
||||||
|
range:
|
||||||
|
from: 1
|
||||||
|
to: 365
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Všechno je v pořádku — žádná údržba nevyžaduje pozornost.",
|
||||||
|
"none_due_mine": "Tobě teď není přiřazeno nic.",
|
||||||
|
"none_due_here": "V této místnosti nevyžaduje údržbu nic.",
|
||||||
|
"unknown_user": "Nevím, kdo se ptá, takže nemůžu určit, které úkoly jsou tvoje.",
|
||||||
|
"unknown_area": "Nevím, ve které místnosti je toto zařízení — nejdřív ho přiřaď k oblasti.",
|
||||||
|
"tasks_due": "Pozornost vyžadují tyto úkoly údržby, celkem {count}: {items}.",
|
||||||
|
"task_due_one": "Pozornost vyžaduje jeden úkol údržby: {items}.",
|
||||||
|
"completed": "Úkol '{task}' u zařízení {object} je zapsaný jako hotový.",
|
||||||
|
"postponed": "Úkol '{task}' u zařízení {object} je odložený na {date}.",
|
||||||
|
"postpone_needs_when": "Řekni mi, o kolik ho mám odložit — třeba o pět dní.",
|
||||||
|
"postpone_past": "Tím by '{task}' spadl do minulosti.",
|
||||||
|
"skipped": "Tento cyklus úkolu '{task}' u zařízení {object} je přeskočený. Další termín je {date}.",
|
||||||
|
"not_found": "Nenašel jsem úkol údržby, který by odpovídal '{name}'.",
|
||||||
|
"ambiguous": "Tomu odpovídá víc úkolů: {candidates}. Upřesni to, prosím.",
|
||||||
|
"too_early": "Úkol '{task}' se dá dokončit až blíž k termínu.",
|
||||||
|
"st_overdue": "zpoždění {days} dní",
|
||||||
|
"st_overdue_one": "zpoždění jeden den",
|
||||||
|
"st_due_today": "termín dnes",
|
||||||
|
"st_due_in": "termín do {days} dní",
|
||||||
|
"st_due_in_one": "termín zítra",
|
||||||
|
"st_triggered": "spuštěno",
|
||||||
|
"item_on": "{task} — {object}",
|
||||||
|
"due_date_suffix": " Další termín je {date}.",
|
||||||
|
"guide_header": "Uložené informace k úkolu '{task}' u zařízení {object}: {segments}.",
|
||||||
|
"guide_none": "K úkolu '{task}' u zařízení {object} nejsou uložené žádné pokyny, dokumenty ani náhradní díly. Můžu místo toho dát obecné, neověřené rady — chceš?",
|
||||||
|
"guide_notes": "poznámky: {notes}",
|
||||||
|
"guide_checklist": "kroky kontrolního seznamu, celkem {count}: {steps}",
|
||||||
|
"guide_doc": "propojený dokument '{title}'",
|
||||||
|
"guide_doc_page": "propojený dokument '{title}', strana {page}",
|
||||||
|
"guide_url": "je uložený odkaz na dokumentaci",
|
||||||
|
"guide_part": "potřeba: {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "místo uložení: {loc}",
|
||||||
|
"guide_part_stock": "na skladě: {stock}",
|
||||||
|
"snoozed": "Připomínky k úkolu '{task}' u zařízení {object} jsou ztlumené po dobu {hours} hodin.",
|
||||||
|
"snooze_unavailable": "Oznámení nejsou nastavená, takže není co ztlumit.",
|
||||||
|
"stock_line": "{stock} × {part} na skladě{loc}{low}.",
|
||||||
|
"stock_loc": " (místo uložení: {loc})",
|
||||||
|
"stock_low": " — na úrovni objednacího limitu nebo pod ním",
|
||||||
|
"stock_untracked": "{part} — u tohoto dílu sklad nesleduju.",
|
||||||
|
"part_not_found": "Nenašel jsem náhradní díl, který by odpovídal '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Alt er i orden — der er ingen vedligeholdelse, der kræver opmærksomhed.",
|
||||||
|
"none_due_mine": "Der er ikke noget tildelt dig lige nu.",
|
||||||
|
"none_due_here": "Der skal ikke laves vedligeholdelse i det her rum.",
|
||||||
|
"unknown_user": "Jeg ved ikke, hvem der spørger, så jeg kan ikke sige, hvilke opgaver der er dine.",
|
||||||
|
"unknown_area": "Jeg ved ikke, hvilket rum den her enhed står i — knyt den til et område først.",
|
||||||
|
"tasks_due": "{count} vedligeholdelsesopgaver kræver opmærksomhed: {items}.",
|
||||||
|
"task_due_one": "Én vedligeholdelsesopgave kræver opmærksomhed: {items}.",
|
||||||
|
"completed": "Jeg har markeret '{task}' på {object} som udført.",
|
||||||
|
"postponed": "Jeg har udskudt '{task}' på {object} til den {date}.",
|
||||||
|
"postpone_needs_when": "Sig, hvor langt jeg skal udskyde den — for eksempel fem dage.",
|
||||||
|
"postpone_past": "Så ville '{task}' ligge i fortiden.",
|
||||||
|
"skipped": "Jeg har sprunget denne omgang af '{task}' på {object} over. Næste omgang skal laves den {date}.",
|
||||||
|
"not_found": "Jeg kunne ikke finde en vedligeholdelsesopgave, der passer på '{name}'.",
|
||||||
|
"ambiguous": "Det passer på flere opgaver: {candidates}. Vær lige lidt mere præcis.",
|
||||||
|
"too_early": "'{task}' kan først markeres som udført tættere på forfaldsdatoen.",
|
||||||
|
"st_overdue": "{days} dage for sent",
|
||||||
|
"st_overdue_one": "én dag for sent",
|
||||||
|
"st_due_today": "skal laves i dag",
|
||||||
|
"st_due_in": "skal laves om {days} dage",
|
||||||
|
"st_due_in_one": "skal laves i morgen",
|
||||||
|
"st_triggered": "udløst",
|
||||||
|
"item_on": "{task} på {object}",
|
||||||
|
"due_date_suffix": " Næste gang skal det laves den {date}.",
|
||||||
|
"guide_header": "Gemte oplysninger om '{task}' på {object}: {segments}.",
|
||||||
|
"guide_none": "Der er ikke gemt nogen vejledning, dokumenter eller reservedele til '{task}' på {object}. Jeg kan i stedet give generelle, ikke-bekræftede råd — vil du have det?",
|
||||||
|
"guide_notes": "noter: {notes}",
|
||||||
|
"guide_checklist": "{count} trin på tjeklisten: {steps}",
|
||||||
|
"guide_doc": "tilknyttet dokument '{title}'",
|
||||||
|
"guide_doc_page": "tilknyttet dokument '{title}', side {page}",
|
||||||
|
"guide_url": "der er gemt et link til dokumentation",
|
||||||
|
"guide_part": "{qty} × {part} skal bruges{extras}",
|
||||||
|
"guide_part_loc": "opbevaringssted {loc}",
|
||||||
|
"guide_part_stock": "{stock} på lager",
|
||||||
|
"snoozed": "Påmindelser for '{task}' på {object} er sat på pause i {hours} timer.",
|
||||||
|
"snooze_unavailable": "Notifikationer er ikke sat op, så der er ikke noget at sætte på pause.",
|
||||||
|
"stock_line": "{stock} × {part} på lager{loc}{low}.",
|
||||||
|
"stock_loc": " (opbevaringssted {loc})",
|
||||||
|
"stock_low": " — på eller under genbestillingsgrænsen",
|
||||||
|
"stock_untracked": "Der føres ikke lager for {part}.",
|
||||||
|
"part_not_found": "Jeg kunne ikke finde en reservedel, der passer på '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Alles in Ordnung — keine Wartung fällig.",
|
||||||
|
"none_due_mine": "Dir ist gerade nichts zugewiesen.",
|
||||||
|
"none_due_here": "In diesem Raum ist keine Wartung fällig.",
|
||||||
|
"unknown_user": "Ich weiß nicht, wer fragt, und kann deine Aufgaben deshalb nicht bestimmen.",
|
||||||
|
"unknown_area": "Ich weiß nicht, in welchem Raum dieses Gerät steht — ordne es zuerst einem Bereich zu.",
|
||||||
|
"tasks_due": "{count} Wartungsaufgaben brauchen Aufmerksamkeit: {items}.",
|
||||||
|
"task_due_one": "Eine Wartungsaufgabe braucht Aufmerksamkeit: {items}.",
|
||||||
|
"completed": "'{task}' an {object} als erledigt eingetragen.",
|
||||||
|
"postponed": "'{task}' an {object} auf den {date} verschoben.",
|
||||||
|
"postpone_needs_when": "Sag mir, um wie lange ich verschieben soll — zum Beispiel um fünf Tage.",
|
||||||
|
"postpone_past": "Damit läge '{task}' in der Vergangenheit.",
|
||||||
|
"skipped": "Dieser Durchgang von '{task}' an {object} wurde übersprungen. Der nächste ist am {date} fällig.",
|
||||||
|
"not_found": "Ich habe keine Wartungsaufgabe zu '{name}' gefunden.",
|
||||||
|
"ambiguous": "Das passt auf mehrere Aufgaben: {candidates}. Bitte formuliere genauer.",
|
||||||
|
"too_early": "'{task}' kann erst näher am Fälligkeitstermin erledigt werden.",
|
||||||
|
"st_overdue": "seit {days} Tagen überfällig",
|
||||||
|
"st_overdue_one": "seit einem Tag überfällig",
|
||||||
|
"st_due_today": "heute fällig",
|
||||||
|
"st_due_in": "fällig in {days} Tagen",
|
||||||
|
"st_due_in_one": "morgen fällig",
|
||||||
|
"st_triggered": "ausgelöst",
|
||||||
|
"item_on": "{task} an {object}",
|
||||||
|
"due_date_suffix": " Der nächste Fälligkeitstermin ist der {date}.",
|
||||||
|
"guide_header": "Hinterlegte Informationen zu '{task}' an {object}: {segments}.",
|
||||||
|
"guide_none": "Zu '{task}' an {object} sind keine Anleitungen, Dokumente oder Ersatzteile hinterlegt. Ich kann stattdessen allgemeine, ungeprüfte Hinweise geben — möchtest du das?",
|
||||||
|
"guide_notes": "Notizen: {notes}",
|
||||||
|
"guide_checklist": "{count} Checklisten-Schritte: {steps}",
|
||||||
|
"guide_doc": "verknüpftes Dokument '{title}'",
|
||||||
|
"guide_doc_page": "verknüpftes Dokument '{title}', Seite {page}",
|
||||||
|
"guide_url": "ein Dokumentations-Link ist hinterlegt",
|
||||||
|
"guide_part": "{qty} × {part} benötigt{extras}",
|
||||||
|
"guide_part_loc": "Lagerort {loc}",
|
||||||
|
"guide_part_stock": "{stock} auf Lager",
|
||||||
|
"snoozed": "Erinnerungen für '{task}' an {object} für {hours} Stunden stummgeschaltet.",
|
||||||
|
"snooze_unavailable": "Benachrichtigungen sind nicht eingerichtet — es gibt nichts stummzuschalten.",
|
||||||
|
"stock_line": "{stock} × {part} auf Lager{loc}{low}.",
|
||||||
|
"stock_loc": " (Lagerort: {loc})",
|
||||||
|
"stock_low": " — an oder unter der Nachbestellgrenze",
|
||||||
|
"stock_untracked": "Für {part} wird kein Bestand geführt.",
|
||||||
|
"part_not_found": "Ich habe kein Ersatzteil zu '{name}' gefunden."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Everything is OK — no maintenance needs attention.",
|
||||||
|
"none_due_mine": "Nothing is assigned to you right now.",
|
||||||
|
"none_due_here": "Nothing needs maintenance in this room.",
|
||||||
|
"unknown_user": "I don't know who is asking, so I can't tell which tasks are yours.",
|
||||||
|
"unknown_area": "I don't know which room this device is in — assign it to an area first.",
|
||||||
|
"tasks_due": "{count} maintenance tasks need attention: {items}.",
|
||||||
|
"task_due_one": "One maintenance task needs attention: {items}.",
|
||||||
|
"completed": "Completed '{task}' on {object}.",
|
||||||
|
"postponed": "Postponed '{task}' on {object} to {date}.",
|
||||||
|
"postpone_needs_when": "Tell me how far to postpone it — for example, by five days.",
|
||||||
|
"postpone_past": "That would put '{task}' in the past.",
|
||||||
|
"skipped": "Skipped this cycle of '{task}' on {object}. The next one is due {date}.",
|
||||||
|
"not_found": "I couldn't find a maintenance task matching '{name}'.",
|
||||||
|
"ambiguous": "That matches several tasks: {candidates}. Please be more specific.",
|
||||||
|
"too_early": "'{task}' can only be completed closer to its due date.",
|
||||||
|
"st_overdue": "{days} days overdue",
|
||||||
|
"st_overdue_one": "1 day overdue",
|
||||||
|
"st_due_today": "due today",
|
||||||
|
"st_due_in": "due in {days} days",
|
||||||
|
"st_due_in_one": "due tomorrow",
|
||||||
|
"st_triggered": "triggered",
|
||||||
|
"item_on": "{task} on {object}",
|
||||||
|
"due_date_suffix": " The next due date is {date}.",
|
||||||
|
"guide_header": "Stored guidance for '{task}' on {object}: {segments}.",
|
||||||
|
"guide_none": "There are no stored instructions, documents or spare parts for '{task}' on {object}. I can offer general, non-verified advice instead — would you like that?",
|
||||||
|
"guide_notes": "notes: {notes}",
|
||||||
|
"guide_checklist": "{count} checklist steps: {steps}",
|
||||||
|
"guide_doc": "linked document '{title}'",
|
||||||
|
"guide_doc_page": "linked document '{title}', page {page}",
|
||||||
|
"guide_url": "a documentation link is on file",
|
||||||
|
"guide_part": "{qty} × {part} needed{extras}",
|
||||||
|
"guide_part_loc": "stored at {loc}",
|
||||||
|
"guide_part_stock": "{stock} in stock",
|
||||||
|
"snoozed": "Snoozed reminders for '{task}' on {object} for {hours} hours.",
|
||||||
|
"snooze_unavailable": "Notifications aren't configured, so there is nothing to snooze.",
|
||||||
|
"stock_line": "{stock} × {part} in stock{loc}{low}.",
|
||||||
|
"stock_loc": " (stored at {loc})",
|
||||||
|
"stock_low": " — at or below the reorder threshold",
|
||||||
|
"stock_untracked": "Stock isn't tracked for {part}.",
|
||||||
|
"part_not_found": "I couldn't find a spare part matching '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Todo en orden — no hay ningún mantenimiento pendiente.",
|
||||||
|
"none_due_mine": "Ahora mismo no tienes nada asignado.",
|
||||||
|
"none_due_here": "En esta habitación no hay ningún mantenimiento pendiente.",
|
||||||
|
"unknown_user": "No sé quién me está hablando, así que no puedo decirte qué tareas son tuyas.",
|
||||||
|
"unknown_area": "No sé en qué habitación está este dispositivo — asígnalo primero a un área.",
|
||||||
|
"tasks_due": "Hay {count} tareas de mantenimiento pendientes: {items}.",
|
||||||
|
"task_due_one": "Hay una tarea de mantenimiento pendiente: {items}.",
|
||||||
|
"completed": "Hecho. He anotado '{task}' en {object}.",
|
||||||
|
"postponed": "He aplazado '{task}' en {object} al {date}.",
|
||||||
|
"postpone_needs_when": "Dime cuánto quieres aplazarlo — por ejemplo, cinco días.",
|
||||||
|
"postpone_past": "Eso dejaría '{task}' en el pasado.",
|
||||||
|
"skipped": "Me he saltado este ciclo de '{task}' en {object}. El siguiente toca el {date}.",
|
||||||
|
"not_found": "No he encontrado ninguna tarea de mantenimiento que coincida con '{name}'.",
|
||||||
|
"ambiguous": "Eso coincide con varias tareas: {candidates}. Concreta un poco más, por favor.",
|
||||||
|
"too_early": "'{task}' solo se puede completar cuando se acerque su fecha prevista.",
|
||||||
|
"st_overdue": "{days} días de retraso",
|
||||||
|
"st_overdue_one": "un día de retraso",
|
||||||
|
"st_due_today": "toca hoy",
|
||||||
|
"st_due_in": "toca en {days} días",
|
||||||
|
"st_due_in_one": "toca mañana",
|
||||||
|
"st_triggered": "se ha activado",
|
||||||
|
"item_on": "{task} en {object}",
|
||||||
|
"due_date_suffix": " La próxima fecha prevista es el {date}.",
|
||||||
|
"guide_header": "Esto es lo que hay guardado sobre '{task}' en {object}: {segments}.",
|
||||||
|
"guide_none": "No hay instrucciones, documentos ni recambios guardados para '{task}' en {object}. En su lugar puedo darte consejos generales, sin verificar. ¿Quieres que lo haga?",
|
||||||
|
"guide_notes": "notas: {notes}",
|
||||||
|
"guide_checklist": "{count} pasos de la lista: {steps}",
|
||||||
|
"guide_doc": "documento vinculado '{title}'",
|
||||||
|
"guide_doc_page": "documento vinculado '{title}', página {page}",
|
||||||
|
"guide_url": "hay guardado un enlace a la documentación",
|
||||||
|
"guide_part": "hacen falta {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "guardado en {loc}",
|
||||||
|
"guide_part_stock": "{stock} en stock",
|
||||||
|
"snoozed": "He silenciado los avisos de '{task}' en {object} durante {hours} horas.",
|
||||||
|
"snooze_unavailable": "Las notificaciones no están configuradas, así que no hay nada que silenciar.",
|
||||||
|
"stock_line": "{stock} × {part} en stock{loc}{low}.",
|
||||||
|
"stock_loc": " (guardado en {loc})",
|
||||||
|
"stock_low": " — en el umbral de reposición o por debajo",
|
||||||
|
"stock_untracked": "De {part} no se lleva control de stock.",
|
||||||
|
"part_not_found": "No he encontrado ningún recambio que coincida con '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Kaikki on kunnossa — mikään huolto ei vaadi huomiota.",
|
||||||
|
"none_due_mine": "Sinulle ei ole juuri nyt osoitettu mitään.",
|
||||||
|
"none_due_here": "Tässä huoneessa ei ole mitään huollettavaa.",
|
||||||
|
"unknown_user": "En tiedä, kuka kysyy, joten en osaa kertoa, mitkä tehtävät ovat sinun.",
|
||||||
|
"unknown_area": "En tiedä, missä huoneessa tämä laite on — liitä se ensin alueeseen.",
|
||||||
|
"tasks_due": "{count} huoltotehtävää vaatii huomiota: {items}.",
|
||||||
|
"task_due_one": "Yksi huoltotehtävä vaatii huomiota: {items}.",
|
||||||
|
"completed": "Merkitsin tehtävän '{task}' tehdyksi kohteessa {object}.",
|
||||||
|
"postponed": "Siirsin tehtävää '{task}' kohteessa {object} myöhemmäksi. Uusi ajankohta: {date}.",
|
||||||
|
"postpone_needs_when": "Kerro, kuinka paljon siirrän sitä — esimerkiksi viisi päivää.",
|
||||||
|
"postpone_past": "Silloin tehtävä '{task}' menisi menneisyyteen.",
|
||||||
|
"skipped": "Ohitin tehtävän '{task}' tämän kerran kohteessa {object}. Seuraava ajankohta: {date}.",
|
||||||
|
"not_found": "En löytänyt huoltotehtävää, joka vastaisi hakua '{name}'.",
|
||||||
|
"ambiguous": "Tämä vastaa useaa tehtävää: {candidates}. Tarkenna vielä hieman.",
|
||||||
|
"too_early": "Tehtävän '{task}' voi kuitata tehdyksi vasta lähempänä sen ajankohtaa.",
|
||||||
|
"st_overdue": "{days} päivää myöhässä",
|
||||||
|
"st_overdue_one": "päivän myöhässä",
|
||||||
|
"st_due_today": "vuorossa tänään",
|
||||||
|
"st_due_in": "vuorossa {days} päivän päästä",
|
||||||
|
"st_due_in_one": "vuorossa huomenna",
|
||||||
|
"st_triggered": "laukesi",
|
||||||
|
"item_on": "{task} – kohteessa {object}",
|
||||||
|
"due_date_suffix": " Seuraava ajankohta on {date}.",
|
||||||
|
"guide_header": "Tallennetut tiedot tehtävälle '{task}' kohteessa {object}: {segments}.",
|
||||||
|
"guide_none": "Tehtävälle '{task}' kohteessa {object} ei ole tallennettu ohjeita, dokumentteja eikä varaosia. Voin antaa sen sijaan yleisiä, varmistamattomia neuvoja — sopiiko se sinulle?",
|
||||||
|
"guide_notes": "muistiinpanot: {notes}",
|
||||||
|
"guide_checklist": "{count} tarkistuslistan kohtaa: {steps}",
|
||||||
|
"guide_doc": "linkitetty dokumentti '{title}'",
|
||||||
|
"guide_doc_page": "linkitetty dokumentti '{title}', sivu {page}",
|
||||||
|
"guide_url": "tallennettuna on linkki dokumentaatioon",
|
||||||
|
"guide_part": "tarvitaan {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "säilytyspaikka {loc}",
|
||||||
|
"guide_part_stock": "{stock} varastossa",
|
||||||
|
"snoozed": "Muistutukset tehtävästä '{task}' kohteessa {object} on vaimennettu {hours} tunniksi.",
|
||||||
|
"snooze_unavailable": "Ilmoituksia ei ole määritetty, joten vaimennettavaa ei ole.",
|
||||||
|
"stock_line": "{stock} × {part} varastossa{loc}{low}.",
|
||||||
|
"stock_loc": " (säilytyspaikka {loc})",
|
||||||
|
"stock_low": " — tilausrajalla tai sen alapuolella",
|
||||||
|
"stock_untracked": "Varastosaldoa ei seurata varaosalle {part}.",
|
||||||
|
"part_not_found": "En löytänyt varaosaa, joka vastaisi hakua '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Tout va bien — il n'y a aucun entretien à faire.",
|
||||||
|
"none_due_mine": "Rien ne t'est attribué pour le moment.",
|
||||||
|
"none_due_here": "Il n'y a aucun entretien à faire dans cette pièce.",
|
||||||
|
"unknown_user": "Je ne sais pas qui me parle, donc je ne peux pas dire quelles tâches sont les tiennes.",
|
||||||
|
"unknown_area": "Je ne sais pas dans quelle pièce se trouve cet appareil — commence par l'affecter à une zone.",
|
||||||
|
"tasks_due": "{count} tâches d'entretien demandent ton attention : {items}.",
|
||||||
|
"task_due_one": "Une tâche d'entretien demande ton attention : {items}.",
|
||||||
|
"completed": "C'est fait pour '{task}' sur {object}.",
|
||||||
|
"postponed": "J'ai reporté '{task}' sur {object} au {date}.",
|
||||||
|
"postpone_needs_when": "Dis-moi de combien je dois le reporter — par exemple, de cinq jours.",
|
||||||
|
"postpone_past": "Ça mettrait '{task}' dans le passé.",
|
||||||
|
"skipped": "J'ai sauté ce cycle de '{task}' sur {object}. Le prochain est à faire le {date}.",
|
||||||
|
"not_found": "Je n'ai pas trouvé de tâche d'entretien qui corresponde à '{name}'.",
|
||||||
|
"ambiguous": "Ça correspond à plusieurs tâches : {candidates}. Sois un peu plus précis, s'il te plaît.",
|
||||||
|
"too_early": "Tu ne pourras valider '{task}' que plus près de sa date d'échéance.",
|
||||||
|
"st_overdue": "{days} jours de retard",
|
||||||
|
"st_overdue_one": "un jour de retard",
|
||||||
|
"st_due_today": "à faire aujourd'hui",
|
||||||
|
"st_due_in": "à faire dans {days} jours",
|
||||||
|
"st_due_in_one": "à faire demain",
|
||||||
|
"st_triggered": "déclenché",
|
||||||
|
"item_on": "{task} sur {object}",
|
||||||
|
"due_date_suffix": " La prochaine échéance est le {date}.",
|
||||||
|
"guide_header": "Voilà ce qui est enregistré pour '{task}' sur {object} : {segments}.",
|
||||||
|
"guide_none": "Il n'y a ni instructions, ni documents, ni pièces détachées enregistrés pour '{task}' sur {object}. Je peux te donner des conseils généraux, non vérifiés — ça t'intéresse ?",
|
||||||
|
"guide_notes": "notes : {notes}",
|
||||||
|
"guide_checklist": "{count} étapes de la checklist : {steps}",
|
||||||
|
"guide_doc": "document lié '{title}'",
|
||||||
|
"guide_doc_page": "document lié '{title}', page {page}",
|
||||||
|
"guide_url": "un lien vers la documentation est enregistré",
|
||||||
|
"guide_part": "il faut {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "rangé à {loc}",
|
||||||
|
"guide_part_stock": "{stock} en stock",
|
||||||
|
"snoozed": "J'ai mis les rappels de '{task}' sur {object} en pause pendant {hours} heures.",
|
||||||
|
"snooze_unavailable": "Les notifications ne sont pas configurées, il n'y a donc rien à mettre en pause.",
|
||||||
|
"stock_line": "{stock} × {part} en stock{loc}{low}.",
|
||||||
|
"stock_loc": " (rangé à {loc})",
|
||||||
|
"stock_low": " — au niveau ou en dessous du seuil de réapprovisionnement",
|
||||||
|
"stock_untracked": "Le stock n'est pas suivi pour {part}.",
|
||||||
|
"part_not_found": "Je n'ai pas trouvé de pièce détachée qui corresponde à '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "सब ठीक है — किसी मेंटेनेंस पर ध्यान देने की ज़रूरत नहीं है।",
|
||||||
|
"none_due_mine": "अभी आपके नाम पर कुछ भी असाइन नहीं है।",
|
||||||
|
"none_due_here": "इस कमरे में किसी चीज़ की मेंटेनेंस बाकी नहीं है।",
|
||||||
|
"unknown_user": "मुझे नहीं पता कि कौन पूछ रहा है, इसलिए यह बताना मुश्किल है कि कौन से काम आपके हैं।",
|
||||||
|
"unknown_area": "मुझे नहीं पता कि यह डिवाइस किस कमरे में है — पहले इसे किसी एरिया में असाइन कर दीजिए।",
|
||||||
|
"tasks_due": "{count} मेंटेनेंस कामों पर ध्यान देना है: {items}।",
|
||||||
|
"task_due_one": "एक मेंटेनेंस काम पर ध्यान देना है: {items}।",
|
||||||
|
"completed": "{object} पर '{task}' को पूरा कर दिया है।",
|
||||||
|
"postponed": "{object} पर '{task}' को {date} तक टाल दिया है।",
|
||||||
|
"postpone_needs_when": "बताइए कितना टालना है — जैसे पाँच दिन।",
|
||||||
|
"postpone_past": "इससे '{task}' की तारीख़ पिछली हो जाएगी।",
|
||||||
|
"skipped": "{object} पर '{task}' का यह चक्र छोड़ दिया है। अगली बार {date} को करना है।",
|
||||||
|
"not_found": "'{name}' से मिलता-जुलता कोई मेंटेनेंस काम नहीं मिला।",
|
||||||
|
"ambiguous": "इससे कई काम मेल खाते हैं: {candidates}। थोड़ा और साफ़ बताइए।",
|
||||||
|
"too_early": "'{task}' को तय तारीख़ के क़रीब आने पर ही पूरा किया जा सकता है।",
|
||||||
|
"st_overdue": "{days} दिन की देरी",
|
||||||
|
"st_overdue_one": "एक दिन की देरी",
|
||||||
|
"st_due_today": "आज होना है",
|
||||||
|
"st_due_in": "{days} दिन में होना है",
|
||||||
|
"st_due_in_one": "कल होना है",
|
||||||
|
"st_triggered": "ट्रिगर हुआ",
|
||||||
|
"item_on": "{object} पर {task}",
|
||||||
|
"due_date_suffix": " अगली तारीख़ {date} है।",
|
||||||
|
"guide_header": "{object} पर '{task}' के लिए सहेजी गई जानकारी: {segments}।",
|
||||||
|
"guide_none": "{object} पर '{task}' के लिए कोई निर्देश, दस्तावेज़ या स्पेयर पार्ट सहेजा नहीं गया है। इसके बदले आम, बिना जाँची हुई सलाह दी जा सकती है — क्या आप चाहेंगे?",
|
||||||
|
"guide_notes": "नोट्स: {notes}",
|
||||||
|
"guide_checklist": "चेकलिस्ट के {count} चरण: {steps}",
|
||||||
|
"guide_doc": "जुड़ा हुआ दस्तावेज़ '{title}'",
|
||||||
|
"guide_doc_page": "जुड़ा हुआ दस्तावेज़ '{title}', पेज {page}",
|
||||||
|
"guide_url": "एक दस्तावेज़ लिंक सहेजा हुआ है",
|
||||||
|
"guide_part": "{qty} × {part} चाहिए{extras}",
|
||||||
|
"guide_part_loc": "रखने की जगह: {loc}",
|
||||||
|
"guide_part_stock": "स्टॉक में {stock}",
|
||||||
|
"snoozed": "{object} पर '{task}' के रिमाइंडर {hours} घंटे के लिए बंद कर दिए हैं।",
|
||||||
|
"snooze_unavailable": "नोटिफ़िकेशन सेट नहीं हैं, इसलिए बंद करने के लिए कुछ है ही नहीं।",
|
||||||
|
"stock_line": "स्टॉक: {stock} × {part}{loc}{low}।",
|
||||||
|
"stock_loc": " (रखने की जगह: {loc})",
|
||||||
|
"stock_low": " — दोबारा ऑर्डर करने की सीमा पर या उससे नीचे",
|
||||||
|
"stock_untracked": "{part} के लिए स्टॉक ट्रैक नहीं किया जाता।",
|
||||||
|
"part_not_found": "'{name}' से मिलता-जुलता कोई स्पेयर पार्ट नहीं मिला।"
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Minden rendben — nincs esedékes karbantartás.",
|
||||||
|
"none_due_mine": "Jelenleg nincs hozzád rendelve semmi.",
|
||||||
|
"none_due_here": "Ebben a szobában nincs esedékes karbantartás.",
|
||||||
|
"unknown_user": "Nem tudom, ki kérdez, ezért nem tudom megmondani, melyik feladat a tiéd.",
|
||||||
|
"unknown_area": "Nem tudom, melyik szobában van ez az eszköz — rendeld hozzá előbb egy területhez.",
|
||||||
|
"tasks_due": "{count} karbantartási feladat esedékes: {items}.",
|
||||||
|
"task_due_one": "Egy karbantartási feladat esedékes: {items}.",
|
||||||
|
"completed": "Elvégzettnek jelöltem a feladatot: '{task}' – {object}.",
|
||||||
|
"postponed": "Elhalasztottam ezt a feladatot: '{task}' – {object}. Az új időpont: {date}.",
|
||||||
|
"postpone_needs_when": "Mondd meg, mennyivel halasszam el — például öt nappal.",
|
||||||
|
"postpone_past": "'{task}': ezzel a feladat a múltba kerülne.",
|
||||||
|
"skipped": "Kihagytam ezt a fordulót: '{task}' – {object}. A következő időpont: {date}.",
|
||||||
|
"not_found": "Nem találtam ehhez illő karbantartási feladatot: '{name}'.",
|
||||||
|
"ambiguous": "Több feladatra is illik: {candidates}. Fogalmazz pontosabban.",
|
||||||
|
"too_early": "'{task}': ezt a feladatot csak az esedékesség közelében lehet elvégezni.",
|
||||||
|
"st_overdue": "{days} napja késésben",
|
||||||
|
"st_overdue_one": "egy napja késésben",
|
||||||
|
"st_due_today": "ma esedékes",
|
||||||
|
"st_due_in": "{days} nap múlva esedékes",
|
||||||
|
"st_due_in_one": "holnap esedékes",
|
||||||
|
"st_triggered": "aktiválódott",
|
||||||
|
"item_on": "{task} – {object}",
|
||||||
|
"due_date_suffix": " A következő esedékesség: {date}.",
|
||||||
|
"guide_header": "'{task}' – {object}. A mentett információk: {segments}.",
|
||||||
|
"guide_none": "Nincsenek mentett útmutatók, dokumentumok vagy alkatrészek ehhez: '{task}' – {object}. Helyette tudok általános, nem ellenőrzött tanácsot adni — kéred?",
|
||||||
|
"guide_notes": "jegyzetek: {notes}",
|
||||||
|
"guide_checklist": "{count} lépés az ellenőrzőlistán: {steps}",
|
||||||
|
"guide_doc": "'{title}' című csatolt dokumentum",
|
||||||
|
"guide_doc_page": "'{title}' című csatolt dokumentum, {page}. oldal",
|
||||||
|
"guide_url": "el van mentve egy dokumentációs link",
|
||||||
|
"guide_part": "{qty} × {part} szükséges{extras}",
|
||||||
|
"guide_part_loc": "tárolási hely: {loc}",
|
||||||
|
"guide_part_stock": "{stock} van készleten",
|
||||||
|
"snoozed": "'{task}' – {object}: {hours} órára elnémítottam az emlékeztetőket.",
|
||||||
|
"snooze_unavailable": "Nincsenek beállítva értesítések, így nincs mit elnémítani.",
|
||||||
|
"stock_line": "{stock} × {part} van készleten{loc}{low}.",
|
||||||
|
"stock_loc": " (tárolási hely: {loc})",
|
||||||
|
"stock_low": " — az újrarendelési küszöbön vagy alatta",
|
||||||
|
"stock_untracked": "Ehhez nincs készletnyilvántartás: {part}.",
|
||||||
|
"part_not_found": "Nem találtam ehhez illő alkatrészt: '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Tutto a posto — non c'è nessuna manutenzione da fare.",
|
||||||
|
"none_due_mine": "Al momento non hai niente assegnato.",
|
||||||
|
"none_due_here": "In questa stanza non c'è nessuna manutenzione da fare.",
|
||||||
|
"unknown_user": "Non so chi mi sta parlando, quindi non posso dirti quali attività sono tue.",
|
||||||
|
"unknown_area": "Non so in quale stanza si trova questo dispositivo — assegnalo prima a un'area.",
|
||||||
|
"tasks_due": "Ci sono {count} attività di manutenzione da fare: {items}.",
|
||||||
|
"task_due_one": "C'è un'attività di manutenzione da fare: {items}.",
|
||||||
|
"completed": "Fatto. Ho segnato '{task}' su {object}.",
|
||||||
|
"postponed": "Ho rimandato '{task}' su {object} al {date}.",
|
||||||
|
"postpone_needs_when": "Dimmi di quanto rimandarla — per esempio, di cinque giorni.",
|
||||||
|
"postpone_past": "Così '{task}' finirebbe nel passato.",
|
||||||
|
"skipped": "Ho saltato questo ciclo di '{task}' su {object}. Il prossimo è previsto per il {date}.",
|
||||||
|
"not_found": "Non ho trovato nessuna attività di manutenzione che corrisponda a '{name}'.",
|
||||||
|
"ambiguous": "Corrisponde a più attività: {candidates}. Puoi essere un po' più preciso?",
|
||||||
|
"too_early": "Puoi completare '{task}' solo quando si avvicina la scadenza.",
|
||||||
|
"st_overdue": "{days} giorni di ritardo",
|
||||||
|
"st_overdue_one": "un giorno di ritardo",
|
||||||
|
"st_due_today": "da fare oggi",
|
||||||
|
"st_due_in": "da fare tra {days} giorni",
|
||||||
|
"st_due_in_one": "da fare domani",
|
||||||
|
"st_triggered": "attivata",
|
||||||
|
"item_on": "{task} su {object}",
|
||||||
|
"due_date_suffix": " La prossima scadenza è il {date}.",
|
||||||
|
"guide_header": "Ecco cosa è salvato per '{task}' su {object}: {segments}.",
|
||||||
|
"guide_none": "Per '{task}' su {object} non ci sono istruzioni, documenti o ricambi salvati. Posso darti dei consigli generali, non verificati — ti va?",
|
||||||
|
"guide_notes": "note: {notes}",
|
||||||
|
"guide_checklist": "{count} passaggi della checklist: {steps}",
|
||||||
|
"guide_doc": "documento collegato '{title}'",
|
||||||
|
"guide_doc_page": "documento collegato '{title}', pagina {page}",
|
||||||
|
"guide_url": "è salvato un link alla documentazione",
|
||||||
|
"guide_part": "servono {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "conservato in {loc}",
|
||||||
|
"guide_part_stock": "{stock} in magazzino",
|
||||||
|
"snoozed": "Ho messo in pausa i promemoria di '{task}' su {object} per {hours} ore.",
|
||||||
|
"snooze_unavailable": "Le notifiche non sono configurate, quindi non c'è niente da mettere in pausa.",
|
||||||
|
"stock_line": "{stock} × {part} in magazzino{loc}{low}.",
|
||||||
|
"stock_loc": " (conservato in {loc})",
|
||||||
|
"stock_low": " — pari o sotto la soglia di riordino",
|
||||||
|
"stock_untracked": "Per {part} non viene tenuta la giacenza.",
|
||||||
|
"part_not_found": "Non ho trovato nessun ricambio che corrisponda a '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "すべて順調です。対応が必要なメンテナンスはありません。",
|
||||||
|
"none_due_mine": "今のところ、あなたに割り当てられているものはありません。",
|
||||||
|
"none_due_here": "この部屋にメンテナンスが必要なものはありません。",
|
||||||
|
"unknown_user": "どなたが話しているかわからないので、どれがあなたのタスクかお伝えできません。",
|
||||||
|
"unknown_area": "この機器がどの部屋にあるかわかりません。先にエリアを割り当ててください。",
|
||||||
|
"tasks_due": "対応が必要なメンテナンスが{count}件あります:{items}。",
|
||||||
|
"task_due_one": "対応が必要なメンテナンスが1件あります:{items}。",
|
||||||
|
"completed": "{object}の「{task}」を完了にしました。",
|
||||||
|
"postponed": "{object}の「{task}」を{date}に延期しました。",
|
||||||
|
"postpone_needs_when": "どのくらい先に延ばすか教えてください。たとえば「5日」のように言ってください。",
|
||||||
|
"postpone_past": "それだと「{task}」の日付が過去になってしまいます。",
|
||||||
|
"skipped": "{object}の「{task}」の今回分をスキップしました。次回は{date}が期限です。",
|
||||||
|
"not_found": "「{name}」に一致するメンテナンスタスクは見つかりませんでした。",
|
||||||
|
"ambiguous": "いくつかのタスクが当てはまります:{candidates}。もう少し詳しく言ってください。",
|
||||||
|
"too_early": "「{task}」は期限が近づいてからでないと完了にできません。",
|
||||||
|
"st_overdue": "{days}日遅れ",
|
||||||
|
"st_overdue_one": "1日遅れ",
|
||||||
|
"st_due_today": "今日が期限",
|
||||||
|
"st_due_in": "期限まであと{days}日",
|
||||||
|
"st_due_in_one": "明日が期限",
|
||||||
|
"st_triggered": "条件成立",
|
||||||
|
"item_on": "{object}の{task}",
|
||||||
|
"due_date_suffix": "次回の期限は{date}です。",
|
||||||
|
"guide_header": "{object}の「{task}」について、次の情報が保存されています:{segments}。",
|
||||||
|
"guide_none": "{object}の「{task}」には、手順も書類も交換部品も保存されていません。代わりに一般的な、確認済みではないアドバイスならお伝えできますが、いかがですか?",
|
||||||
|
"guide_notes": "メモ:{notes}",
|
||||||
|
"guide_checklist": "チェックリスト{count}項目:{steps}",
|
||||||
|
"guide_doc": "関連書類「{title}」",
|
||||||
|
"guide_doc_page": "関連書類「{title}」の{page}ページ",
|
||||||
|
"guide_url": "説明書のリンクが保存されています",
|
||||||
|
"guide_part": "{qty} × {part}が必要{extras}",
|
||||||
|
"guide_part_loc": "保管場所は{loc}",
|
||||||
|
"guide_part_stock": "在庫は{stock}",
|
||||||
|
"snoozed": "{object}の「{task}」のリマインダーを{hours}時間、一時停止しました。",
|
||||||
|
"snooze_unavailable": "通知が設定されていないので、一時停止するものがありません。",
|
||||||
|
"stock_line": "{stock} × {part}の在庫があります{loc}{low}。",
|
||||||
|
"stock_loc": "(保管場所は{loc})",
|
||||||
|
"stock_low": "。在庫は発注の目安以下です",
|
||||||
|
"stock_untracked": "{part}の在庫は管理していません。",
|
||||||
|
"part_not_found": "「{name}」に一致する交換部品は見つかりませんでした。"
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "다 괜찮아요. 지금 챙길 정비는 없어요.",
|
||||||
|
"none_due_mine": "지금 배정된 작업은 없어요.",
|
||||||
|
"none_due_here": "이 방에는 정비가 필요한 게 없어요.",
|
||||||
|
"unknown_user": "누가 물어보는지 알 수 없어서, 어떤 작업이 배정돼 있는지 알려드릴 수 없어요.",
|
||||||
|
"unknown_area": "이 기기가 어느 방에 있는지 몰라요. 먼저 구역을 지정해 주세요.",
|
||||||
|
"tasks_due": "정비 작업 {count}개를 챙겨야 해요: {items}.",
|
||||||
|
"task_due_one": "정비 작업 하나를 챙겨야 해요: {items}.",
|
||||||
|
"completed": "{object}의 '{task}', 완료로 기록했어요.",
|
||||||
|
"postponed": "{object}의 '{task}', {date}까지 미뤘어요.",
|
||||||
|
"postpone_needs_when": "얼마나 미룰지 알려주세요. 예를 들어 '닷새 뒤'처럼요.",
|
||||||
|
"postpone_past": "그러면 '{task}' 날짜가 과거가 돼요.",
|
||||||
|
"skipped": "{object}의 '{task}', 이번 차례는 건너뛰었어요. 다음은 {date}에 예정돼 있어요.",
|
||||||
|
"not_found": "'{name}'에 맞는 정비 작업을 찾지 못했어요.",
|
||||||
|
"ambiguous": "여러 작업이 해당돼요: {candidates}. 조금 더 구체적으로 말씀해 주세요.",
|
||||||
|
"too_early": "'{task}' 작업은 예정일이 가까워져야 완료할 수 있어요.",
|
||||||
|
"st_overdue": "{days}일 지연",
|
||||||
|
"st_overdue_one": "하루 지연",
|
||||||
|
"st_due_today": "오늘 예정",
|
||||||
|
"st_due_in": "{days}일 뒤 예정",
|
||||||
|
"st_due_in_one": "내일 예정",
|
||||||
|
"st_triggered": "조건 충족",
|
||||||
|
"item_on": "{object}의 {task}",
|
||||||
|
"due_date_suffix": " 다음은 {date}에 예정돼 있어요.",
|
||||||
|
"guide_header": "{object}의 '{task}'에 저장된 정보예요: {segments}.",
|
||||||
|
"guide_none": "{object}의 '{task}'에는 저장된 안내나 문서, 예비 부품이 없어요. 대신 일반적인, 검증되지 않은 조언을 드릴 수 있는데, 들어보실래요?",
|
||||||
|
"guide_notes": "메모: {notes}",
|
||||||
|
"guide_checklist": "체크리스트 {count}단계: {steps}",
|
||||||
|
"guide_doc": "연결된 문서 '{title}'",
|
||||||
|
"guide_doc_page": "연결된 문서 '{title}' {page}쪽",
|
||||||
|
"guide_url": "설명서 링크가 저장돼 있어요",
|
||||||
|
"guide_part": "{qty} × {part} 필요{extras}",
|
||||||
|
"guide_part_loc": "보관 위치는 {loc}",
|
||||||
|
"guide_part_stock": "재고 {stock}",
|
||||||
|
"snoozed": "{object}의 '{task}' 알림을 {hours}시간 동안 미뤄뒀어요.",
|
||||||
|
"snooze_unavailable": "알림이 설정돼 있지 않아서 미뤄둘 게 없어요.",
|
||||||
|
"stock_line": "{stock} × {part} 재고가 있어요{loc}{low}.",
|
||||||
|
"stock_loc": " (보관 위치: {loc})",
|
||||||
|
"stock_low": ". 재주문 기준 이하예요",
|
||||||
|
"stock_untracked": "{part} 재고는 관리하지 않아요.",
|
||||||
|
"part_not_found": "'{name}'에 맞는 예비 부품을 찾지 못했어요."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Alt er i orden — ingenting trenger vedlikehold nå.",
|
||||||
|
"none_due_mine": "Ingenting er tildelt deg akkurat nå.",
|
||||||
|
"none_due_here": "Ingenting trenger vedlikehold i dette rommet.",
|
||||||
|
"unknown_user": "Jeg vet ikke hvem som spør, så jeg kan ikke si hvilke oppgaver som er dine.",
|
||||||
|
"unknown_area": "Jeg vet ikke hvilket rom denne enheten står i — knytt den til et område først.",
|
||||||
|
"tasks_due": "{count} vedlikeholdsoppgaver trenger oppmerksomhet: {items}.",
|
||||||
|
"task_due_one": "Én vedlikeholdsoppgave trenger oppmerksomhet: {items}.",
|
||||||
|
"completed": "Jeg har krysset av '{task}' på {object}.",
|
||||||
|
"postponed": "Jeg har utsatt '{task}' på {object} til {date}.",
|
||||||
|
"postpone_needs_when": "Si hvor langt jeg skal utsette den — for eksempel fem dager.",
|
||||||
|
"postpone_past": "Da ville '{task}' havne i fortiden.",
|
||||||
|
"skipped": "Jeg hoppet over denne runden av '{task}' på {object}. Neste runde skal gjøres {date}.",
|
||||||
|
"not_found": "Jeg fant ingen vedlikeholdsoppgave som passer med '{name}'.",
|
||||||
|
"ambiguous": "Det passer med flere oppgaver: {candidates}. Vær litt mer presis.",
|
||||||
|
"too_early": "'{task}' kan først krysses av nærmere forfallsdatoen.",
|
||||||
|
"st_overdue": "{days} dager for sent",
|
||||||
|
"st_overdue_one": "én dag for sent",
|
||||||
|
"st_due_today": "skal gjøres i dag",
|
||||||
|
"st_due_in": "skal gjøres om {days} dager",
|
||||||
|
"st_due_in_one": "skal gjøres i morgen",
|
||||||
|
"st_triggered": "utløst",
|
||||||
|
"item_on": "{task} på {object}",
|
||||||
|
"due_date_suffix": " Neste forfallsdato er {date}.",
|
||||||
|
"guide_header": "Lagret informasjon om '{task}' på {object}: {segments}.",
|
||||||
|
"guide_none": "Det er ikke lagret noen instruksjoner, dokumenter eller reservedeler for '{task}' på {object}. Jeg kan i stedet gi generelle, ubekreftede råd — vil du det?",
|
||||||
|
"guide_notes": "notater: {notes}",
|
||||||
|
"guide_checklist": "{count} punkter på sjekklisten: {steps}",
|
||||||
|
"guide_doc": "tilknyttet dokument '{title}'",
|
||||||
|
"guide_doc_page": "tilknyttet dokument '{title}', side {page}",
|
||||||
|
"guide_url": "det er lagret en lenke til dokumentasjon",
|
||||||
|
"guide_part": "{qty} × {part} trengs{extras}",
|
||||||
|
"guide_part_loc": "oppbevaringssted {loc}",
|
||||||
|
"guide_part_stock": "{stock} på lager",
|
||||||
|
"snoozed": "Påminnelser for '{task}' på {object} er satt på pause i {hours} timer.",
|
||||||
|
"snooze_unavailable": "Varsler er ikke satt opp, så det er ingenting å sette på pause.",
|
||||||
|
"stock_line": "{stock} × {part} på lager{loc}{low}.",
|
||||||
|
"stock_loc": " (oppbevaringssted {loc})",
|
||||||
|
"stock_low": " — på eller under bestillingsgrensen",
|
||||||
|
"stock_untracked": "Det føres ikke lager for {part}.",
|
||||||
|
"part_not_found": "Jeg fant ingen reservedel som passer med '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Alles in orde — er is geen onderhoud nodig.",
|
||||||
|
"none_due_mine": "Er staat op dit moment niets voor je open.",
|
||||||
|
"none_due_here": "In deze kamer is geen onderhoud nodig.",
|
||||||
|
"unknown_user": "Ik weet niet wie er vraagt, dus ik kan niet zeggen welke taken van jou zijn.",
|
||||||
|
"unknown_area": "Ik weet niet in welke kamer dit apparaat staat — wijs het eerst aan een gebied toe.",
|
||||||
|
"tasks_due": "Er zijn {count} onderhoudstaken die aandacht nodig hebben: {items}.",
|
||||||
|
"task_due_one": "Er is één onderhoudstaak die aandacht nodig heeft: {items}.",
|
||||||
|
"completed": "Gedaan. Ik heb '{task}' bij {object} afgevinkt.",
|
||||||
|
"postponed": "Ik heb '{task}' bij {object} uitgesteld naar {date}.",
|
||||||
|
"postpone_needs_when": "Zeg even hoe lang ik het moet uitstellen — bijvoorbeeld vijf dagen.",
|
||||||
|
"postpone_past": "Dan zou '{task}' in het verleden liggen.",
|
||||||
|
"skipped": "Ik heb deze ronde van '{task}' bij {object} overgeslagen. De volgende staat op {date}.",
|
||||||
|
"not_found": "Ik kon geen onderhoudstaak vinden die past bij '{name}'.",
|
||||||
|
"ambiguous": "Dat past bij meerdere taken: {candidates}. Kun je het iets preciezer zeggen?",
|
||||||
|
"too_early": "'{task}' kun je pas afvinken als de datum dichterbij is.",
|
||||||
|
"st_overdue": "{days} dagen te laat",
|
||||||
|
"st_overdue_one": "één dag te laat",
|
||||||
|
"st_due_today": "vandaag aan de beurt",
|
||||||
|
"st_due_in": "over {days} dagen aan de beurt",
|
||||||
|
"st_due_in_one": "morgen aan de beurt",
|
||||||
|
"st_triggered": "geactiveerd",
|
||||||
|
"item_on": "{task} bij {object}",
|
||||||
|
"due_date_suffix": " De volgende keer is op {date}.",
|
||||||
|
"guide_header": "Dit is er opgeslagen over '{task}' bij {object}: {segments}.",
|
||||||
|
"guide_none": "Er zijn geen instructies, documenten of onderdelen opgeslagen voor '{task}' bij {object}. Ik kan je wel algemene, niet-gecontroleerde tips geven — wil je dat?",
|
||||||
|
"guide_notes": "notities: {notes}",
|
||||||
|
"guide_checklist": "{count} stappen op de checklist: {steps}",
|
||||||
|
"guide_doc": "gekoppeld document '{title}'",
|
||||||
|
"guide_doc_page": "gekoppeld document '{title}', pagina {page}",
|
||||||
|
"guide_url": "er is een link naar de documentatie opgeslagen",
|
||||||
|
"guide_part": "je hebt {qty} × {part} nodig{extras}",
|
||||||
|
"guide_part_loc": "ligt in {loc}",
|
||||||
|
"guide_part_stock": "{stock} op voorraad",
|
||||||
|
"snoozed": "Ik heb de herinneringen voor '{task}' bij {object} {hours} uur gepauzeerd.",
|
||||||
|
"snooze_unavailable": "Meldingen zijn niet ingesteld, dus er valt niets te pauzeren.",
|
||||||
|
"stock_line": "{stock} × {part} op voorraad{loc}{low}.",
|
||||||
|
"stock_loc": " (ligt in {loc})",
|
||||||
|
"stock_low": " — op of onder de bestelgrens",
|
||||||
|
"stock_untracked": "Van {part} wordt de voorraad niet bijgehouden.",
|
||||||
|
"part_not_found": "Ik kon geen onderdeel vinden dat past bij '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Wszystko w porządku — żadna konserwacja nie wymaga uwagi.",
|
||||||
|
"none_due_mine": "W tej chwili nic nie jest do ciebie przypisane.",
|
||||||
|
"none_due_here": "W tym pomieszczeniu nic nie wymaga konserwacji.",
|
||||||
|
"unknown_user": "Nie wiem, kto pyta, więc nie mogę powiedzieć, które zadania są twoje.",
|
||||||
|
"unknown_area": "Nie wiem, w którym pomieszczeniu jest to urządzenie — najpierw przypisz je do obszaru.",
|
||||||
|
"tasks_due": "Zadania konserwacyjne wymagające uwagi, łącznie {count}: {items}.",
|
||||||
|
"task_due_one": "Jedno zadanie konserwacyjne wymaga uwagi: {items}.",
|
||||||
|
"completed": "Zadanie '{task}' na urządzeniu {object} zapisane jako wykonane.",
|
||||||
|
"postponed": "Zadanie '{task}' na urządzeniu {object} przełożone na {date}.",
|
||||||
|
"postpone_needs_when": "Powiedz mi, o ile mam przełożyć — na przykład o pięć dni.",
|
||||||
|
"postpone_past": "Wtedy '{task}' wypadłoby w przeszłości.",
|
||||||
|
"skipped": "Ten cykl zadania '{task}' na urządzeniu {object} został pominięty. Następny termin to {date}.",
|
||||||
|
"not_found": "Nie znalazłem zadania konserwacyjnego pasującego do '{name}'.",
|
||||||
|
"ambiguous": "To pasuje do kilku zadań: {candidates}. Doprecyzuj, proszę.",
|
||||||
|
"too_early": "Zadanie '{task}' można wykonać dopiero bliżej terminu.",
|
||||||
|
"st_overdue": "{days} dni po terminie",
|
||||||
|
"st_overdue_one": "jeden dzień po terminie",
|
||||||
|
"st_due_today": "termin dzisiaj",
|
||||||
|
"st_due_in": "termin za {days} dni",
|
||||||
|
"st_due_in_one": "termin jutro",
|
||||||
|
"st_triggered": "wyzwolone",
|
||||||
|
"item_on": "{task} — {object}",
|
||||||
|
"due_date_suffix": " Następny termin to {date}.",
|
||||||
|
"guide_header": "Zapisane informacje dla zadania '{task}' na urządzeniu {object}: {segments}.",
|
||||||
|
"guide_none": "Do zadania '{task}' na urządzeniu {object} nie ma zapisanych instrukcji, dokumentów ani części zamiennych. Mogę zamiast tego podać ogólne, niezweryfikowane wskazówki — chcesz?",
|
||||||
|
"guide_notes": "notatki: {notes}",
|
||||||
|
"guide_checklist": "kroki listy kontrolnej, łącznie {count}: {steps}",
|
||||||
|
"guide_doc": "powiązany dokument '{title}'",
|
||||||
|
"guide_doc_page": "powiązany dokument '{title}', strona {page}",
|
||||||
|
"guide_url": "zapisany jest link do dokumentacji",
|
||||||
|
"guide_part": "potrzebne: {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "miejsce przechowywania: {loc}",
|
||||||
|
"guide_part_stock": "w magazynie: {stock}",
|
||||||
|
"snoozed": "Przypomnienia dla zadania '{task}' na urządzeniu {object} wyciszone przez okres {hours} godzin.",
|
||||||
|
"snooze_unavailable": "Powiadomienia nie są skonfigurowane, więc nie ma czego wyciszać.",
|
||||||
|
"stock_line": "{stock} × {part} w magazynie{loc}{low}.",
|
||||||
|
"stock_loc": " (miejsce przechowywania: {loc})",
|
||||||
|
"stock_low": " — na poziomie progu zamówienia lub poniżej",
|
||||||
|
"stock_untracked": "{part} — nie prowadzę stanu magazynowego dla tej części.",
|
||||||
|
"part_not_found": "Nie znalazłem części zamiennej pasującej do '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Está tudo em ordem — nenhuma manutenção precisa de atenção.",
|
||||||
|
"none_due_mine": "Nada está atribuído a você no momento.",
|
||||||
|
"none_due_here": "Nada precisa de manutenção neste cômodo.",
|
||||||
|
"unknown_user": "Não sei quem está perguntando, então não consigo dizer quais tarefas são suas.",
|
||||||
|
"unknown_area": "Não sei em que cômodo este dispositivo está — atribua ele a uma área primeiro.",
|
||||||
|
"tasks_due": "{count} tarefas de manutenção precisam de atenção: {items}.",
|
||||||
|
"task_due_one": "Uma tarefa de manutenção precisa de atenção: {items}.",
|
||||||
|
"completed": "Marquei '{task}' em {object} como concluída.",
|
||||||
|
"postponed": "Adiei '{task}' em {object} para {date}.",
|
||||||
|
"postpone_needs_when": "Me diga por quanto tempo adiar — por exemplo, cinco dias.",
|
||||||
|
"postpone_past": "Isso colocaria '{task}' no passado.",
|
||||||
|
"skipped": "Pulei este ciclo de '{task}' em {object}. O próximo vence em {date}.",
|
||||||
|
"not_found": "Não encontrei nenhuma tarefa de manutenção que corresponda a '{name}'.",
|
||||||
|
"ambiguous": "Isso corresponde a várias tarefas: {candidates}. Seja mais específico, por favor.",
|
||||||
|
"too_early": "'{task}' só pode ser concluída mais perto da data de vencimento.",
|
||||||
|
"st_overdue": "{days} dias de atraso",
|
||||||
|
"st_overdue_one": "um dia de atraso",
|
||||||
|
"st_due_today": "vence hoje",
|
||||||
|
"st_due_in": "vence em {days} dias",
|
||||||
|
"st_due_in_one": "vence amanhã",
|
||||||
|
"st_triggered": "acionada",
|
||||||
|
"item_on": "{task} em {object}",
|
||||||
|
"due_date_suffix": " O próximo vencimento é {date}.",
|
||||||
|
"guide_header": "Informações registradas sobre '{task}' em {object}: {segments}.",
|
||||||
|
"guide_none": "Não há instruções, documentos nem peças de reposição registrados para '{task}' em {object}. Posso dar dicas gerais e não verificadas — você quer?",
|
||||||
|
"guide_notes": "observações: {notes}",
|
||||||
|
"guide_checklist": "{count} passos da lista de verificação: {steps}",
|
||||||
|
"guide_doc": "documento vinculado '{title}'",
|
||||||
|
"guide_doc_page": "documento vinculado '{title}', página {page}",
|
||||||
|
"guide_url": "há um link de documentação registrado",
|
||||||
|
"guide_part": "peça necessária: {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "local: {loc}",
|
||||||
|
"guide_part_stock": "{stock} em estoque",
|
||||||
|
"snoozed": "Silenciei os lembretes de '{task}' em {object} por {hours} horas.",
|
||||||
|
"snooze_unavailable": "As notificações não estão configuradas, então não há nada para silenciar.",
|
||||||
|
"stock_line": "{stock} × {part} em estoque{loc}{low}.",
|
||||||
|
"stock_loc": " (local: {loc})",
|
||||||
|
"stock_low": " — no limite de reposição ou abaixo dele",
|
||||||
|
"stock_untracked": "Não há controle de estoque para {part}.",
|
||||||
|
"part_not_found": "Não encontrei nenhuma peça de reposição que corresponda a '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Está tudo bem — não há nenhuma manutenção pendente.",
|
||||||
|
"none_due_mine": "Neste momento não tens nada atribuído.",
|
||||||
|
"none_due_here": "Nesta divisão não há nenhuma manutenção pendente.",
|
||||||
|
"unknown_user": "Não sei quem está a falar, por isso não consigo dizer que tarefas são tuas.",
|
||||||
|
"unknown_area": "Não sei em que divisão está este dispositivo — atribui-o primeiro a uma área.",
|
||||||
|
"tasks_due": "Há {count} tarefas de manutenção a precisar de atenção: {items}.",
|
||||||
|
"task_due_one": "Há uma tarefa de manutenção a precisar de atenção: {items}.",
|
||||||
|
"completed": "Feito. Registei '{task}' em {object}.",
|
||||||
|
"postponed": "Adiei '{task}' em {object} para {date}.",
|
||||||
|
"postpone_needs_when": "Diz-me quanto tempo queres adiar — por exemplo, cinco dias.",
|
||||||
|
"postpone_past": "Assim '{task}' ficaria no passado.",
|
||||||
|
"skipped": "Saltei este ciclo de '{task}' em {object}. O próximo está previsto para {date}.",
|
||||||
|
"not_found": "Não encontrei nenhuma tarefa de manutenção que corresponda a '{name}'.",
|
||||||
|
"ambiguous": "Isso corresponde a várias tarefas: {candidates}. Podes ser um pouco mais específico?",
|
||||||
|
"too_early": "Só podes concluir '{task}' mais perto da data prevista.",
|
||||||
|
"st_overdue": "{days} dias de atraso",
|
||||||
|
"st_overdue_one": "um dia de atraso",
|
||||||
|
"st_due_today": "para fazer hoje",
|
||||||
|
"st_due_in": "para fazer daqui a {days} dias",
|
||||||
|
"st_due_in_one": "para fazer amanhã",
|
||||||
|
"st_triggered": "ativada",
|
||||||
|
"item_on": "{task} em {object}",
|
||||||
|
"due_date_suffix": " A próxima data prevista é {date}.",
|
||||||
|
"guide_header": "Isto é o que está guardado sobre '{task}' em {object}: {segments}.",
|
||||||
|
"guide_none": "Não há instruções, documentos nem peças guardadas para '{task}' em {object}. Em vez disso posso dar-te conselhos gerais, não verificados — queres?",
|
||||||
|
"guide_notes": "notas: {notes}",
|
||||||
|
"guide_checklist": "{count} passos da lista: {steps}",
|
||||||
|
"guide_doc": "documento ligado '{title}'",
|
||||||
|
"guide_doc_page": "documento ligado '{title}', página {page}",
|
||||||
|
"guide_url": "está guardado um link para a documentação",
|
||||||
|
"guide_part": "precisas de {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "guardado em {loc}",
|
||||||
|
"guide_part_stock": "{stock} em stock",
|
||||||
|
"snoozed": "Silenciei os lembretes de '{task}' em {object} durante {hours} horas.",
|
||||||
|
"snooze_unavailable": "As notificações não estão configuradas, por isso não há nada para silenciar.",
|
||||||
|
"stock_line": "{stock} × {part} em stock{loc}{low}.",
|
||||||
|
"stock_loc": " (guardado em {loc})",
|
||||||
|
"stock_low": " — no limite de reposição ou abaixo",
|
||||||
|
"stock_untracked": "O stock de {part} não é acompanhado.",
|
||||||
|
"part_not_found": "Não encontrei nenhuma peça que corresponda a '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Всё в порядке — обслуживание пока не требуется.",
|
||||||
|
"none_due_mine": "На тебя сейчас ничего не назначено.",
|
||||||
|
"none_due_here": "В этой комнате обслуживание не требуется.",
|
||||||
|
"unknown_user": "Я не знаю, кто спрашивает, поэтому не могу определить, какие задачи твои.",
|
||||||
|
"unknown_area": "Я не знаю, в какой комнате это устройство — сначала назначь ему зону.",
|
||||||
|
"tasks_due": "Внимания требуют задачи обслуживания, всего {count}: {items}.",
|
||||||
|
"task_due_one": "Внимания требует одна задача обслуживания: {items}.",
|
||||||
|
"completed": "Задача '{task}' у устройства {object} отмечена как выполненная.",
|
||||||
|
"postponed": "Задача '{task}' у устройства {object} перенесена на {date}.",
|
||||||
|
"postpone_needs_when": "Скажи, на сколько перенести — например, на пять дней.",
|
||||||
|
"postpone_past": "Тогда '{task}' окажется в прошлом.",
|
||||||
|
"skipped": "Этот цикл задачи '{task}' у устройства {object} пропущен. Следующий срок — {date}.",
|
||||||
|
"not_found": "Я не нашёл задачу обслуживания, подходящую под '{name}'.",
|
||||||
|
"ambiguous": "Под это подходит несколько задач: {candidates}. Уточни, пожалуйста.",
|
||||||
|
"too_early": "Задачу '{task}' можно выполнить только ближе к сроку.",
|
||||||
|
"st_overdue": "просрочка {days} дней",
|
||||||
|
"st_overdue_one": "просрочка один день",
|
||||||
|
"st_due_today": "срок сегодня",
|
||||||
|
"st_due_in": "срок в течение {days} дней",
|
||||||
|
"st_due_in_one": "срок завтра",
|
||||||
|
"st_triggered": "сработало",
|
||||||
|
"item_on": "{task} — {object}",
|
||||||
|
"due_date_suffix": " Следующий срок — {date}.",
|
||||||
|
"guide_header": "Сохранённые сведения о задаче '{task}' у устройства {object}: {segments}.",
|
||||||
|
"guide_none": "Для задачи '{task}' у устройства {object} не сохранено ни инструкций, ни документов, ни запчастей. Могу дать общие, непроверенные советы — хочешь?",
|
||||||
|
"guide_notes": "заметки: {notes}",
|
||||||
|
"guide_checklist": "шаги контрольного списка, всего {count}: {steps}",
|
||||||
|
"guide_doc": "связанный документ '{title}'",
|
||||||
|
"guide_doc_page": "связанный документ '{title}', страница {page}",
|
||||||
|
"guide_url": "сохранена ссылка на документацию",
|
||||||
|
"guide_part": "нужно: {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "место хранения: {loc}",
|
||||||
|
"guide_part_stock": "на складе: {stock}",
|
||||||
|
"snoozed": "Напоминания по задаче '{task}' у устройства {object} не будут приходить в течение {hours} часов.",
|
||||||
|
"snooze_unavailable": "Уведомления не настроены, так что отключать нечего.",
|
||||||
|
"stock_line": "{stock} × {part} на складе{loc}{low}.",
|
||||||
|
"stock_loc": " (место хранения: {loc})",
|
||||||
|
"stock_low": " — на уровне порога дозаказа или ниже",
|
||||||
|
"stock_untracked": "{part} — запас по этой детали не отслеживается.",
|
||||||
|
"part_not_found": "Я не нашёл запчасть, подходящую под '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Allt är i sin ordning — ingen underhållsuppgift behöver åtgärdas.",
|
||||||
|
"none_due_mine": "Ingenting är tilldelat dig just nu.",
|
||||||
|
"none_due_here": "Inget underhåll behöver göras i det här rummet.",
|
||||||
|
"unknown_user": "Jag vet inte vem som frågar, så jag kan inte säga vilka uppgifter som är dina.",
|
||||||
|
"unknown_area": "Jag vet inte vilket rum den här enheten står i — koppla den till ett område först.",
|
||||||
|
"tasks_due": "{count} underhållsuppgifter behöver åtgärdas: {items}.",
|
||||||
|
"task_due_one": "En underhållsuppgift behöver åtgärdas: {items}.",
|
||||||
|
"completed": "Jag har bockat av '{task}' på {object}.",
|
||||||
|
"postponed": "Jag har skjutit upp '{task}' på {object} till den {date}.",
|
||||||
|
"postpone_needs_when": "Säg hur långt jag ska skjuta upp den — till exempel fem dagar.",
|
||||||
|
"postpone_past": "Då skulle '{task}' hamna i det förflutna.",
|
||||||
|
"skipped": "Jag har hoppat över den här omgången av '{task}' på {object}. Nästa omgång ska göras den {date}.",
|
||||||
|
"not_found": "Jag hittade ingen underhållsuppgift som matchar '{name}'.",
|
||||||
|
"ambiguous": "Det matchar flera uppgifter: {candidates}. Var lite mer specifik.",
|
||||||
|
"too_early": "'{task}' går att bocka av först närmare förfallodatumet.",
|
||||||
|
"st_overdue": "{days} dagar för sent",
|
||||||
|
"st_overdue_one": "en dag för sent",
|
||||||
|
"st_due_today": "ska göras idag",
|
||||||
|
"st_due_in": "ska göras om {days} dagar",
|
||||||
|
"st_due_in_one": "ska göras imorgon",
|
||||||
|
"st_triggered": "utlöst",
|
||||||
|
"item_on": "{task} på {object}",
|
||||||
|
"due_date_suffix": " Nästa gång är det dags den {date}.",
|
||||||
|
"guide_header": "Sparad information om '{task}' på {object}: {segments}.",
|
||||||
|
"guide_none": "Det finns ingen sparad instruktion, inga dokument och inga reservdelar för '{task}' på {object}. Jag kan ge allmänna, overifierade råd i stället — vill du det?",
|
||||||
|
"guide_notes": "anteckningar: {notes}",
|
||||||
|
"guide_checklist": "{count} steg i checklistan: {steps}",
|
||||||
|
"guide_doc": "länkat dokument '{title}'",
|
||||||
|
"guide_doc_page": "länkat dokument '{title}', sidan {page}",
|
||||||
|
"guide_url": "det finns en länk till dokumentation",
|
||||||
|
"guide_part": "{qty} × {part} behövs{extras}",
|
||||||
|
"guide_part_loc": "förvaringsplats {loc}",
|
||||||
|
"guide_part_stock": "{stock} i lager",
|
||||||
|
"snoozed": "Jag har pausat påminnelserna för '{task}' på {object} i {hours} timmar.",
|
||||||
|
"snooze_unavailable": "Aviseringar är inte inställda, så det finns inget att pausa.",
|
||||||
|
"stock_line": "{stock} × {part} i lager{loc}{low}.",
|
||||||
|
"stock_loc": " (förvaringsplats {loc})",
|
||||||
|
"stock_low": " — vid eller under beställningsgränsen",
|
||||||
|
"stock_untracked": "Lagersaldot följs inte för {part}.",
|
||||||
|
"part_not_found": "Jag hittade ingen reservdel som matchar '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Her şey yolunda — bakım bekleyen bir şey yok.",
|
||||||
|
"none_due_mine": "Şu anda sana atanmış bir şey yok.",
|
||||||
|
"none_due_here": "Bu odada bakım bekleyen bir şey yok.",
|
||||||
|
"unknown_user": "Kimin sorduğunu bilmiyorum, bu yüzden hangi görevlerin sana ait olduğunu söyleyemem.",
|
||||||
|
"unknown_area": "Bu cihazın hangi odada olduğunu bilmiyorum — önce onu bir alana ata.",
|
||||||
|
"tasks_due": "{count} bakım görevi ilgilenmeyi bekliyor: {items}.",
|
||||||
|
"task_due_one": "Bir bakım görevi ilgilenmeyi bekliyor: {items}.",
|
||||||
|
"completed": "{object} için '{task}' görevi tamamlandı.",
|
||||||
|
"postponed": "{object} için '{task}' görevi {date} tarihine ertelendi.",
|
||||||
|
"postpone_needs_when": "Ne kadar erteleyeceğimi söyle — örneğin beş gün.",
|
||||||
|
"postpone_past": "Bu durumda '{task}' görevi geçmişte kalır.",
|
||||||
|
"skipped": "{object} için '{task}' görevinin bu turu atlandı. Sıradaki {date} tarihinde.",
|
||||||
|
"not_found": "'{name}' ile eşleşen bir bakım görevi bulamadım.",
|
||||||
|
"ambiguous": "Birden fazla göreve uyuyor: {candidates}. Biraz daha açık söyler misin?",
|
||||||
|
"too_early": "'{task}' görevi ancak son tarihine yaklaşınca tamamlanabilir.",
|
||||||
|
"st_overdue": "{days} gün gecikmiş",
|
||||||
|
"st_overdue_one": "bir gün gecikmiş",
|
||||||
|
"st_due_today": "bugün yapılacak",
|
||||||
|
"st_due_in": "{days} gün sonra yapılacak",
|
||||||
|
"st_due_in_one": "yarın yapılacak",
|
||||||
|
"st_triggered": "tetiklendi",
|
||||||
|
"item_on": "{object} için {task}",
|
||||||
|
"due_date_suffix": " Sıradaki bakım tarihi: {date}.",
|
||||||
|
"guide_header": "{object} için '{task}' görevine ait kayıtlı bilgiler: {segments}.",
|
||||||
|
"guide_none": "{object} için '{task}' görevine ait kayıtlı bir talimat, belge ya da yedek parça yok. İstersen bunun yerine genel, doğrulanmamış tavsiyeler verebilirim — ister misin?",
|
||||||
|
"guide_notes": "notlar: {notes}",
|
||||||
|
"guide_checklist": "{count} kontrol listesi adımı: {steps}",
|
||||||
|
"guide_doc": "bağlı belge '{title}'",
|
||||||
|
"guide_doc_page": "bağlı belge '{title}', sayfa {page}",
|
||||||
|
"guide_url": "kayıtlı bir doküman bağlantısı var",
|
||||||
|
"guide_part": "{qty} × {part} gerekiyor{extras}",
|
||||||
|
"guide_part_loc": "saklama yeri: {loc}",
|
||||||
|
"guide_part_stock": "stokta {stock} adet",
|
||||||
|
"snoozed": "{object} için '{task}' görevinin hatırlatmaları {hours} saat susturuldu.",
|
||||||
|
"snooze_unavailable": "Bildirimler ayarlanmamış, o yüzden susturulacak bir şey yok.",
|
||||||
|
"stock_line": "Stokta {stock} × {part} var{loc}{low}.",
|
||||||
|
"stock_loc": " (saklama yeri: {loc})",
|
||||||
|
"stock_low": " — yeniden sipariş sınırında ya da altında",
|
||||||
|
"stock_untracked": "{part} için stok takibi yapılmıyor.",
|
||||||
|
"part_not_found": "'{name}' ile eşleşen bir yedek parça bulamadım."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "Усе гаразд — обслуговування наразі не потрібне.",
|
||||||
|
"none_due_mine": "На тебе зараз нічого не призначено.",
|
||||||
|
"none_due_here": "У цій кімнаті обслуговування не потрібне.",
|
||||||
|
"unknown_user": "Я не знаю, хто питає, тому не можу визначити, які завдання твої.",
|
||||||
|
"unknown_area": "Я не знаю, у якій кімнаті цей пристрій — спершу признач йому зону.",
|
||||||
|
"tasks_due": "Уваги потребують завдання з обслуговування, усього {count}: {items}.",
|
||||||
|
"task_due_one": "Уваги потребує одне завдання з обслуговування: {items}.",
|
||||||
|
"completed": "Завдання '{task}' на пристрої {object} позначено як виконане.",
|
||||||
|
"postponed": "Завдання '{task}' на пристрої {object} перенесено на {date}.",
|
||||||
|
"postpone_needs_when": "Скажи, на скільки перенести — наприклад, на п’ять днів.",
|
||||||
|
"postpone_past": "Тоді '{task}' опиниться в минулому.",
|
||||||
|
"skipped": "Цей цикл завдання '{task}' на пристрої {object} пропущено. Наступний термін — {date}.",
|
||||||
|
"not_found": "Я не знайшов завдання з обслуговування, яке відповідає '{name}'.",
|
||||||
|
"ambiguous": "Цьому відповідає кілька завдань: {candidates}. Уточни, будь ласка.",
|
||||||
|
"too_early": "Завдання '{task}' можна виконати лише ближче до терміну.",
|
||||||
|
"st_overdue": "прострочення {days} днів",
|
||||||
|
"st_overdue_one": "прострочення один день",
|
||||||
|
"st_due_today": "термін сьогодні",
|
||||||
|
"st_due_in": "термін протягом {days} днів",
|
||||||
|
"st_due_in_one": "термін завтра",
|
||||||
|
"st_triggered": "спрацювало",
|
||||||
|
"item_on": "{task} — {object}",
|
||||||
|
"due_date_suffix": " Наступний термін — {date}.",
|
||||||
|
"guide_header": "Збережені відомості про завдання '{task}' на пристрої {object}: {segments}.",
|
||||||
|
"guide_none": "Для завдання '{task}' на пристрої {object} не збережено ані інструкцій, ані документів, ані запчастин. Можу натомість дати загальні, неперевірені поради — хочеш?",
|
||||||
|
"guide_notes": "нотатки: {notes}",
|
||||||
|
"guide_checklist": "кроки контрольного списку, усього {count}: {steps}",
|
||||||
|
"guide_doc": "пов’язаний документ '{title}'",
|
||||||
|
"guide_doc_page": "пов’язаний документ '{title}', сторінка {page}",
|
||||||
|
"guide_url": "збережено посилання на документацію",
|
||||||
|
"guide_part": "потрібно: {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "місце зберігання: {loc}",
|
||||||
|
"guide_part_stock": "на складі: {stock}",
|
||||||
|
"snoozed": "Нагадування щодо завдання '{task}' на пристрої {object} не надходитимуть протягом {hours} годин.",
|
||||||
|
"snooze_unavailable": "Сповіщення не налаштовані, тож вимикати нічого.",
|
||||||
|
"stock_line": "{stock} × {part} на складі{loc}{low}.",
|
||||||
|
"stock_loc": " (місце зберігання: {loc})",
|
||||||
|
"stock_low": " — на рівні порога дозамовлення або нижче",
|
||||||
|
"stock_untracked": "{part} — запас цієї деталі не відстежується.",
|
||||||
|
"part_not_found": "Я не знайшов запчастину, яка відповідає '{name}'."
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"none_due": "一切正常,没有需要处理的维护。",
|
||||||
|
"none_due_mine": "现在没有分配给你的任务。",
|
||||||
|
"none_due_here": "这个房间里没有需要维护的东西。",
|
||||||
|
"unknown_user": "我不知道是谁在问,所以没法判断哪些任务是你的。",
|
||||||
|
"unknown_area": "我不知道这个设备在哪个房间,请先把它分配到一个区域。",
|
||||||
|
"tasks_due": "有{count}项维护任务需要处理:{items}。",
|
||||||
|
"task_due_one": "有一项维护任务需要处理:{items}。",
|
||||||
|
"completed": "已完成{object}的“{task}”。",
|
||||||
|
"postponed": "已把{object}的“{task}”推迟到{date}。",
|
||||||
|
"postpone_needs_when": "告诉我要推迟多久,比如推迟五天。",
|
||||||
|
"postpone_past": "那样的话,“{task}”的日期就会落在过去了。",
|
||||||
|
"skipped": "已跳过{object}的“{task}”这一次。下一次在{date}到期。",
|
||||||
|
"not_found": "我没有找到和“{name}”对得上的维护任务。",
|
||||||
|
"ambiguous": "有好几项任务都对得上:{candidates}。请说得更具体一些。",
|
||||||
|
"too_early": "“{task}”要等到接近到期日才能完成。",
|
||||||
|
"st_overdue": "已逾期{days}天",
|
||||||
|
"st_overdue_one": "已逾期一天",
|
||||||
|
"st_due_today": "今天到期",
|
||||||
|
"st_due_in": "{days}天后到期",
|
||||||
|
"st_due_in_one": "明天到期",
|
||||||
|
"st_triggered": "已触发",
|
||||||
|
"item_on": "{object}的{task}",
|
||||||
|
"due_date_suffix": "下一个到期日是{date}。",
|
||||||
|
"guide_header": "关于{object}的“{task}”,保存的信息有:{segments}。",
|
||||||
|
"guide_none": "{object}的“{task}”没有保存任何操作说明、文档或备件。我可以给你一些通用的、未经核实的建议,需要吗?",
|
||||||
|
"guide_notes": "备注:{notes}",
|
||||||
|
"guide_checklist": "{count}个清单步骤:{steps}",
|
||||||
|
"guide_doc": "关联文档“{title}”",
|
||||||
|
"guide_doc_page": "关联文档“{title}”第{page}页",
|
||||||
|
"guide_url": "已保存一个说明书链接",
|
||||||
|
"guide_part": "需要 {qty} × {part}{extras}",
|
||||||
|
"guide_part_loc": "存放在{loc}",
|
||||||
|
"guide_part_stock": "库存{stock}",
|
||||||
|
"snoozed": "已把{object}的“{task}”提醒暂停{hours}小时。",
|
||||||
|
"snooze_unavailable": "还没有设置通知,所以没有可以暂停的提醒。",
|
||||||
|
"stock_line": "库存 {stock} × {part}{loc}{low}。",
|
||||||
|
"stock_loc": "(存放在{loc})",
|
||||||
|
"stock_low": ",已达到或低于补货下限",
|
||||||
|
"stock_untracked": "{part}的库存没有记录。",
|
||||||
|
"part_not_found": "我没有找到和“{name}”对得上的备件。"
|
||||||
|
}
|
||||||
@@ -115,7 +115,9 @@ class MaintenanceActionButton(MaintenanceEntity, ButtonEntity):
|
|||||||
if not self._task_data:
|
if not self._task_data:
|
||||||
raise HomeAssistantError(f"Task {self._task_id} no longer exists")
|
raise HomeAssistantError(f"Task {self._task_id} no longer exists")
|
||||||
if self._action == "complete":
|
if self._action == "complete":
|
||||||
await self.coordinator.complete_maintenance(self._task_id, notes="Completed from dashboard button")
|
await self.coordinator.complete_maintenance(
|
||||||
|
self._task_id, notes="Completed from dashboard button", unattended=True
|
||||||
|
)
|
||||||
elif self._action == "skip":
|
elif self._action == "skip":
|
||||||
await self.coordinator.skip_maintenance(self._task_id, reason="Skipped from dashboard button")
|
await self.coordinator.skip_maintenance(self._task_id, reason="Skipped from dashboard button")
|
||||||
elif self._action == "reset":
|
elif self._action == "reset":
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Das Format des Benachrichtigungsdienstes ist ungültig. Verwenden Sie 'notify.dienstname'.",
|
"invalid_service": "❌ Das Format des Benachrichtigungsdienstes ist ungültig. Verwenden Sie 'notify.dienstname'.",
|
||||||
"failed": "❌ Testbenachrichtigung konnte nicht gesendet werden. Bitte prüfen Sie Ihre Konfiguration.",
|
"failed": "❌ Testbenachrichtigung konnte nicht gesendet werden. Bitte prüfen Sie Ihre Konfiguration.",
|
||||||
"push_message": "🔧 Testbenachrichtigung — Ihre Benachrichtigungseinrichtung funktioniert!",
|
"push_message": "🔧 Testbenachrichtigung — Ihre Benachrichtigungseinrichtung funktioniert!",
|
||||||
|
"user_no_device": "ℹ️ Diesem Nutzer ist kein Companion-Gerät zugeordnet — seine Erinnerungen gehen an den Haushalts-Dienst.",
|
||||||
},
|
},
|
||||||
"nl": {
|
"nl": {
|
||||||
"success": "✅ Testmelding verzonden — uw service werkt. Krijgt een specifiek apparaat niets, controleer dat apparaat in uw notify-groep (en het HA-logboek).",
|
"success": "✅ Testmelding verzonden — uw service werkt. Krijgt een specifiek apparaat niets, controleer dat apparaat in uw notify-groep (en het HA-logboek).",
|
||||||
@@ -145,6 +146,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Het formaat van de meldingsservice is ongeldig. Gebruik 'notify.servicenaam'.",
|
"invalid_service": "❌ Het formaat van de meldingsservice is ongeldig. Gebruik 'notify.servicenaam'.",
|
||||||
"failed": "❌ Testmelding kon niet worden verzonden. Controleer uw configuratie.",
|
"failed": "❌ Testmelding kon niet worden verzonden. Controleer uw configuratie.",
|
||||||
"push_message": "🔧 Testmelding — uw meldingsinstellingen werken!",
|
"push_message": "🔧 Testmelding — uw meldingsinstellingen werken!",
|
||||||
|
"user_no_device": "ℹ️ Aan deze gebruiker is geen Companion-apparaat gekoppeld — hun herinneringen gaan naar de huishoudelijke dienst.",
|
||||||
},
|
},
|
||||||
"fr": {
|
"fr": {
|
||||||
"success": "✅ Notification de test envoyée — votre service fonctionne. Si un appareil précis ne reçoit rien, vérifiez-le dans votre groupe notify (et les journaux HA).",
|
"success": "✅ Notification de test envoyée — votre service fonctionne. Si un appareil précis ne reçoit rien, vérifiez-le dans votre groupe notify (et les journaux HA).",
|
||||||
@@ -152,6 +154,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Le format du service de notification est invalide. Utilisez 'notify.nom_du_service'.",
|
"invalid_service": "❌ Le format du service de notification est invalide. Utilisez 'notify.nom_du_service'.",
|
||||||
"failed": "❌ Impossible d'envoyer la notification de test. Veuillez vérifier votre configuration.",
|
"failed": "❌ Impossible d'envoyer la notification de test. Veuillez vérifier votre configuration.",
|
||||||
"push_message": "🔧 Notification de test — votre configuration de notifications fonctionne !",
|
"push_message": "🔧 Notification de test — votre configuration de notifications fonctionne !",
|
||||||
|
"user_no_device": "ℹ️ Aucun appareil Companion n'est lié à cet utilisateur — ses rappels partent vers le service du foyer.",
|
||||||
},
|
},
|
||||||
"it": {
|
"it": {
|
||||||
"success": "✅ Notifica di test inviata — il servizio funziona. Se un dispositivo specifico non riceve nulla, controllalo nel tuo gruppo notify (e nei log di HA).",
|
"success": "✅ Notifica di test inviata — il servizio funziona. Se un dispositivo specifico non riceve nulla, controllalo nel tuo gruppo notify (e nei log di HA).",
|
||||||
@@ -159,6 +162,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Il formato del servizio di notifica non è valido. Usa 'notify.nome_servizio'.",
|
"invalid_service": "❌ Il formato del servizio di notifica non è valido. Usa 'notify.nome_servizio'.",
|
||||||
"failed": "❌ Impossibile inviare la notifica di test. Verifica la tua configurazione.",
|
"failed": "❌ Impossibile inviare la notifica di test. Verifica la tua configurazione.",
|
||||||
"push_message": "🔧 Notifica di test — la configurazione delle notifiche funziona!",
|
"push_message": "🔧 Notifica di test — la configurazione delle notifiche funziona!",
|
||||||
|
"user_no_device": "ℹ️ Nessun dispositivo Companion è collegato a questo utente — i suoi promemoria vanno al servizio della casa.",
|
||||||
},
|
},
|
||||||
"es": {
|
"es": {
|
||||||
"success": "✅ Notificación de prueba enviada — tu servicio funciona. Si un dispositivo concreto no recibe nada, revísalo en tu grupo notify (y los registros de HA).",
|
"success": "✅ Notificación de prueba enviada — tu servicio funciona. Si un dispositivo concreto no recibe nada, revísalo en tu grupo notify (y los registros de HA).",
|
||||||
@@ -166,6 +170,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ El formato del servicio de notificación no es válido. Use 'notify.nombre_servicio'.",
|
"invalid_service": "❌ El formato del servicio de notificación no es válido. Use 'notify.nombre_servicio'.",
|
||||||
"failed": "❌ No se pudo enviar la notificación de prueba. Verifique su configuración.",
|
"failed": "❌ No se pudo enviar la notificación de prueba. Verifique su configuración.",
|
||||||
"push_message": "🔧 Notificación de prueba — ¡su configuración de notificaciones funciona!",
|
"push_message": "🔧 Notificación de prueba — ¡su configuración de notificaciones funciona!",
|
||||||
|
"user_no_device": "ℹ️ Este usuario no tiene ningún dispositivo Companion vinculado — sus recordatorios van al servicio del hogar.",
|
||||||
},
|
},
|
||||||
"en": {
|
"en": {
|
||||||
"success": "✅ Test notification sent — your service works. If a specific device gets nothing, check that device inside your notify group (and Home Assistant's logs).",
|
"success": "✅ Test notification sent — your service works. If a specific device gets nothing, check that device inside your notify group (and Home Assistant's logs).",
|
||||||
@@ -173,6 +178,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ The notification service format is invalid. Use 'notify.service_name'.",
|
"invalid_service": "❌ The notification service format is invalid. Use 'notify.service_name'.",
|
||||||
"failed": "❌ Failed to send the test notification. Please verify your service configuration.",
|
"failed": "❌ Failed to send the test notification. Please verify your service configuration.",
|
||||||
"push_message": "🔧 Test notification — your notification setup is working!",
|
"push_message": "🔧 Test notification — your notification setup is working!",
|
||||||
|
"user_no_device": "ℹ️ No Companion device is linked to this user — their reminders go to the household service.",
|
||||||
},
|
},
|
||||||
"ru": {
|
"ru": {
|
||||||
"success": "✅ Тестовое уведомление отправлено — сервис работает. Если конкретное устройство ничего не получает, проверьте его в вашей notify-группе (и в журналах HA).",
|
"success": "✅ Тестовое уведомление отправлено — сервис работает. Если конкретное устройство ничего не получает, проверьте его в вашей notify-группе (и в журналах HA).",
|
||||||
@@ -180,6 +186,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Неверный формат сервиса уведомлений. Используйте 'notify.имя_сервиса'.",
|
"invalid_service": "❌ Неверный формат сервиса уведомлений. Используйте 'notify.имя_сервиса'.",
|
||||||
"failed": "❌ Не удалось отправить тестовое уведомление. Проверьте настройки сервиса.",
|
"failed": "❌ Не удалось отправить тестовое уведомление. Проверьте настройки сервиса.",
|
||||||
"push_message": "🔧 Тестовое уведомление — ваша система уведомлений работает!",
|
"push_message": "🔧 Тестовое уведомление — ваша система уведомлений работает!",
|
||||||
|
"user_no_device": "ℹ️ К этому пользователю не привязано устройство Companion — его напоминания уходят в общий сервис.",
|
||||||
},
|
},
|
||||||
"uk": {
|
"uk": {
|
||||||
"success": "✅ Тестове сповіщення надіслано — служба працює. Якщо певний пристрій нічого не отримує, перевірте його у вашій notify-групі (та в журналах HA).",
|
"success": "✅ Тестове сповіщення надіслано — служба працює. Якщо певний пристрій нічого не отримує, перевірте його у вашій notify-групі (та в журналах HA).",
|
||||||
@@ -187,6 +194,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Невірний формат служби сповіщень. Використовуйте 'notify.service_name'.",
|
"invalid_service": "❌ Невірний формат служби сповіщень. Використовуйте 'notify.service_name'.",
|
||||||
"failed": "❌ Не вдалося надіслати тестове сповіщення. Перевірте конфігурацію служби.",
|
"failed": "❌ Не вдалося надіслати тестове сповіщення. Перевірте конфігурацію служби.",
|
||||||
"push_message": "🔧 Тестове сповіщення — ваші сповіщення працюють!",
|
"push_message": "🔧 Тестове сповіщення — ваші сповіщення працюють!",
|
||||||
|
"user_no_device": "ℹ️ До цього користувача не прив'язано пристрій Companion — його нагадування надходять до загальної служби.",
|
||||||
},
|
},
|
||||||
"pt": {
|
"pt": {
|
||||||
"success": "✅ Notificação de teste enviada — o seu serviço funciona. Se um dispositivo específico não receber nada, verifique-o no seu grupo notify (e nos registos do HA).",
|
"success": "✅ Notificação de teste enviada — o seu serviço funciona. Se um dispositivo específico não receber nada, verifique-o no seu grupo notify (e nos registos do HA).",
|
||||||
@@ -194,6 +202,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Formato inválido do serviço de notificação. Use 'notify.nome_do_servico'.",
|
"invalid_service": "❌ Formato inválido do serviço de notificação. Use 'notify.nome_do_servico'.",
|
||||||
"failed": "❌ Falha ao enviar a notificação de teste. Verifique a configuração do serviço.",
|
"failed": "❌ Falha ao enviar a notificação de teste. Verifique a configuração do serviço.",
|
||||||
"push_message": "🔧 Notificação de teste — as suas notificações estão a funcionar!",
|
"push_message": "🔧 Notificação de teste — as suas notificações estão a funcionar!",
|
||||||
|
"user_no_device": "ℹ️ Este utilizador não tem nenhum dispositivo Companion associado — os lembretes seguem para o serviço da casa.",
|
||||||
},
|
},
|
||||||
"zh": {
|
"zh": {
|
||||||
"success": "✅ 测试通知已发送 — 您的服务正常。如果某个设备未收到,请在您的 notify 群组中检查该设备(以及 HA 日志)。",
|
"success": "✅ 测试通知已发送 — 您的服务正常。如果某个设备未收到,请在您的 notify 群组中检查该设备(以及 HA 日志)。",
|
||||||
@@ -201,6 +210,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ 通知服务格式无效。请使用 'notify.服务名称' 格式。",
|
"invalid_service": "❌ 通知服务格式无效。请使用 'notify.服务名称' 格式。",
|
||||||
"failed": "❌ 测试通知发送失败。请验证您的服务配置。",
|
"failed": "❌ 测试通知发送失败。请验证您的服务配置。",
|
||||||
"push_message": "🔧 测试通知 — 您的通知设置已生效!",
|
"push_message": "🔧 测试通知 — 您的通知设置已生效!",
|
||||||
|
"user_no_device": "ℹ️ 该用户未关联 Companion 设备 — 其提醒将发送到家庭通知服务。",
|
||||||
},
|
},
|
||||||
"pt-br": {
|
"pt-br": {
|
||||||
"success": "✅ Notificação de teste enviada — seu serviço funciona. Se um dispositivo específico não receber nada, verifique esse dispositivo dentro do seu grupo de notificação (e os logs do Home Assistant).",
|
"success": "✅ Notificação de teste enviada — seu serviço funciona. Se um dispositivo específico não receber nada, verifique esse dispositivo dentro do seu grupo de notificação (e os logs do Home Assistant).",
|
||||||
@@ -208,6 +218,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ O formato do serviço de notificação é inválido. Use 'notify.nome_do_servico'.",
|
"invalid_service": "❌ O formato do serviço de notificação é inválido. Use 'notify.nome_do_servico'.",
|
||||||
"failed": "❌ Falha ao enviar a notificação de teste. Verifique a configuração do serviço.",
|
"failed": "❌ Falha ao enviar a notificação de teste. Verifique a configuração do serviço.",
|
||||||
"push_message": "🔧 Notificação de teste — sua configuração de notificações está funcionando!",
|
"push_message": "🔧 Notificação de teste — sua configuração de notificações está funcionando!",
|
||||||
|
"user_no_device": "ℹ️ Este usuário não tem nenhum dispositivo Companion vinculado — os lembretes vão para o serviço da casa.",
|
||||||
},
|
},
|
||||||
"hu": {
|
"hu": {
|
||||||
"success": "✅ Tesztértesítés elküldve — a szolgáltatás működik. Ha egy adott eszközre nem érkezik semmi, ellenőrizze az eszközt az értesítési csoportban (és a Home Assistant naplóit).",
|
"success": "✅ Tesztértesítés elküldve — a szolgáltatás működik. Ha egy adott eszközre nem érkezik semmi, ellenőrizze az eszközt az értesítési csoportban (és a Home Assistant naplóit).",
|
||||||
@@ -215,6 +226,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Az értesítési szolgáltatás formátuma érvénytelen. Használja a 'notify.szolgaltatas_nev' formát.",
|
"invalid_service": "❌ Az értesítési szolgáltatás formátuma érvénytelen. Használja a 'notify.szolgaltatas_nev' formát.",
|
||||||
"failed": "❌ A tesztértesítés küldése nem sikerült. Ellenőrizze a szolgáltatás beállításait.",
|
"failed": "❌ A tesztértesítés küldése nem sikerült. Ellenőrizze a szolgáltatás beállításait.",
|
||||||
"push_message": "🔧 Tesztértesítés — az értesítési rendszere működik!",
|
"push_message": "🔧 Tesztértesítés — az értesítési rendszere működik!",
|
||||||
|
"user_no_device": "ℹ️ Ehhez a felhasználóhoz nincs Companion eszköz rendelve — az emlékeztetői a háztartási szolgáltatásra mennek.",
|
||||||
},
|
},
|
||||||
"ko": {
|
"ko": {
|
||||||
"success": "✅ 테스트 알림을 보냈습니다 — 서비스가 작동합니다. 특정 기기에 알림이 오지 않으면 알림 그룹 내 해당 기기와 Home Assistant 로그를 확인하세요.",
|
"success": "✅ 테스트 알림을 보냈습니다 — 서비스가 작동합니다. 특정 기기에 알림이 오지 않으면 알림 그룹 내 해당 기기와 Home Assistant 로그를 확인하세요.",
|
||||||
@@ -222,6 +234,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ 알림 서비스 형식이 잘못되었습니다. 'notify.service_name' 형식을 사용하세요.",
|
"invalid_service": "❌ 알림 서비스 형식이 잘못되었습니다. 'notify.service_name' 형식을 사용하세요.",
|
||||||
"failed": "❌ 테스트 알림 전송에 실패했습니다. 서비스 설정을 확인하세요.",
|
"failed": "❌ 테스트 알림 전송에 실패했습니다. 서비스 설정을 확인하세요.",
|
||||||
"push_message": "🔧 테스트 알림 — 알림 설정이 정상 작동합니다!",
|
"push_message": "🔧 테스트 알림 — 알림 설정이 정상 작동합니다!",
|
||||||
|
"user_no_device": "ℹ️ 이 사용자에게 연결된 Companion 기기가 없습니다 — 알림은 가정 서비스로 전송됩니다.",
|
||||||
},
|
},
|
||||||
"tr": {
|
"tr": {
|
||||||
"success": "✅ Test bildirimi gönderildi — servisiniz çalışıyor. Belirli bir cihaza bildirim gelmiyorsa bildirim grubunuzdaki o cihazı (ve Home Assistant günlüklerini) kontrol edin.",
|
"success": "✅ Test bildirimi gönderildi — servisiniz çalışıyor. Belirli bir cihaza bildirim gelmiyorsa bildirim grubunuzdaki o cihazı (ve Home Assistant günlüklerini) kontrol edin.",
|
||||||
@@ -229,6 +242,7 @@ _TEST_NOTIFICATION_RESULTS: dict[str, dict[str, str]] = {
|
|||||||
"invalid_service": "❌ Bildirim servisi biçimi geçersiz. 'notify.servis_adi' kullanın.",
|
"invalid_service": "❌ Bildirim servisi biçimi geçersiz. 'notify.servis_adi' kullanın.",
|
||||||
"failed": "❌ Test bildirimi gönderilemedi. Servis yapılandırmanızı kontrol edin.",
|
"failed": "❌ Test bildirimi gönderilemedi. Servis yapılandırmanızı kontrol edin.",
|
||||||
"push_message": "🔧 Test bildirimi — bildirim kurulumunuz çalışıyor!",
|
"push_message": "🔧 Test bildirimi — bildirim kurulumunuz çalışıyor!",
|
||||||
|
"user_no_device": "ℹ️ Bu kullanıcıya bağlı bir Companion cihazı yok — hatırlatıcıları ev servisine gider.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,14 +254,36 @@ def _get_test_result_text(hass: HomeAssistant, key: str) -> str:
|
|||||||
return texts.get(key, texts.get("failed", key))
|
return texts.get(key, texts.get("failed", key))
|
||||||
|
|
||||||
|
|
||||||
async def send_test_notification(hass: HomeAssistant, options: dict[str, Any]) -> str:
|
async def send_test_notification(
|
||||||
"""Send a test notification using the configured notify service.
|
hass: HomeAssistant,
|
||||||
|
options: dict[str, Any],
|
||||||
|
user_id: str | None = None,
|
||||||
|
) -> str:
|
||||||
|
"""Send a test notification, optionally to ONE household member.
|
||||||
|
|
||||||
Returns a result key ("success", "no_service", "invalid_service", "failed")
|
Returns a result key ("success", "no_service", "invalid_service",
|
||||||
that callers map to localized text. Action buttons are included whenever
|
"failed", "user_no_device") that callers map to localized text. Action
|
||||||
the corresponding action-feature toggles are enabled, so the rendered
|
buttons are included whenever the corresponding action-feature toggles are
|
||||||
notification matches the real layout users see for actual tasks.
|
enabled, so the rendered notification matches the real layout users see
|
||||||
|
for actual tasks.
|
||||||
|
|
||||||
|
With ``user_id`` the target is resolved through the SAME lookup the real
|
||||||
|
per-task routing uses (``get_user_notify_services``). That is the whole
|
||||||
|
point of a per-user test: one that took its own path could report success
|
||||||
|
while real reminders still went somewhere else — which is exactly how the
|
||||||
|
wrong-service bug behind #75 stayed invisible.
|
||||||
"""
|
"""
|
||||||
|
if user_id:
|
||||||
|
from .helpers.notification_manager import get_user_notify_services
|
||||||
|
|
||||||
|
user_services = await get_user_notify_services(hass, user_id)
|
||||||
|
if not user_services:
|
||||||
|
# Not a failure: this member simply has no Companion device, so
|
||||||
|
# their reminders fall back to the household service. Saying so is
|
||||||
|
# more useful than sending a test that proves nothing.
|
||||||
|
return "user_no_device"
|
||||||
|
return await _send_test_to(hass, options, user_services)
|
||||||
|
|
||||||
notify_service = str(options.get(CONF_NOTIFY_SERVICE, ""))
|
notify_service = str(options.get(CONF_NOTIFY_SERVICE, ""))
|
||||||
if not notify_service:
|
if not notify_service:
|
||||||
return "no_service"
|
return "no_service"
|
||||||
@@ -258,6 +294,15 @@ async def send_test_notification(hass: HomeAssistant, options: dict[str, Any]) -
|
|||||||
if error:
|
if error:
|
||||||
return "invalid_service"
|
return "invalid_service"
|
||||||
|
|
||||||
|
return await _send_test_to(hass, options, [normalized])
|
||||||
|
|
||||||
|
|
||||||
|
async def _send_test_to(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
options: dict[str, Any],
|
||||||
|
services: list[str],
|
||||||
|
) -> str:
|
||||||
|
"""Send the test payload to every resolved service; "success" if any went."""
|
||||||
try:
|
try:
|
||||||
from .helpers.notification_manager import async_dispatch_notify
|
from .helpers.notification_manager import async_dispatch_notify
|
||||||
|
|
||||||
@@ -279,11 +324,13 @@ async def send_test_notification(hass: HomeAssistant, options: dict[str, Any]) -
|
|||||||
test_actions.append({"action": "MS_TEST_SNOOZE", "title": "\U0001f4a4 Snooze"})
|
test_actions.append({"action": "MS_TEST_SNOOZE", "title": "\U0001f4a4 Snooze"})
|
||||||
service_data["data"] = {"actions": test_actions}
|
service_data["data"] = {"actions": test_actions}
|
||||||
# Dual-path: legacy notify service OR notify entity (send_message).
|
# Dual-path: legacy notify service OR notify entity (send_message).
|
||||||
if not await async_dispatch_notify(hass, normalized, service_data, blocking=True):
|
sent_any = False
|
||||||
return "failed"
|
for service in services:
|
||||||
return "success"
|
if await async_dispatch_notify(hass, service, service_data, blocking=True):
|
||||||
|
sent_any = True
|
||||||
|
return "success" if sent_any else "failed"
|
||||||
except Exception: # noqa: BLE001 - any failure mode reports "failed" to the UI
|
except Exception: # noqa: BLE001 - any failure mode reports "failed" to the UI
|
||||||
_LOGGER.debug("Test notification failed for %s", notify_service, exc_info=True)
|
_LOGGER.debug("Test notification failed for %s", services, exc_info=True)
|
||||||
return "failed"
|
return "failed"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -249,6 +249,11 @@ CONF_SNOOZE_DURATION_HOURS = "snooze_duration_hours"
|
|||||||
|
|
||||||
# v2.15.0: opt-in weekly digest — a single Monday-morning summary notification.
|
# v2.15.0: opt-in weekly digest — a single Monday-morning summary notification.
|
||||||
CONF_WEEKLY_DIGEST_ENABLED = "weekly_digest_enabled"
|
CONF_WEEKLY_DIGEST_ENABLED = "weekly_digest_enabled"
|
||||||
|
|
||||||
|
# v2.44: opt-in copy of the shipped Assist sentence files into
|
||||||
|
# <config>/custom_sentences/. The classic conversation agent reads sentences
|
||||||
|
# from there and nowhere else, and the HACS release ZIP never carried them.
|
||||||
|
CONF_INSTALL_ASSIST_SENTENCES = "install_assist_sentences"
|
||||||
CONF_WARRANTY_REMINDER_ENABLED = "warranty_reminder_enabled"
|
CONF_WARRANTY_REMINDER_ENABLED = "warranty_reminder_enabled"
|
||||||
CONF_WARRANTY_REMINDER_DAYS = "warranty_reminder_days"
|
CONF_WARRANTY_REMINDER_DAYS = "warranty_reminder_days"
|
||||||
DEFAULT_WARRANTY_REMINDER_DAYS = 30
|
DEFAULT_WARRANTY_REMINDER_DAYS = 30
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, timedelta
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -49,6 +50,7 @@ from .const import (
|
|||||||
ScheduleType,
|
ScheduleType,
|
||||||
TriggerEntityState,
|
TriggerEntityState,
|
||||||
)
|
)
|
||||||
|
from .helpers.budget import compute_spend
|
||||||
from .helpers.schedule import normalize_task_storage, read_legacy_fields
|
from .helpers.schedule import normalize_task_storage, read_legacy_fields
|
||||||
from .models.maintenance_object import MaintenanceObject
|
from .models.maintenance_object import MaintenanceObject
|
||||||
from .models.maintenance_task import MaintenanceTask
|
from .models.maintenance_task import MaintenanceTask
|
||||||
@@ -786,53 +788,18 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
Stores the result in hass.data[DOMAIN][BUDGET_CACHE_KEY] so that
|
Stores the result in hass.data[DOMAIN][BUDGET_CACHE_KEY] so that
|
||||||
every coordinator reads from the same cache instead of each one
|
every coordinator reads from the same cache instead of each one
|
||||||
re-scanning all entries on every 5-minute refresh.
|
re-scanning all entries on every 5-minute refresh.
|
||||||
|
|
||||||
|
The scan itself lives in :func:`helpers.budget.compute_spend`, shared
|
||||||
|
with the ``budget_status`` WS command — this method only owns the
|
||||||
|
*caching* around it. The two used to hold divergent copies of the same
|
||||||
|
loop, so the alert and the panel could report different spend.
|
||||||
"""
|
"""
|
||||||
now = dt_util.now()
|
monthly, yearly = compute_spend(self.hass)
|
||||||
monthly = 0.0
|
|
||||||
yearly = 0.0
|
|
||||||
|
|
||||||
for ce in self.hass.config_entries.async_entries(DOMAIN):
|
|
||||||
if ce.unique_id == GLOBAL_UNIQUE_ID:
|
|
||||||
continue
|
|
||||||
|
|
||||||
rd = getattr(ce, "runtime_data", None)
|
|
||||||
ce_store = getattr(rd, "store", None) if rd else None
|
|
||||||
|
|
||||||
for tid in ce.data.get(CONF_TASKS, {}):
|
|
||||||
if ce_store is not None:
|
|
||||||
history = ce_store.get_history(tid)
|
|
||||||
else:
|
|
||||||
history = ce.data.get(CONF_TASKS, {}).get(tid, {}).get("history", [])
|
|
||||||
|
|
||||||
for h_entry in history:
|
|
||||||
if h_entry.get("type") != "completed":
|
|
||||||
continue
|
|
||||||
cost = h_entry.get("cost")
|
|
||||||
if cost is None:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
cost_val = float(cost)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
continue
|
|
||||||
ts = h_entry.get("timestamp", "")
|
|
||||||
try:
|
|
||||||
entry_dt = datetime.fromisoformat(ts)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
continue
|
|
||||||
# Ensure TZ-aware so year/month boundaries are evaluated
|
|
||||||
# in HA's local timezone (otherwise off-by-one near midnight).
|
|
||||||
if entry_dt.tzinfo is None:
|
|
||||||
entry_dt = entry_dt.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE)
|
|
||||||
entry_dt = dt_util.as_local(entry_dt)
|
|
||||||
if entry_dt.year == now.year:
|
|
||||||
yearly += cost_val
|
|
||||||
if entry_dt.month == now.month:
|
|
||||||
monthly += cost_val
|
|
||||||
|
|
||||||
self.hass.data.setdefault(DOMAIN, {})[BUDGET_CACHE_KEY] = {
|
self.hass.data.setdefault(DOMAIN, {})[BUDGET_CACHE_KEY] = {
|
||||||
"monthly_spent": monthly,
|
"monthly_spent": monthly,
|
||||||
"yearly_spent": yearly,
|
"yearly_spent": yearly,
|
||||||
"last_updated": now,
|
"last_updated": dt_util.now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _async_check_budget(self, task_results: dict[str, Any]) -> None:
|
async def _async_check_budget(self, task_results: dict[str, Any]) -> None:
|
||||||
@@ -965,13 +932,63 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
restock_quantity: float | None = None,
|
restock_quantity: float | None = None,
|
||||||
used_parts: list[dict[str, Any]] | None = None,
|
used_parts: list[dict[str, Any]] | None = None,
|
||||||
auto: bool = False,
|
auto: bool = False,
|
||||||
|
unattended: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mark a task as completed and persist."""
|
"""Mark a task as completed and persist.
|
||||||
|
|
||||||
|
``unattended`` marks a surface that cannot ask a human for anything —
|
||||||
|
a button press, a to-do tick, an NFC tap, a notification button, a
|
||||||
|
voice command. Those paths attach a canned provenance note
|
||||||
|
("Completed via NFC tag"), which must NOT be mistaken for the note a
|
||||||
|
task demands: the point of a required note is that somebody wrote it.
|
||||||
|
"""
|
||||||
merged = self._get_merged_tasks_data()
|
merged = self._get_merged_tasks_data()
|
||||||
if task_id not in merged:
|
if task_id not in merged:
|
||||||
_LOGGER.error("Task %s not found in entry %s", task_id, self.entry.title)
|
_LOGGER.error("Task %s not found in entry %s", task_id, self.entry.title)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Required completion details. Checked HERE — the one point every
|
||||||
|
# surface funnels through — so a task demanding a note cannot be
|
||||||
|
# closed out from a button, the to-do list, an NFC tag, a
|
||||||
|
# notification action, voice or a service call.
|
||||||
|
#
|
||||||
|
# Deliberately BEFORE the double-complete guard below: a rejected
|
||||||
|
# attempt must not stamp that guard, or the corrected completion the
|
||||||
|
# user makes seconds later (after filling in the dialog) would be
|
||||||
|
# silently swallowed as a duplicate.
|
||||||
|
#
|
||||||
|
# Automatic completions are exempt — a self-clearing problem sensor
|
||||||
|
# has nobody to ask, and a required photo would strand the task.
|
||||||
|
if not auto:
|
||||||
|
from .helpers.completion_requirements import (
|
||||||
|
missing_completion_fields,
|
||||||
|
required_completion_fields,
|
||||||
|
)
|
||||||
|
|
||||||
|
if unattended:
|
||||||
|
# Nobody was asked, so nothing the caller attached counts as
|
||||||
|
# an answer — a canned "Completed from the To-do list" note is
|
||||||
|
# provenance, not the note the task demands.
|
||||||
|
missing = required_completion_fields(merged[task_id])
|
||||||
|
else:
|
||||||
|
missing = missing_completion_fields(
|
||||||
|
merged[task_id],
|
||||||
|
notes=notes,
|
||||||
|
cost=cost,
|
||||||
|
duration=duration,
|
||||||
|
photo_doc_id=photo_doc_id,
|
||||||
|
completed_by=completed_by,
|
||||||
|
)
|
||||||
|
if missing:
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="completion_details_required",
|
||||||
|
translation_placeholders={
|
||||||
|
"task_name": str(merged[task_id].get("name", task_id)),
|
||||||
|
"fields": ", ".join(missing),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
# Household double-complete guard (journey M1): two people seeing the
|
# Household double-complete guard (journey M1): two people seeing the
|
||||||
# same overdue task and both tapping Complete within seconds would
|
# same overdue task and both tapping Complete within seconds would
|
||||||
# record two completions — duplicated history/cost and a DOUBLE
|
# record two completions — duplicated history/cost and a DOUBLE
|
||||||
@@ -1241,6 +1258,28 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
self._lifecycle_event_payload(task, task_id, reason=reason),
|
self._lifecycle_event_payload(task, task_id, reason=reason),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_refresh_now(self) -> None:
|
||||||
|
"""Recompute immediately — for changes a person just made.
|
||||||
|
|
||||||
|
``async_request_refresh`` is debounced, and Home Assistant's default
|
||||||
|
window is **ten seconds** (``REQUEST_REFRESH_DEFAULT_COOLDOWN``). That
|
||||||
|
is right for trigger-driven churn — a noisy sensor must not recompute
|
||||||
|
the object on every state change — and wrong for a user action: any
|
||||||
|
second action within that window had its request coalesced to the end
|
||||||
|
of it, so the panel kept showing the old computed status for up to ten
|
||||||
|
seconds and the change looked like it had done nothing.
|
||||||
|
|
||||||
|
Assigning a user and then postponing the task was the reported case
|
||||||
|
(#111 review, 2026-07-28), but nothing about it is specific to those
|
||||||
|
two: completing two tasks on one object in quick succession, or any
|
||||||
|
bulk action, hit the same window.
|
||||||
|
|
||||||
|
The recompute covers one object's tasks, so doing it per user action is
|
||||||
|
cheap; the debounced path stays exactly as it was for triggers.
|
||||||
|
"""
|
||||||
|
await self.async_refresh()
|
||||||
|
|
||||||
async def _persist_and_signal_task_change(
|
async def _persist_and_signal_task_change(
|
||||||
self,
|
self,
|
||||||
task_id: str,
|
task_id: str,
|
||||||
@@ -1261,7 +1300,7 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
self.hass,
|
self.hass,
|
||||||
SIGNAL_TASK_RESET.format(entry_id=self.entry.entry_id, task_id=task_id),
|
SIGNAL_TASK_RESET.format(entry_id=self.entry.entry_id, task_id=task_id),
|
||||||
)
|
)
|
||||||
await self.async_request_refresh()
|
await self.async_refresh_now()
|
||||||
|
|
||||||
def _lifecycle_event_payload(
|
def _lifecycle_event_payload(
|
||||||
self,
|
self,
|
||||||
@@ -1321,7 +1360,7 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
new_data = dict(self.entry.data)
|
new_data = dict(self.entry.data)
|
||||||
new_data[CONF_TASKS] = tasks_data
|
new_data[CONF_TASKS] = tasks_data
|
||||||
self.hass.config_entries.async_update_entry(self.entry, data=new_data)
|
self.hass.config_entries.async_update_entry(self.entry, data=new_data)
|
||||||
await self.async_request_refresh()
|
await self.async_refresh_now()
|
||||||
|
|
||||||
async def async_persist_trigger_runtime(
|
async def async_persist_trigger_runtime(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -165,6 +165,9 @@ class CounterTrigger(BaseTrigger):
|
|||||||
# falls back to the RAW counter value — a 27,000 km odometer reads
|
# falls back to the RAW counter value — a 27,000 km odometer reads
|
||||||
# as "27000/15000, overdue" (issue #102). Debounced upstream, and
|
# as "27000/15000, overdue" (issue #102). Debounced upstream, and
|
||||||
# the periodic refresh never writes baselines, so no loop.
|
# the periodic refresh never writes baselines, so no loop.
|
||||||
|
# Debounced ON PURPOSE: a counter entity can change many times
|
||||||
|
# a minute, and this is the path the ten-second coalescing
|
||||||
|
# window exists for. User actions use async_refresh_now.
|
||||||
await self._coordinator.async_request_refresh()
|
await self._coordinator.async_request_refresh()
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
|
|||||||
+48
-32
@@ -11,18 +11,14 @@ import { property, state } from "lit/decorators.js";
|
|||||||
import { t, ensureLocale, DEFAULT_CURRENCY_SYMBOL } from "../styles";
|
import { t, ensureLocale, DEFAULT_CURRENCY_SYMBOL } from "../styles";
|
||||||
import { describeWsError } from "../ws-errors";
|
import { describeWsError } from "../ws-errors";
|
||||||
import { sectionCardSharedStyles } from "./section-card-shared-styles";
|
import { sectionCardSharedStyles } from "./section-card-shared-styles";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { BudgetStatus, HomeAssistant } from "../types";
|
||||||
|
|
||||||
interface BudgetStatus {
|
|
||||||
monthly_budget?: number;
|
|
||||||
monthly_spent?: number;
|
|
||||||
yearly_budget?: number;
|
|
||||||
yearly_spent?: number;
|
|
||||||
currency_symbol?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CardConfig { type: string; title?: string; }
|
interface CardConfig { type: string; title?: string; }
|
||||||
|
|
||||||
|
/** Backend default for budget_alert_threshold (const.py / settings_registry).
|
||||||
|
* Only reached if an older core omits the field from budget_status. */
|
||||||
|
const DEFAULT_ALERT_THRESHOLD_PCT = 80;
|
||||||
|
|
||||||
export class MaintenanceBudgetSectionCard extends LitElement {
|
export class MaintenanceBudgetSectionCard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@state() private _config: CardConfig = { type: "" };
|
@state() private _config: CardConfig = { type: "" };
|
||||||
@@ -109,10 +105,21 @@ export class MaintenanceBudgetSectionCard extends LitElement {
|
|||||||
return html`<ha-card><div class="loading">${t("loading", L) || "Loading…"}</div></ha-card>`;
|
return html`<ha-card><div class="loading">${t("loading", L) || "Loading…"}</div></ha-card>`;
|
||||||
}
|
}
|
||||||
const sym = s.currency_symbol || DEFAULT_CURRENCY_SYMBOL;
|
const sym = s.currency_symbol || DEFAULT_CURRENCY_SYMBOL;
|
||||||
const mPct = s.monthly_budget ? Math.min(100, ((s.monthly_spent || 0) / s.monthly_budget) * 100) : 0;
|
// The amber step is the CONFIGURED budget_alert_threshold, not a literal 80
|
||||||
const yPct = s.yearly_budget ? Math.min(100, ((s.yearly_spent || 0) / s.yearly_budget) * 100) : 0;
|
// — same rule the panel's budget bar uses (maintenance-panel._renderBudgetBar).
|
||||||
const mWarn = mPct >= 100 ? "danger" : mPct >= 80 ? "warning" : "ok";
|
const threshold = s.alert_threshold_pct ?? DEFAULT_ALERT_THRESHOLD_PCT;
|
||||||
const yWarn = yPct >= 100 ? "danger" : yPct >= 80 ? "warning" : "ok";
|
const tracks = [
|
||||||
|
{
|
||||||
|
label: t("budget_monthly", L) || "Monthly",
|
||||||
|
spent: s.monthly_spent || 0,
|
||||||
|
budget: s.monthly_budget || 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("budget_yearly", L) || "Yearly",
|
||||||
|
spent: s.yearly_spent || 0,
|
||||||
|
budget: s.yearly_budget || 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
@@ -127,25 +134,34 @@ export class MaintenanceBudgetSectionCard extends LitElement {
|
|||||||
|
|
||||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||||
|
|
||||||
<div class="track">
|
${tracks.map((track) => {
|
||||||
<div class="track-label-row">
|
// #104: budget tracking without a maximum — a bar needs a
|
||||||
<label>${t("budget_monthly", L) || "Monthly"}</label>
|
// denominator, so show the plain spent total instead of "9 / 0 €"
|
||||||
<span class="track-numbers ${mWarn}">
|
// over an always-empty bar. Mirrors the panel's spent-only lines.
|
||||||
${(s.monthly_spent || 0).toFixed(0)} / ${(s.monthly_budget || 0).toFixed(0)} ${sym}
|
if (!(track.budget > 0)) {
|
||||||
</span>
|
return html`
|
||||||
</div>
|
<div class="track spent-only">
|
||||||
<div class="bar"><div class="bar-fill ${mWarn}" style="width:${mPct}%"></div></div>
|
<div class="track-label-row">
|
||||||
</div>
|
<label>${track.label}</label>
|
||||||
|
<span class="track-numbers ok">${track.spent.toFixed(0)} ${sym}</span>
|
||||||
<div class="track">
|
</div>
|
||||||
<div class="track-label-row">
|
</div>
|
||||||
<label>${t("budget_yearly", L) || "Yearly"}</label>
|
`;
|
||||||
<span class="track-numbers ${yWarn}">
|
}
|
||||||
${(s.yearly_spent || 0).toFixed(0)} / ${(s.yearly_budget || 0).toFixed(0)} ${sym}
|
const pct = Math.min(100, Math.max(0, (track.spent / track.budget) * 100));
|
||||||
</span>
|
const warn = pct >= 100 ? "danger" : pct >= threshold ? "warning" : "ok";
|
||||||
</div>
|
return html`
|
||||||
<div class="bar"><div class="bar-fill ${yWarn}" style="width:${yPct}%"></div></div>
|
<div class="track">
|
||||||
</div>
|
<div class="track-label-row">
|
||||||
|
<label>${track.label}</label>
|
||||||
|
<span class="track-numbers ${warn}">
|
||||||
|
${track.spent.toFixed(0)} / ${track.budget.toFixed(0)} ${sym}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar"><div class="bar-fill ${warn}" style="width:${pct}%"></div></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
|
||||||
${this._isAdmin
|
${this._isAdmin
|
||||||
? html`
|
? html`
|
||||||
|
|||||||
+86
-23
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
import { LitElement, html, css, nothing } from "lit";
|
import { LitElement, html, css, nothing } from "lit";
|
||||||
import { property, state } from "lit/decorators.js";
|
import { property, state } from "lit/decorators.js";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant, TaskPartLink } from "../types";
|
||||||
import { t, nativeFieldStyles } from "../styles";
|
import { t, nativeFieldStyles } from "../styles";
|
||||||
import { describeWsError } from "../ws-errors";
|
import { describeWsError } from "../ws-errors";
|
||||||
|
import { partLinkKey, type LinkedPart } from "../helpers/shared-parts";
|
||||||
|
import { REQUIRED_COMPLETION_LABELS } from "./required-completion-labels";
|
||||||
|
|
||||||
export class MaintenanceCompleteDialog extends LitElement {
|
export class MaintenanceCompleteDialog extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@@ -19,12 +21,20 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
@property() public readingUnit = "";
|
@property() public readingUnit = "";
|
||||||
/** Buy task (part_ref): default restock quantity — shows an editable qty field. */
|
/** Buy task (part_ref): default restock quantity — shows an editable qty field. */
|
||||||
@property({ attribute: false }) public restockDefault: number | null = null;
|
@property({ attribute: false }) public restockDefault: number | null = null;
|
||||||
/** #99: the object's parts — enables the editable "parts used" section. */
|
/** #99: the parts offered on completion — enables the editable "parts used"
|
||||||
@property({ attribute: false }) public parts: Array<{ id: string; name: string; unit?: string | null; stock?: number | null }> = [];
|
* section. Built by `partsForCompletion`: the object's own inventory plus
|
||||||
/** #99: the task's fixed consumes_parts links (prefill for the section). */
|
* every shared pool this task links to (#111), each tagged with its owner. */
|
||||||
@property({ attribute: false }) public consumesParts: Array<{ part_id: string; quantity: number }> = [];
|
@property({ attribute: false }) public parts: LinkedPart[] = [];
|
||||||
|
/** #99: the task's fixed consumes_parts links (prefill for the section).
|
||||||
|
* A link may carry an `entry_id` (#111) and MUST keep it through the edit —
|
||||||
|
* without it the completion would decrement the wrong inventory, or none. */
|
||||||
|
@property({ attribute: false }) public consumesParts: TaskPartLink[] = [];
|
||||||
/** "Consumes: 1× HEPA-Filter (Shelf B)" hint lines for consuming tasks. */
|
/** "Consumes: 1× HEPA-Filter (Shelf B)" hint lines for consuming tasks. */
|
||||||
@property({ type: Array }) public consumesInfo: string[] = [];
|
@property({ type: Array }) public consumesInfo: string[] = [];
|
||||||
|
/** Details this task demands before it counts as done (v2.44). The backend
|
||||||
|
* enforces the same list at every completion surface; blocking Save here
|
||||||
|
* just means the user never has to meet that rejection. */
|
||||||
|
@property({ type: Array }) public requiredFields: string[] = [];
|
||||||
@state() private _open = false;
|
@state() private _open = false;
|
||||||
@state() private _notes = "";
|
@state() private _notes = "";
|
||||||
@state() private _cost = "";
|
@state() private _cost = "";
|
||||||
@@ -38,7 +48,9 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
@state() private _photoUploading = false;
|
@state() private _photoUploading = false;
|
||||||
@state() private _readingValue = "";
|
@state() private _readingValue = "";
|
||||||
@state() private _restockQty = "";
|
@state() private _restockQty = "";
|
||||||
@state() private _usedParts: Record<string, number> = {};
|
/** Keyed by `partLinkKey` — the (entry_id, part_id) pair — because two
|
||||||
|
* objects can carry the same part id, so part_id alone would merge pools. */
|
||||||
|
@state() private _usedParts: Record<string, TaskPartLink> = {};
|
||||||
|
|
||||||
public open(): void {
|
public open(): void {
|
||||||
if (this._open) return;
|
if (this._open) return;
|
||||||
@@ -55,8 +67,9 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
this._readingValue = "";
|
this._readingValue = "";
|
||||||
this._restockQty = this.restockDefault !== null ? String(this.restockDefault) : "";
|
this._restockQty = this.restockDefault !== null ? String(this.restockDefault) : "";
|
||||||
// #99: prefill "parts used" with the task's fixed links — the user can
|
// #99: prefill "parts used" with the task's fixed links — the user can
|
||||||
// untick or adjust before completing.
|
// untick or adjust before completing. The whole link is kept, entry_id
|
||||||
this._usedParts = Object.fromEntries(this.consumesParts.map((l) => [l.part_id, l.quantity]));
|
// included, so a shared pool survives the edit (#111).
|
||||||
|
this._usedParts = Object.fromEntries(this.consumesParts.map((l) => [partLinkKey(l), { ...l }]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _toggleCheck(idx: number): void {
|
private _toggleCheck(idx: number): void {
|
||||||
@@ -149,10 +162,16 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
}
|
}
|
||||||
// #99: with a parts section shown, send the explicit selection — it
|
// #99: with a parts section shown, send the explicit selection — it
|
||||||
// replaces the automatic consumes_parts deduction (empty = none used).
|
// replaces the automatic consumes_parts deduction (empty = none used).
|
||||||
|
// entry_id travels only when the pool is somebody else's (#111), so an
|
||||||
|
// own-part payload is byte-identical to what shipped before.
|
||||||
if (this.parts.length > 0) {
|
if (this.parts.length > 0) {
|
||||||
data.used_parts = Object.entries(this._usedParts)
|
data.used_parts = Object.values(this._usedParts)
|
||||||
.filter(([, qty]) => Number.isFinite(qty) && qty > 0)
|
.filter((l) => Number.isFinite(l.quantity) && l.quantity > 0)
|
||||||
.map(([part_id, quantity]) => ({ part_id, quantity }));
|
.map((l) =>
|
||||||
|
l.entry_id
|
||||||
|
? { part_id: l.part_id, quantity: l.quantity, entry_id: l.entry_id }
|
||||||
|
: { part_id: l.part_id, quantity: l.quantity },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
await this.hass.connection.sendMessagePromise(data);
|
await this.hass.connection.sendMessagePromise(data);
|
||||||
this._open = false;
|
this._open = false;
|
||||||
@@ -164,6 +183,28 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Required details the user has not supplied yet (drives Save + markers). */
|
||||||
|
private get _missingRequired(): string[] {
|
||||||
|
const filled: Record<string, boolean> = {
|
||||||
|
notes: this._notes.trim() !== "",
|
||||||
|
cost: this._cost.trim() !== "",
|
||||||
|
duration: this._duration.trim() !== "",
|
||||||
|
photo: this._photoDocId !== "",
|
||||||
|
// "Who did it" is filled in server-side from the authenticated
|
||||||
|
// connection (websocket/tasks_actions.py), so the dialog satisfies it
|
||||||
|
// as long as we ARE a logged-in user. Claiming it is always satisfied
|
||||||
|
// was how a task requiring "user" ended up unclosable: Save stayed
|
||||||
|
// enabled and the backend rejected the completion every time.
|
||||||
|
user: !!this.hass?.user,
|
||||||
|
};
|
||||||
|
return this.requiredFields.filter((f) => !filled[f]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Marker appended to a required field's label. */
|
||||||
|
private _req(field: string) {
|
||||||
|
return this.requiredFields.includes(field) ? html`<span class="req-mark" aria-hidden="true">*</span>` : nothing;
|
||||||
|
}
|
||||||
|
|
||||||
private _close(): void {
|
private _close(): void {
|
||||||
this._open = false;
|
this._open = false;
|
||||||
}
|
}
|
||||||
@@ -200,25 +241,36 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
? html`<div class="used-parts">
|
? html`<div class="used-parts">
|
||||||
<span class="field-label">${t("complete_parts_used", L)}</span>
|
<span class="field-label">${t("complete_parts_used", L)}</span>
|
||||||
${this.parts.map((pt) => {
|
${this.parts.map((pt) => {
|
||||||
const qty = this._usedParts[pt.id];
|
const key = partLinkKey({ part_id: pt.id, entry_id: pt.entry_id });
|
||||||
const checked = qty !== undefined;
|
const link = this._usedParts[key];
|
||||||
|
const checked = link !== undefined;
|
||||||
|
const base: TaskPartLink = pt.entry_id
|
||||||
|
? { part_id: pt.id, quantity: 1, entry_id: pt.entry_id }
|
||||||
|
: { part_id: pt.id, quantity: 1 };
|
||||||
return html`<div class="used-part-row">
|
return html`<div class="used-part-row">
|
||||||
<label class="used-part-check">
|
<label class="used-part-check">
|
||||||
<input type="checkbox" .checked=${checked}
|
<input type="checkbox" .checked=${checked}
|
||||||
@change=${(e: Event) => {
|
@change=${(e: Event) => {
|
||||||
const next = { ...this._usedParts };
|
const next = { ...this._usedParts };
|
||||||
if ((e.target as HTMLInputElement).checked) next[pt.id] = next[pt.id] || 1;
|
if ((e.target as HTMLInputElement).checked) next[key] = next[key] || base;
|
||||||
else delete next[pt.id];
|
else delete next[key];
|
||||||
this._usedParts = next;
|
this._usedParts = next;
|
||||||
}} />
|
}} />
|
||||||
<span>${pt.name}${pt.stock !== null && pt.stock !== undefined ? ` (${pt.stock}${pt.unit ? " " + pt.unit : ""})` : ""}</span>
|
<span
|
||||||
|
>${pt.name}${pt.owner_name
|
||||||
|
? html`<span class="used-part-owner"> (${pt.owner_name})</span>`
|
||||||
|
: nothing}${pt.stock !== null && pt.stock !== undefined ? ` (${pt.stock}${pt.unit ? " " + pt.unit : ""})` : ""}</span
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
${checked
|
${checked
|
||||||
? html`<input class="used-part-qty" type="number" min="0.01" max="999" step="0.01"
|
? html`<input class="used-part-qty" type="number" min="0.01" max="999" step="0.01"
|
||||||
.value=${String(qty)}
|
.value=${String(link.quantity)}
|
||||||
@input=${(e: Event) => {
|
@input=${(e: Event) => {
|
||||||
const v = parseFloat((e.target as HTMLInputElement).value);
|
const v = parseFloat((e.target as HTMLInputElement).value);
|
||||||
this._usedParts = { ...this._usedParts, [pt.id]: Number.isFinite(v) && v >= 0.01 ? v : 1 };
|
this._usedParts = {
|
||||||
|
...this._usedParts,
|
||||||
|
[key]: { ...base, quantity: Number.isFinite(v) && v >= 0.01 ? v : 1 },
|
||||||
|
};
|
||||||
}} />`
|
}} />`
|
||||||
: nothing}
|
: nothing}
|
||||||
</div>`;
|
</div>`;
|
||||||
@@ -245,25 +297,25 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
only sees the title + Cancel/Complete buttons — the original
|
only sees the title + Cancel/Complete buttons — the original
|
||||||
bug report. Native inputs always render. -->
|
bug report. Native inputs always render. -->
|
||||||
<label class="field">
|
<label class="field">
|
||||||
<span class="field-label">${t("notes_optional", L)}</span>
|
<span class="field-label">${t("notes_optional", L)}${this._req("notes")}</span>
|
||||||
<input type="text" class="field-input"
|
<input type="text" class="field-input"
|
||||||
.value=${this._notes}
|
.value=${this._notes}
|
||||||
@input=${(e: Event) => (this._notes = (e.target as HTMLInputElement).value)} />
|
@input=${(e: Event) => (this._notes = (e.target as HTMLInputElement).value)} />
|
||||||
</label>
|
</label>
|
||||||
<label class="field">
|
<label class="field">
|
||||||
<span class="field-label">${t("cost_optional", L)}</span>
|
<span class="field-label">${t("cost_optional", L)}${this._req("cost")}</span>
|
||||||
<input type="number" step="0.01" min="0" class="field-input"
|
<input type="number" step="0.01" min="0" class="field-input"
|
||||||
.value=${this._cost}
|
.value=${this._cost}
|
||||||
@input=${(e: Event) => (this._cost = (e.target as HTMLInputElement).value)} />
|
@input=${(e: Event) => (this._cost = (e.target as HTMLInputElement).value)} />
|
||||||
</label>
|
</label>
|
||||||
<label class="field">
|
<label class="field">
|
||||||
<span class="field-label">${t("duration_minutes", L)}</span>
|
<span class="field-label">${t("duration_minutes", L)}${this._req("duration")}</span>
|
||||||
<input type="number" step="0.01" min="0" class="field-input"
|
<input type="number" step="0.01" min="0" class="field-input"
|
||||||
.value=${this._duration}
|
.value=${this._duration}
|
||||||
@input=${(e: Event) => (this._duration = (e.target as HTMLInputElement).value)} />
|
@input=${(e: Event) => (this._duration = (e.target as HTMLInputElement).value)} />
|
||||||
</label>
|
</label>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<span class="field-label">${t("completion_photo_optional", L)}</span>
|
<span class="field-label">${t("completion_photo_optional", L)}${this._req("photo")}</span>
|
||||||
${this._photoPreview
|
${this._photoPreview
|
||||||
? html`
|
? html`
|
||||||
<div class="photo-preview">
|
<div class="photo-preview">
|
||||||
@@ -306,7 +358,10 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
</ha-button>
|
</ha-button>
|
||||||
<ha-button
|
<ha-button
|
||||||
@click=${this._complete}
|
@click=${this._complete}
|
||||||
.disabled=${this._loading}
|
.disabled=${this._loading || this._missingRequired.length > 0}
|
||||||
|
title=${this._missingRequired.length
|
||||||
|
? this._missingRequired.map((f) => t("err_required", L).replace("{field}", t(REQUIRED_COMPLETION_LABELS[f] ?? f, L))).join(" · ")
|
||||||
|
: ""}
|
||||||
>
|
>
|
||||||
${this._loading ? t("completing", L) : t("complete", L)}
|
${this._loading ? t("completing", L) : t("complete", L)}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
@@ -316,6 +371,11 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static styles = [nativeFieldStyles, css`
|
static styles = [nativeFieldStyles, css`
|
||||||
|
.req-mark {
|
||||||
|
color: var(--error-color, #f44336);
|
||||||
|
margin-left: 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
.dialog-title {
|
.dialog-title {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -348,6 +408,9 @@ export class MaintenanceCompleteDialog extends LitElement {
|
|||||||
font-size: 13px; cursor: pointer;
|
font-size: 13px; cursor: pointer;
|
||||||
}
|
}
|
||||||
.used-part-check input { cursor: pointer; }
|
.used-part-check input { cursor: pointer; }
|
||||||
|
/* #111: whose stock this row draws on. Muted but never omitted — an
|
||||||
|
unlabelled foreign pool is indistinguishable from an own part. */
|
||||||
|
.used-part-owner { color: var(--secondary-text-color); }
|
||||||
.used-part-qty {
|
.used-part-qty {
|
||||||
width: 76px; padding: 4px 6px; border-radius: 4px; font: inherit; font-size: 13px;
|
width: 76px; padding: 4px 6px; border-radius: 4px; font: inherit; font-size: 13px;
|
||||||
border: 1px solid var(--divider-color);
|
border: 1px solid var(--divider-color);
|
||||||
|
|||||||
@@ -155,9 +155,15 @@ export class MaintenanceQrDialog extends LitElement {
|
|||||||
const completeLabel = escapeHtml(t("qr_action_complete", L));
|
const completeLabel = escapeHtml(t("qr_action_complete", L));
|
||||||
|
|
||||||
w.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
w.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||||
|
<meta name="color-scheme" content="light">
|
||||||
<title>${safeTitle}</title>
|
<title>${safeTitle}</title>
|
||||||
<style>
|
<style>
|
||||||
body{font-family:sans-serif;text-align:center;padding:20px}
|
/* Printable sheet — must not inherit the phone's dark theme. The QR images
|
||||||
|
carry their own white quiet zone and stay scannable either way, but the
|
||||||
|
labels below are explicit dark greys and would vanish on a WebView's dark
|
||||||
|
canvas. Same reasoning as helpers/report.ts. */
|
||||||
|
:root{color-scheme:light}
|
||||||
|
body{font-family:sans-serif;text-align:center;padding:20px;background:#fff;color:#1a1a1a}
|
||||||
h2{margin:0 0 4px}
|
h2{margin:0 0 4px}
|
||||||
.sub{color:#666;font-size:14px;margin-bottom:16px}
|
.sub{color:#666;font-size:14px;margin-bottom:16px}
|
||||||
.qr-row{display:flex;justify-content:center;gap:24px;margin:12px 0}
|
.qr-row{display:flex;justify-content:center;gap:24px;margin:12px 0}
|
||||||
|
|||||||
@@ -9,6 +9,15 @@ import { UserService } from "../user-service";
|
|||||||
import { OBJECT_COLUMNS, sanitizeColumns } from "../helpers/object-columns";
|
import { OBJECT_COLUMNS, sanitizeColumns } from "../helpers/object-columns";
|
||||||
import { downloadTextFile } from "../helpers/download";
|
import { downloadTextFile } from "../helpers/download";
|
||||||
|
|
||||||
|
/** One household member and the notify services they actually resolve to.
|
||||||
|
* Empty `services` means no Companion device is linked, so their reminders
|
||||||
|
* fall back to the household notification service. */
|
||||||
|
interface PersonNotifyTarget {
|
||||||
|
user_id: string;
|
||||||
|
name: string;
|
||||||
|
services: string[];
|
||||||
|
}
|
||||||
|
|
||||||
/* Settings response shape from WS maintenance_supporter/settings */
|
/* Settings response shape from WS maintenance_supporter/settings */
|
||||||
interface SettingsResponse {
|
interface SettingsResponse {
|
||||||
features: AdvancedFeatures;
|
features: AdvancedFeatures;
|
||||||
@@ -27,6 +36,8 @@ interface SettingsResponse {
|
|||||||
notify_targets?: string[];
|
notify_targets?: string[];
|
||||||
panel_enabled: boolean;
|
panel_enabled: boolean;
|
||||||
panel_title: string;
|
panel_title: string;
|
||||||
|
/** Opt-in copy of the shipped Assist sentences into the config dir. */
|
||||||
|
install_assist_sentences?: boolean;
|
||||||
};
|
};
|
||||||
notifications: {
|
notifications: {
|
||||||
due_soon_enabled: boolean;
|
due_soon_enabled: boolean;
|
||||||
@@ -108,6 +119,8 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
@state() private _includeHistory = true;
|
@state() private _includeHistory = true;
|
||||||
@state() private _toast = "";
|
@state() private _toast = "";
|
||||||
@state() private _testingNotification = false;
|
@state() private _testingNotification = false;
|
||||||
|
@state() private _personTargets: PersonNotifyTarget[] = [];
|
||||||
|
@state() private _testingUser = "";
|
||||||
@state() private _users: HAUser[] = [];
|
@state() private _users: HAUser[] = [];
|
||||||
@state() private _savedViews: Array<{ id: string; name: string }> = [];
|
@state() private _savedViews: Array<{ id: string; name: string }> = [];
|
||||||
|
|
||||||
@@ -169,6 +182,23 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
} catch {
|
} catch {
|
||||||
this._users = [];
|
this._users = [];
|
||||||
}
|
}
|
||||||
|
this._loadNotifyTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Which notify services each household member resolves to.
|
||||||
|
*
|
||||||
|
* Resolved by the backend through the same helper the reminder path uses,
|
||||||
|
* so the list shown here is the list that will actually be used.
|
||||||
|
*/
|
||||||
|
private async _loadNotifyTargets(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const res = await this.hass.connection.sendMessagePromise<{ targets: PersonNotifyTarget[] }>({
|
||||||
|
type: "maintenance_supporter/notify/user_targets",
|
||||||
|
});
|
||||||
|
this._personTargets = res.targets || [];
|
||||||
|
} catch {
|
||||||
|
this._personTargets = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadSettings(): Promise<void> {
|
private async _loadSettings(): Promise<void> {
|
||||||
@@ -220,11 +250,13 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sendTestNotification = async (): Promise<void> => {
|
private _sendTestNotification = async (userId?: string): Promise<void> => {
|
||||||
this._testingNotification = true;
|
if (userId) this._testingUser = userId;
|
||||||
|
else this._testingNotification = true;
|
||||||
try {
|
try {
|
||||||
const res = await this.hass.connection.sendMessagePromise({
|
const res = await this.hass.connection.sendMessagePromise({
|
||||||
type: "maintenance_supporter/global/test_notification",
|
type: "maintenance_supporter/global/test_notification",
|
||||||
|
...(userId ? { user_id: userId } : {}),
|
||||||
}) as { success: boolean; message?: string };
|
}) as { success: boolean; message?: string };
|
||||||
const msg = res.message
|
const msg = res.message
|
||||||
|| (res.success ? t("test_notification_success", this._lang) : t("test_notification_failed", this._lang));
|
|| (res.success ? t("test_notification_success", this._lang) : t("test_notification_failed", this._lang));
|
||||||
@@ -232,7 +264,8 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
} catch {
|
} catch {
|
||||||
this._showToast(t("test_notification_failed", this._lang));
|
this._showToast(t("test_notification_failed", this._lang));
|
||||||
} finally {
|
} finally {
|
||||||
this._testingNotification = false;
|
if (userId) this._testingUser = "";
|
||||||
|
else this._testingNotification = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -570,6 +603,12 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
@change=${(e: Event) => this._updateSetting("panel_title", (e.target as HTMLInputElement).value.trim())} />
|
@change=${(e: Event) => this._updateSetting("panel_title", (e.target as HTMLInputElement).value.trim())} />
|
||||||
</label>
|
</label>
|
||||||
` : ""}
|
` : ""}
|
||||||
|
<label class="setting-row">
|
||||||
|
<span class="setting-label">${t("settings_install_assist_sentences", L)}</span>
|
||||||
|
<input type="checkbox" .checked=${g.install_assist_sentences ?? false}
|
||||||
|
@change=${(e: Event) => this._updateSetting("install_assist_sentences", (e.target as HTMLInputElement).checked)} />
|
||||||
|
</label>
|
||||||
|
<div class="setting-hint">${t("settings_install_assist_sentences_hint", L)}</div>
|
||||||
<label class="setting-row">
|
<label class="setting-row">
|
||||||
<span class="setting-label">${t("settings_notifications", L)}</span>
|
<span class="setting-label">${t("settings_notifications", L)}</span>
|
||||||
<input type="checkbox" .checked=${g.notifications_enabled}
|
<input type="checkbox" .checked=${g.notifications_enabled}
|
||||||
@@ -588,10 +627,28 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
<span class="setting-label">${t("test_notification", L)}</span>
|
<span class="setting-label">${t("test_notification", L)}</span>
|
||||||
<button class="ha-button secondary"
|
<button class="ha-button secondary"
|
||||||
?disabled=${!g.notify_service || this._testingNotification}
|
?disabled=${!g.notify_service || this._testingNotification}
|
||||||
@click=${this._sendTestNotification}>
|
@click=${() => this._sendTestNotification()}>
|
||||||
${this._testingNotification ? t("testing", L) : t("send_test", L)}
|
${this._testingNotification ? t("testing", L) : t("send_test", L)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
${this._personTargets.length ? html`
|
||||||
|
<div class="notify-per-person">
|
||||||
|
<span class="setting-label">${t("notify_per_person", L)}</span>
|
||||||
|
${this._personTargets.map((target) => html`
|
||||||
|
<div class="notify-person-row">
|
||||||
|
<span class="notify-person-name">${target.name}</span>
|
||||||
|
<span class="notify-person-target ${target.services.length ? "" : "muted"}">
|
||||||
|
${target.services.length ? target.services.join(", ") : t("notify_no_own_device", L)}
|
||||||
|
</span>
|
||||||
|
<button class="ha-button secondary"
|
||||||
|
?disabled=${!target.services.length || this._testingUser === target.user_id}
|
||||||
|
@click=${() => this._sendTestNotification(target.user_id)}>
|
||||||
|
${this._testingUser === target.user_id ? t("testing", L) : t("send_test", L)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
` : nothing}
|
||||||
` : nothing}
|
` : nothing}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -1606,6 +1663,31 @@ export class MaintenanceSettingsView extends LitElement {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
.notify-per-person {
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid var(--divider-color, #e0e0e0);
|
||||||
|
}
|
||||||
|
.notify-person-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 6px 0 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.notify-person-name {
|
||||||
|
font-weight: 500;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
.notify-person-target {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 160px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
word-break: break-word;
|
||||||
|
color: var(--secondary-text-color, #727272);
|
||||||
|
}
|
||||||
|
.notify-person-target.muted {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
/* v2.27: template gallery clustered by category */
|
/* v2.27: template gallery clustered by category */
|
||||||
.tpl-group { margin-top: 14px; }
|
.tpl-group { margin-top: 14px; }
|
||||||
.tpl-group-head {
|
.tpl-group-head {
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
import { LitElement, html, css, nothing } from "lit";
|
import { LitElement, html, css, nothing } from "lit";
|
||||||
import { property, state } from "lit/decorators.js";
|
import { property, state } from "lit/decorators.js";
|
||||||
import type { AdaptiveConfig, HomeAssistant, MaintenanceTask, TriggerConfig, HAUser } from "../types";
|
import type { AdaptiveConfig, HomeAssistant, MaintenanceTask, TaskPartLink, TriggerConfig, HAUser } from "../types";
|
||||||
import { formatDate, t, weekdayName } from "../styles";
|
import { formatDate, t, weekdayName } from "../styles";
|
||||||
import { UserService } from "../user-service";
|
import { UserService } from "../user-service";
|
||||||
|
import { partLinkKey } from "../helpers/shared-parts";
|
||||||
|
|
||||||
import { describeWsError } from "../ws-errors";
|
import { describeWsError } from "../ws-errors";
|
||||||
|
import { REQUIRED_COMPLETION_KEYS, REQUIRED_COMPLETION_LABELS } from "./required-completion-labels";
|
||||||
import "./ms-textfield";
|
import "./ms-textfield";
|
||||||
|
|
||||||
const MAINTENANCE_TYPE_KEYS = ["cleaning", "inspection", "replacement", "calibration", "service", "reading", "custom"];
|
const MAINTENANCE_TYPE_KEYS = ["cleaning", "inspection", "replacement", "calibration", "service", "reading", "custom"];
|
||||||
@@ -122,6 +124,14 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
@property({ type: Number, attribute: "default-warning-days" }) public defaultWarningDays = 7;
|
@property({ type: Number, attribute: "default-warning-days" }) public defaultWarningDays = 7;
|
||||||
/** The object's spare parts — offered as "consumes parts" checkboxes. */
|
/** The object's spare parts — offered as "consumes parts" checkboxes. */
|
||||||
@state() private parts: Array<{ id: string; name: string; unit?: string }> = [];
|
@state() private parts: Array<{ id: string; name: string; unit?: string }> = [];
|
||||||
|
/** #111: OTHER objects that own spare parts, so a task can draw on a shared
|
||||||
|
* pool (three vacuums, one box of dust bags). Grouped by owner in the UI —
|
||||||
|
* which pool a link means must never be a guess. */
|
||||||
|
@state() private _foreignOwners: Array<{
|
||||||
|
entry_id: string;
|
||||||
|
name: string;
|
||||||
|
parts: Array<{ id: string; name: string; unit?: string }>;
|
||||||
|
}> = [];
|
||||||
@state() private _open = false;
|
@state() private _open = false;
|
||||||
@state() private _loading = false;
|
@state() private _loading = false;
|
||||||
@state() private _error = "";
|
@state() private _error = "";
|
||||||
@@ -210,7 +220,9 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
@state() private _nfcTagId = "";
|
@state() private _nfcTagId = "";
|
||||||
// v2.20 (#83): unit for `reading`-type tasks ("kWh", "m³", ...)
|
// v2.20 (#83): unit for `reading`-type tasks ("kWh", "m³", ...)
|
||||||
@state() private _readingUnit = "";
|
@state() private _readingUnit = "";
|
||||||
@state() private _consumesParts: Record<string, number> = {};
|
/** The picked links, keyed by `partLinkKey` — the (entry_id, part_id) pair,
|
||||||
|
* since the same part id can exist on two objects (battery fleet). */
|
||||||
|
@state() private _consumesParts: Record<string, TaskPartLink> = {};
|
||||||
@state() private _partsLoadFailed = false;
|
@state() private _partsLoadFailed = false;
|
||||||
@state() private _availableTags: Array<{id: string; name: string}> = [];
|
@state() private _availableTags: Array<{id: string; name: string}> = [];
|
||||||
|
|
||||||
@@ -222,6 +234,9 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
|
|
||||||
// Checklist (newline-separated steps, one per line)
|
// Checklist (newline-separated steps, one per line)
|
||||||
@state() private _checklistText = "";
|
@state() private _checklistText = "";
|
||||||
|
/** Details this task demands on completion — enforced by the backend on
|
||||||
|
* every surface, so a button press or voice command cannot bypass it. */
|
||||||
|
@state() private _requiredCompletion: string[] = [];
|
||||||
|
|
||||||
// Schedule time (HH:MM, advanced feature)
|
// Schedule time (HH:MM, advanced feature)
|
||||||
@state() private _scheduleTime = "";
|
@state() private _scheduleTime = "";
|
||||||
@@ -271,7 +286,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
this._objectChoices = [];
|
this._objectChoices = [];
|
||||||
}
|
}
|
||||||
this._resetFields();
|
this._resetFields();
|
||||||
await Promise.all([this._loadUsers(), this._loadTags(), this._loadParts()]);
|
await Promise.all([this._loadUsers(), this._loadTags(), this._loadParts(), this._loadForeignPools()]);
|
||||||
this._open = true;
|
this._open = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,12 +336,17 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
this._lastPerformed = task.last_performed || "";
|
this._lastPerformed = task.last_performed || "";
|
||||||
this._nfcTagId = task.nfc_tag_id || "";
|
this._nfcTagId = task.nfc_tag_id || "";
|
||||||
this._readingUnit = task.reading_unit || "";
|
this._readingUnit = task.reading_unit || "";
|
||||||
this._consumesParts = Object.fromEntries((task.consumes_parts || []).map((l) => [l.part_id, l.quantity]));
|
// Whole link, entry_id included — hydrating only part_id would turn every
|
||||||
|
// shared-pool link into an own-part link on the next save (#111).
|
||||||
|
this._consumesParts = Object.fromEntries(
|
||||||
|
(task.consumes_parts || []).map((l) => [partLinkKey(l), { ...l }]),
|
||||||
|
);
|
||||||
this._responsibleUserId = task.responsible_user_id || null;
|
this._responsibleUserId = task.responsible_user_id || null;
|
||||||
this._assigneePool = [...(task.assignee_pool || [])];
|
this._assigneePool = [...(task.assignee_pool || [])];
|
||||||
this._rotationStrategy = task.rotation_strategy || "";
|
this._rotationStrategy = task.rotation_strategy || "";
|
||||||
|
|
||||||
this._checklistText = (task.checklist || []).join("\n");
|
this._checklistText = (task.checklist || []).join("\n");
|
||||||
|
this._requiredCompletion = [...(task.required_completion_fields || [])];
|
||||||
this._scheduleTime = task.schedule_time || "";
|
this._scheduleTime = task.schedule_time || "";
|
||||||
|
|
||||||
// v1.3.0: hydrate on_complete_action + quick_complete_defaults
|
// v1.3.0: hydrate on_complete_action + quick_complete_defaults
|
||||||
@@ -395,7 +415,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
this._fetchEntityAttributes(this._triggerEntityId);
|
this._fetchEntityAttributes(this._triggerEntityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([this._loadUsers(), this._loadTags(), this._loadParts()]);
|
await Promise.all([this._loadUsers(), this._loadTags(), this._loadParts(), this._loadForeignPools()]);
|
||||||
this._open = true;
|
this._open = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +454,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
this._assigneePool = [];
|
this._assigneePool = [];
|
||||||
this._rotationStrategy = "";
|
this._rotationStrategy = "";
|
||||||
this._checklistText = "";
|
this._checklistText = "";
|
||||||
|
this._requiredCompletion = [];
|
||||||
this._scheduleTime = "";
|
this._scheduleTime = "";
|
||||||
this._environmentalEntity = "";
|
this._environmentalEntity = "";
|
||||||
this._environmentalAttribute = "";
|
this._environmentalAttribute = "";
|
||||||
@@ -736,6 +757,40 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** #111: the other objects' spare-part pools this task could draw on.
|
||||||
|
*
|
||||||
|
* A sibling of `_loadParts`, run in the SAME Promise.all rather than nested
|
||||||
|
* inside it: chaining it after the own-parts fetch delays the dialog opening
|
||||||
|
* by a further round trip for a list that is secondary to it.
|
||||||
|
*
|
||||||
|
* Failure is soft on purpose — the own-parts picker is the primary path and
|
||||||
|
* must not disappear because this second call did not come back. */
|
||||||
|
private async _loadForeignPools(): Promise<void> {
|
||||||
|
this._foreignOwners = [];
|
||||||
|
if (!this._entryId) return;
|
||||||
|
try {
|
||||||
|
const result = (await this.hass.connection.sendMessagePromise({
|
||||||
|
type: "maintenance_supporter/objects",
|
||||||
|
})) as {
|
||||||
|
objects?: Array<{
|
||||||
|
entry_id: string;
|
||||||
|
object?: { name?: string };
|
||||||
|
parts?: Array<{ id: string; name: string; unit?: string }>;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
this._foreignOwners = (result.objects || [])
|
||||||
|
.filter((o) => o.entry_id !== this._entryId && (o.parts || []).length > 0)
|
||||||
|
.map((o) => ({
|
||||||
|
entry_id: o.entry_id,
|
||||||
|
name: o.object?.name || o.entry_id,
|
||||||
|
parts: o.parts || [],
|
||||||
|
}))
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
} catch {
|
||||||
|
this._foreignOwners = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async _loadTags(): Promise<void> {
|
private async _loadTags(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const result = await this.hass.connection.sendMessagePromise({
|
const result = await this.hass.connection.sendMessagePromise({
|
||||||
@@ -773,6 +828,69 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A task already drawing on a shared pool opens that section expanded — a
|
||||||
|
* collapsed disclosure would hide a link that is very much active. */
|
||||||
|
private get _hasForeignPick(): boolean {
|
||||||
|
return Object.values(this._consumesParts).some((l) => !!l.entry_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** One "consumes parts" checkbox + quantity.
|
||||||
|
*
|
||||||
|
* `ownerEntryId` is undefined for the object's own parts and set for a pool
|
||||||
|
* owned by another object (#111) — that argument is the ONLY difference
|
||||||
|
* between the two lists, which is why they share this renderer. */
|
||||||
|
private _renderConsumesRow(
|
||||||
|
part: { id: string; name: string; unit?: string },
|
||||||
|
ownerEntryId?: string,
|
||||||
|
) {
|
||||||
|
const key = partLinkKey({ part_id: part.id, entry_id: ownerEntryId });
|
||||||
|
const link = this._consumesParts[key];
|
||||||
|
const base: TaskPartLink = ownerEntryId
|
||||||
|
? { part_id: part.id, quantity: 1, entry_id: ownerEntryId }
|
||||||
|
: { part_id: part.id, quantity: 1 };
|
||||||
|
return html`
|
||||||
|
<div class="consumes-row">
|
||||||
|
<label class="consumes-check">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${link !== undefined}
|
||||||
|
@change=${(e: Event) => {
|
||||||
|
const next = { ...this._consumesParts };
|
||||||
|
if ((e.target as HTMLInputElement).checked) next[key] = next[key] || base;
|
||||||
|
else delete next[key];
|
||||||
|
this._consumesParts = next;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>${part.name}${part.unit ? ` (${part.unit})` : ""}</span>
|
||||||
|
</label>
|
||||||
|
${link !== undefined
|
||||||
|
? html`<input
|
||||||
|
class="consumes-qty"
|
||||||
|
type="number"
|
||||||
|
min="0.01"
|
||||||
|
max="999"
|
||||||
|
step="0.01"
|
||||||
|
.value=${String(link.quantity)}
|
||||||
|
@input=${(e: Event) => {
|
||||||
|
const v = parseFloat((e.target as HTMLInputElement).value);
|
||||||
|
this._consumesParts = {
|
||||||
|
...this._consumesParts,
|
||||||
|
[key]: { ...base, quantity: Number.isFinite(v) && v >= 0.01 ? v : 1 },
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>`
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleRequired(field: string, on: boolean): void {
|
||||||
|
const next = new Set(this._requiredCompletion);
|
||||||
|
if (on) next.add(field);
|
||||||
|
else next.delete(field);
|
||||||
|
this._requiredCompletion = [...next];
|
||||||
|
}
|
||||||
|
|
||||||
private async _save(): Promise<void> {
|
private async _save(): Promise<void> {
|
||||||
if (this._loading) return; // synchronous re-entry guard (double-click)
|
if (this._loading) return; // synchronous re-entry guard (double-click)
|
||||||
if (!this._name.trim()) return;
|
if (!this._name.trim()) return;
|
||||||
@@ -787,7 +905,16 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
name: this._name,
|
name: this._name,
|
||||||
task_type: this._type,
|
task_type: this._type,
|
||||||
schedule_type: this._scheduleType,
|
schedule_type: this._scheduleType,
|
||||||
warning_days: parseInt(this._warningDays, 10) || 7,
|
// `0` is a legal, meaningful value — "no due-soon window, go straight
|
||||||
|
// from ok to overdue" (backend range is 0–365). The old
|
||||||
|
// `parseInt(...) || 7` treated it as falsy and silently rewrote a
|
||||||
|
// stored 0 to 7 on EVERY save, even when the user never touched the
|
||||||
|
// field. Same class as bug #42, but worse: it needed no user action.
|
||||||
|
// Only a genuinely unparseable field falls back, and to the
|
||||||
|
// configured default rather than a hardcoded 7.
|
||||||
|
warning_days: Number.isNaN(parseInt(this._warningDays, 10))
|
||||||
|
? this.defaultWarningDays
|
||||||
|
: Math.max(0, parseInt(this._warningDays, 10)),
|
||||||
};
|
};
|
||||||
const ecd = this._earliestCompletionDays.trim();
|
const ecd = this._earliestCompletionDays.trim();
|
||||||
data.earliest_completion_days = ecd === "" ? null : Math.max(0, parseInt(ecd, 10) || 0);
|
data.earliest_completion_days = ecd === "" ? null : Math.max(0, parseInt(ecd, 10) || 0);
|
||||||
@@ -836,14 +963,20 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
data.last_performed = this._lastPerformed || null;
|
data.last_performed = this._lastPerformed || null;
|
||||||
data.nfc_tag_id = this._nfcTagId || null;
|
data.nfc_tag_id = this._nfcTagId || null;
|
||||||
data.reading_unit = this._readingUnit.trim() || null;
|
data.reading_unit = this._readingUnit.trim() || null;
|
||||||
if (this.parts.length) {
|
// Only send when a picker was actually rendered. A failed parts load
|
||||||
data.consumes_parts = Object.entries(this._consumesParts).map(([part_id, quantity]) => ({
|
// leaves both lists empty, and sending [] then would silently wipe links
|
||||||
part_id,
|
// the user never saw. entry_id is written ONLY for a foreign pick, so an
|
||||||
quantity,
|
// own-parts task saves byte-identically to before (#111).
|
||||||
}));
|
if (this.parts.length || this._foreignOwners.length) {
|
||||||
|
data.consumes_parts = Object.values(this._consumesParts).map((l) =>
|
||||||
|
l.entry_id
|
||||||
|
? { part_id: l.part_id, quantity: l.quantity, entry_id: l.entry_id }
|
||||||
|
: { part_id: l.part_id, quantity: l.quantity },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
data.responsible_user_id = this._responsibleUserId;
|
data.responsible_user_id = this._responsibleUserId;
|
||||||
data.assignee_pool = this._assigneePool;
|
data.assignee_pool = this._assigneePool;
|
||||||
|
data.required_completion_fields = this._requiredCompletion;
|
||||||
data.rotation_strategy =
|
data.rotation_strategy =
|
||||||
this._assigneePool.length >= 2 && this._rotationStrategy
|
this._assigneePool.length >= 2 && this._rotationStrategy
|
||||||
? this._rotationStrategy
|
? this._rotationStrategy
|
||||||
@@ -1700,6 +1833,9 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
this._entryId = (e.target as HTMLSelectElement).value;
|
this._entryId = (e.target as HTMLSelectElement).value;
|
||||||
this._consumesParts = {};
|
this._consumesParts = {};
|
||||||
this._loadParts();
|
this._loadParts();
|
||||||
|
// The new owner drops out of the shared-pool list and the old
|
||||||
|
// one joins it, so this has to be recomputed too (#111).
|
||||||
|
this._loadForeignPools();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
${this._objectChoices.map(
|
${this._objectChoices.map(
|
||||||
@@ -1738,44 +1874,27 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
${this._partsLoadFailed
|
${this._partsLoadFailed
|
||||||
? html`<div class="field-help parts-load-failed">${t("parts_load_failed", L)}</div>`
|
? html`<div class="field-help parts-load-failed">${t("parts_load_failed", L)}</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
${this.parts.length
|
${this.parts.length || this._foreignOwners.length
|
||||||
? html`
|
? html`
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>${t("consumes_parts_label", L)}</label>
|
<label>${t("consumes_parts_label", L)}</label>
|
||||||
${this.parts.map((part) => {
|
${this.parts.map((part) => this._renderConsumesRow(part))}
|
||||||
const qty = this._consumesParts[part.id];
|
${this._foreignOwners.length
|
||||||
return html`
|
? html`
|
||||||
<div class="consumes-row">
|
<details class="shared-pools" ?open=${this._hasForeignPick}>
|
||||||
<label class="consumes-check">
|
<summary>${t("shared_parts_other_objects", L)}</summary>
|
||||||
<input
|
<div class="field-help">${t("shared_parts_help", L)}</div>
|
||||||
type="checkbox"
|
${this._foreignOwners.map(
|
||||||
.checked=${qty !== undefined}
|
(owner) => html`
|
||||||
@change=${(e: Event) => {
|
<div class="shared-pool-owner">${owner.name}</div>
|
||||||
const next = { ...this._consumesParts };
|
${owner.parts.map((part) =>
|
||||||
if ((e.target as HTMLInputElement).checked) next[part.id] = next[part.id] || 1;
|
this._renderConsumesRow(part, owner.entry_id),
|
||||||
else delete next[part.id];
|
)}
|
||||||
this._consumesParts = next;
|
`,
|
||||||
}}
|
)}
|
||||||
/>
|
</details>
|
||||||
<span>${part.name}${part.unit ? ` (${part.unit})` : ""}</span>
|
`
|
||||||
</label>
|
: nothing}
|
||||||
${qty !== undefined
|
|
||||||
? html`<input
|
|
||||||
class="consumes-qty"
|
|
||||||
type="number"
|
|
||||||
min="0.01"
|
|
||||||
max="999"
|
|
||||||
step="0.01"
|
|
||||||
.value=${String(qty)}
|
|
||||||
@input=${(e: Event) => {
|
|
||||||
const v = parseFloat((e.target as HTMLInputElement).value);
|
|
||||||
this._consumesParts = { ...this._consumesParts, [part.id]: Number.isFinite(v) && v >= 0.01 ? v : 1 };
|
|
||||||
}}
|
|
||||||
/>`
|
|
||||||
: nothing}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
@@ -1857,6 +1976,8 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
<ms-textfield
|
<ms-textfield
|
||||||
label="${t("warning_days", L)}"
|
label="${t("warning_days", L)}"
|
||||||
type="number"
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="365"
|
||||||
.value=${this._warningDays}
|
.value=${this._warningDays}
|
||||||
@input=${(e: Event) => (this._warningDays = (e.target as HTMLInputElement).value)}
|
@input=${(e: Event) => (this._warningDays = (e.target as HTMLInputElement).value)}
|
||||||
></ms-textfield>
|
></ms-textfield>
|
||||||
@@ -1879,6 +2000,19 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
></textarea>
|
></textarea>
|
||||||
<div class="field-help">${t("checklist_help", L)}</div>
|
<div class="field-help">${t("checklist_help", L)}</div>
|
||||||
` : nothing}
|
` : nothing}
|
||||||
|
<h3>${t("require_on_completion", L)}</h3>
|
||||||
|
<div class="required-completion">
|
||||||
|
${REQUIRED_COMPLETION_KEYS.map((field) => html`
|
||||||
|
<label class="req-option">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${this._requiredCompletion.includes(field)}
|
||||||
|
@change=${(e: Event) => this._toggleRequired(field, (e.target as HTMLInputElement).checked)}
|
||||||
|
/>
|
||||||
|
<span>${t(REQUIRED_COMPLETION_LABELS[field], L)}</span>
|
||||||
|
</label>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
<ms-textfield
|
<ms-textfield
|
||||||
label="${t("last_performed_optional", L)}"
|
label="${t("last_performed_optional", L)}"
|
||||||
type="date"
|
type="date"
|
||||||
@@ -2127,6 +2261,24 @@ export class MaintenanceTaskDialog extends LitElement {
|
|||||||
background: var(--card-background-color);
|
background: var(--card-background-color);
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
/* #111: other objects' pools sit behind a disclosure so the object's OWN
|
||||||
|
parts stay the primary list; each group is headed by the owning object's
|
||||||
|
name, so which pool a checkbox means is never a guess. */
|
||||||
|
.shared-pools {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.shared-pools > summary {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 2px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.shared-pool-owner {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
.field-help {
|
.field-help {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
|||||||
+4
-2
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import { LitElement, html, css, nothing } from "lit";
|
import { LitElement, html, css, nothing } from "lit";
|
||||||
import { property, state } from "lit/decorators.js";
|
import { property, state } from "lit/decorators.js";
|
||||||
import { sharedStyles, t, STATUS_COLORS, formatDate, formatDateTime, formatRecurrence } from "../styles";
|
import { sharedStyles, t, STATUS_COLORS, formatDate, formatDateTime, formatInterval, formatRecurrence } from "../styles";
|
||||||
import { describeWsError } from "../ws-errors";
|
import { describeWsError } from "../ws-errors";
|
||||||
import { renderWeibullSection } from "../renderers/weibull";
|
import { renderWeibullSection } from "../renderers/weibull";
|
||||||
import { renderPredictionSection } from "../renderers/prediction";
|
import { renderPredictionSection } from "../renderers/prediction";
|
||||||
@@ -294,7 +294,9 @@ export class MaintenanceTaskQuickActionsDialog extends LitElement {
|
|||||||
task_id: this._taskId,
|
task_id: this._taskId,
|
||||||
});
|
});
|
||||||
this._toast = r.recommended_interval
|
this._toast = r.recommended_interval
|
||||||
? `${t("reanalyze_result", this._lang) || "Recomputed"}: ${r.recommended_interval}d (${r.data_points} pts)`
|
// The analyzer always works in DAYS (helpers/interval_analyzer.py), so
|
||||||
|
// the unit is pinned here rather than taken from the task's own unit.
|
||||||
|
? `${t("reanalyze_result", this._lang) || "Recomputed"}: ${formatInterval(r.recommended_interval, "days", this._lang)} (${r.data_points} pts)`
|
||||||
: (t("reanalyze_insufficient_data", this._lang) || "Not enough data");
|
: (t("reanalyze_insufficient_data", this._lang) || "Not enough data");
|
||||||
await this._loadTask();
|
await this._loadTask();
|
||||||
setTimeout(() => { this._toast = ""; }, 3500);
|
setTimeout(() => { this._toast = ""; }, 3500);
|
||||||
|
|||||||
@@ -252,6 +252,8 @@ export function openCompleteDialog(args: {
|
|||||||
task_name: string;
|
task_name: string;
|
||||||
checklist?: string[];
|
checklist?: string[];
|
||||||
adaptive_enabled?: boolean;
|
adaptive_enabled?: boolean;
|
||||||
|
/** Details the task demands before it counts as done (v2.44). */
|
||||||
|
required_completion_fields?: string[];
|
||||||
}): boolean {
|
}): boolean {
|
||||||
const dlg = getOrCreate<MaintenanceCompleteDialog>(COMPLETE_DIALOG_TAG);
|
const dlg = getOrCreate<MaintenanceCompleteDialog>(COMPLETE_DIALOG_TAG);
|
||||||
if (!syncHass(dlg)) return false;
|
if (!syncHass(dlg)) return false;
|
||||||
@@ -260,6 +262,7 @@ export function openCompleteDialog(args: {
|
|||||||
dlg.taskName = args.task_name;
|
dlg.taskName = args.task_name;
|
||||||
dlg.checklist = args.checklist ?? [];
|
dlg.checklist = args.checklist ?? [];
|
||||||
dlg.adaptiveEnabled = !!args.adaptive_enabled;
|
dlg.adaptiveEnabled = !!args.adaptive_enabled;
|
||||||
|
dlg.requiredFields = args.required_completion_fields ?? [];
|
||||||
dlg.lang = (getHass()?.language) || "en";
|
dlg.lang = (getHass()?.language) || "en";
|
||||||
dlg.open();
|
dlg.open();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ const common = {
|
|||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
external: [],
|
external: [],
|
||||||
define: { __MS_BUNDLE_VERSION__: JSON.stringify(manifestVersion) },
|
define: { __MS_BUNDLE_VERSION__: JSON.stringify(manifestVersion) },
|
||||||
|
// A readable banner as well as the define. After the minifier is done the
|
||||||
|
// stamped version survives only as `var xy="2.44.1"` with a generated name,
|
||||||
|
// which nothing outside the bundle can reliably find — so 2.44.0 shipped a
|
||||||
|
// bundle built before the version bump and every install showed a permanent
|
||||||
|
// "reload the panel" banner (#112). This line is what
|
||||||
|
// tests/test_frontend_bundle_version.py checks, and it also lets anyone read
|
||||||
|
// the built version straight out of devtools.
|
||||||
|
banner: { js: `/*! maintenance_supporter frontend ${manifestVersion} */` },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Panel
|
// Panel
|
||||||
|
|||||||
@@ -73,10 +73,19 @@ export function buildObjectReportHtml(
|
|||||||
const totalCost = tasks.reduce((n, t) => n + (t.total_cost ?? 0), 0);
|
const totalCost = tasks.reduce((n, t) => n + (t.total_cost ?? 0), 0);
|
||||||
|
|
||||||
return `<!DOCTYPE html><html><head><meta charset="utf-8">
|
return `<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||||
|
<meta name="color-scheme" content="light">
|
||||||
<title>${esc(labels.title)} — ${esc(obj.name)}</title>
|
<title>${esc(labels.title)} — ${esc(obj.name)}</title>
|
||||||
<style>
|
<style>
|
||||||
|
/* This is a PRINTABLE sheet, not part of the app's theme: it opens as a
|
||||||
|
blob in whatever viewer the OS supplies. In the Companion app that is a
|
||||||
|
WebView, and a WebView on a dark-themed phone paints a DARK default
|
||||||
|
canvas — against which the dark body text below disappeared completely,
|
||||||
|
leaving only the pale row borders showing as stripes. Declaring the
|
||||||
|
scheme AND painting the background keeps the sheet identical everywhere,
|
||||||
|
and matches what comes out of a printer. */
|
||||||
|
:root { color-scheme: light; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
body { font: 13px/1.5 -apple-system, Segoe UI, Roboto, sans-serif; color: #1a1a1a; margin: 32px; }
|
body { font: 13px/1.5 -apple-system, Segoe UI, Roboto, sans-serif; color: #1a1a1a; background: #fff; margin: 32px; }
|
||||||
h1 { font-size: 22px; margin: 0 0 2px; }
|
h1 { font-size: 22px; margin: 0 0 2px; }
|
||||||
.sub { color: #666; margin: 0 0 20px; }
|
.sub { color: #666; margin: 0 0 20px; }
|
||||||
.meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 6px 24px; margin-bottom: 20px; }
|
.meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 6px 24px; margin-bottom: 20px; }
|
||||||
|
|||||||
@@ -83,11 +83,17 @@ export function buildTaskWorksheetHtml(
|
|||||||
: "";
|
: "";
|
||||||
|
|
||||||
return `<!DOCTYPE html>
|
return `<!DOCTYPE html>
|
||||||
<html><head><meta charset="utf-8"><title>${esc(task.name)} — ${esc(L.title)}</title>
|
<html><head><meta charset="utf-8"><meta name="color-scheme" content="light">
|
||||||
|
<title>${esc(task.name)} — ${esc(L.title)}</title>
|
||||||
<style>
|
<style>
|
||||||
|
/* A work sheet is meant to be printed or read as a sheet, so it must not
|
||||||
|
inherit the phone's dark theme: the Companion app opens it in a WebView
|
||||||
|
that paints a dark canvas, and this dark text would vanish against it.
|
||||||
|
See the same note in report.ts. */
|
||||||
|
:root { color-scheme: light; }
|
||||||
@page { size: A4; margin: 14mm; }
|
@page { size: A4; margin: 14mm; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
body { font: 13px/1.45 -apple-system, "Segoe UI", Roboto, sans-serif; color: #111; margin: 0; }
|
body { font: 13px/1.45 -apple-system, "Segoe UI", Roboto, sans-serif; color: #111; background: #fff; margin: 0; }
|
||||||
header { display: flex; justify-content: space-between; align-items: flex-start;
|
header { display: flex; justify-content: space-between; align-items: flex-start;
|
||||||
border-bottom: 3px solid #111; padding-bottom: 8px; margin-bottom: 12px; }
|
border-bottom: 3px solid #111; padding-bottom: 8px; margin-bottom: 12px; }
|
||||||
h1 { font-size: 22px; margin: 0 0 2px; }
|
h1 { font-size: 22px; margin: 0 0 2px; }
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Hodnota spouštěče",
|
"trigger_val": "Hodnota spouštěče",
|
||||||
"complete_title": "Dokončit: ",
|
"complete_title": "Dokončit: ",
|
||||||
"checklist": "Kontrolní seznam",
|
"checklist": "Kontrolní seznam",
|
||||||
|
"require_on_completion": "Vyžadovat při dokončení",
|
||||||
"checklist_steps_optional": "Kroky kontrolního seznamu (volitelné)",
|
"checklist_steps_optional": "Kroky kontrolního seznamu (volitelné)",
|
||||||
"checklist_placeholder": "Vyčistit filtr\nVyměnit těsnění\nOtestovat tlak",
|
"checklist_placeholder": "Vyčistit filtr\nVyměnit těsnění\nOtestovat tlak",
|
||||||
"checklist_help": "Jeden krok na řádek. Max 100 položek.",
|
"checklist_help": "Jeden krok na řádek. Max 100 položek.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Prázdné = zobrazit všechny stavy.",
|
"card_filter_status_help": "Prázdné = zobrazit všechny stavy.",
|
||||||
"card_filter_objects": "Filtrovat podle objektů",
|
"card_filter_objects": "Filtrovat podle objektů",
|
||||||
"card_filter_objects_help": "Prázdné = zobrazit všechny objekty.",
|
"card_filter_objects_help": "Prázdné = zobrazit všechny objekty.",
|
||||||
|
"card_filter_areas": "Filtrovat podle oblastí",
|
||||||
|
"card_filter_areas_help": "Prázdné = zobrazit všechny oblasti.",
|
||||||
"card_filter_entities": "Filtrovat podle entit (entity_ids)",
|
"card_filter_entities": "Filtrovat podle entit (entity_ids)",
|
||||||
"card_filter_entities_help": "Vyberte entity sensor / binary_sensor z této integrace. Prázdné = všechny.",
|
"card_filter_entities_help": "Vyberte entity sensor / binary_sensor z této integrace. Prázdné = všechny.",
|
||||||
"card_loading_objects": "Načítání objektů…",
|
"card_loading_objects": "Načítání objektů…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Název panelu",
|
"settings_panel_title": "Název panelu",
|
||||||
"settings_notifications": "Oznámení",
|
"settings_notifications": "Oznámení",
|
||||||
"settings_notify_service": "Služba oznámení",
|
"settings_notify_service": "Služba oznámení",
|
||||||
|
"settings_install_assist_sentences": "Nainstalovat věty pro Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Zkopíruje hlasové věty do vaší konfigurace, aby je klasický agent Assist rozpoznal. Soubor, který jste upravili, nebude nikdy přepsán.",
|
||||||
"test_notification": "Testovací oznámení",
|
"test_notification": "Testovací oznámení",
|
||||||
"send_test": "Odeslat test",
|
"send_test": "Odeslat test",
|
||||||
"testing": "Odesílání…",
|
"testing": "Odesílání…",
|
||||||
"test_notification_success": "Testovací oznámení odesláno",
|
"test_notification_success": "Testovací oznámení odesláno",
|
||||||
"test_notification_failed": "Testovací oznámení se nezdařilo",
|
"test_notification_failed": "Testovací oznámení se nezdařilo",
|
||||||
|
"notify_per_person": "Doručování podle osoby",
|
||||||
|
"notify_no_own_device": "Žádné vlastní zařízení — použije domácí službu",
|
||||||
"settings_notify_due_soon": "Oznámit když brzy",
|
"settings_notify_due_soon": "Oznámit když brzy",
|
||||||
"settings_notify_overdue": "Oznámit když po termínu",
|
"settings_notify_overdue": "Oznámit když po termínu",
|
||||||
"settings_notify_triggered": "Oznámit když spuštěno",
|
"settings_notify_triggered": "Oznámit když spuštěno",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Podle uživatele",
|
"groupby_user": "Podle uživatele",
|
||||||
"filter_label": "Filtr",
|
"filter_label": "Filtr",
|
||||||
"user_label": "Uživatel",
|
"user_label": "Uživatel",
|
||||||
|
"photo_label": "Fotografie",
|
||||||
"sort_label": "Řazení",
|
"sort_label": "Řazení",
|
||||||
"group_by_label": "Seskupit podle",
|
"group_by_label": "Seskupit podle",
|
||||||
"state_value_help": "Použijte hodnotu stavu HA (obvykle malými písmeny, např. \"on\"/\"off\"). Velikost písmen se při uložení normalizuje.",
|
"state_value_help": "Použijte hodnotu stavu HA (obvykle malými písmeny, např. \"on\"/\"off\"). Velikost písmen se při uložení normalizuje.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Upravit zásobu",
|
"part_restock": "Upravit zásobu",
|
||||||
"restock_quantity_label": "Zakoupené množství",
|
"restock_quantity_label": "Zakoupené množství",
|
||||||
"consumes_parts_label": "Spotřebovává díly",
|
"consumes_parts_label": "Spotřebovává díly",
|
||||||
|
"shared_parts_other_objects": "Díly z jiných objektů",
|
||||||
|
"shared_parts_help": "Několik objektů může sdílet jeden sklad. Dokončení tohoto úkolu odečte zásobu z vlastnícího objektu.",
|
||||||
|
"shared_part_unknown": "Neznámý díl",
|
||||||
"parts_load_failed": "Nepodařilo se načíst díly tohoto objektu — možnosti spotřeby dílů nyní nejsou k dispozici.",
|
"parts_load_failed": "Nepodařilo se načíst díly tohoto objektu — možnosti spotřeby dílů nyní nejsou k dispozici.",
|
||||||
"settings_export_selection": "Omezit na vybrané objekty (volitelné)",
|
"settings_export_selection": "Omezit na vybrané objekty (volitelné)",
|
||||||
"settings_docs_archive": "Archiv dokumentů (se soubory)",
|
"settings_docs_archive": "Archiv dokumentů (se soubory)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Udløserværdi",
|
"trigger_val": "Udløserværdi",
|
||||||
"complete_title": "Fuldfør: ",
|
"complete_title": "Fuldfør: ",
|
||||||
"checklist": "Tjekliste",
|
"checklist": "Tjekliste",
|
||||||
|
"require_on_completion": "Kræv ved fuldførelse",
|
||||||
"checklist_steps_optional": "Tjeklistetrin (valgfrit)",
|
"checklist_steps_optional": "Tjeklistetrin (valgfrit)",
|
||||||
"checklist_placeholder": "Rengør filter\nUdskift pakning\nTest tryk",
|
"checklist_placeholder": "Rengør filter\nUdskift pakning\nTest tryk",
|
||||||
"checklist_help": "Ét trin pr. linje. Maks. 100 elementer.",
|
"checklist_help": "Ét trin pr. linje. Maks. 100 elementer.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Tom = vis alle statusser.",
|
"card_filter_status_help": "Tom = vis alle statusser.",
|
||||||
"card_filter_objects": "Filtrer efter objekter",
|
"card_filter_objects": "Filtrer efter objekter",
|
||||||
"card_filter_objects_help": "Tom = vis alle objekter.",
|
"card_filter_objects_help": "Tom = vis alle objekter.",
|
||||||
|
"card_filter_areas": "Filtrer efter områder",
|
||||||
|
"card_filter_areas_help": "Tom = vis alle områder.",
|
||||||
"card_filter_entities": "Filtrer efter enheder (entity_ids)",
|
"card_filter_entities": "Filtrer efter enheder (entity_ids)",
|
||||||
"card_filter_entities_help": "Vælg sensor- / binary_sensor-enheder fra denne integration. Tom = alle.",
|
"card_filter_entities_help": "Vælg sensor- / binary_sensor-enheder fra denne integration. Tom = alle.",
|
||||||
"card_loading_objects": "Indlæser objekter…",
|
"card_loading_objects": "Indlæser objekter…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Sidepanelets titel",
|
"settings_panel_title": "Sidepanelets titel",
|
||||||
"settings_notifications": "Notifikationer",
|
"settings_notifications": "Notifikationer",
|
||||||
"settings_notify_service": "Notifikationstjeneste",
|
"settings_notify_service": "Notifikationstjeneste",
|
||||||
|
"settings_install_assist_sentences": "Installer Assist-sætninger",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopierer stemmesætningerne til din konfiguration, så den klassiske Assist-agent genkender dem. En fil, du selv har redigeret, overskrives aldrig.",
|
||||||
"test_notification": "Testnotifikation",
|
"test_notification": "Testnotifikation",
|
||||||
"send_test": "Send test",
|
"send_test": "Send test",
|
||||||
"testing": "Sender…",
|
"testing": "Sender…",
|
||||||
"test_notification_success": "Testnotifikation sendt",
|
"test_notification_success": "Testnotifikation sendt",
|
||||||
"test_notification_failed": "Testnotifikation mislykkedes",
|
"test_notification_failed": "Testnotifikation mislykkedes",
|
||||||
|
"notify_per_person": "Levering pr. person",
|
||||||
|
"notify_no_own_device": "Ingen egen enhed — bruger husstandens tjeneste",
|
||||||
"settings_notify_due_soon": "Notificer ved snart forfalden",
|
"settings_notify_due_soon": "Notificer ved snart forfalden",
|
||||||
"settings_notify_overdue": "Notificer ved forfalden",
|
"settings_notify_overdue": "Notificer ved forfalden",
|
||||||
"settings_notify_triggered": "Notificer ved udløst",
|
"settings_notify_triggered": "Notificer ved udløst",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Efter bruger",
|
"groupby_user": "Efter bruger",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Bruger",
|
"user_label": "Bruger",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sortering",
|
"sort_label": "Sortering",
|
||||||
"group_by_label": "Grupper efter",
|
"group_by_label": "Grupper efter",
|
||||||
"state_value_help": "Brug HA-tilstandsværdien (normalt med små bogstaver, f.eks. \"on\"/\"off\"). Store/små bogstaver normaliseres ved lagring.",
|
"state_value_help": "Brug HA-tilstandsværdien (normalt med små bogstaver, f.eks. \"on\"/\"off\"). Store/små bogstaver normaliseres ved lagring.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Justér lager",
|
"part_restock": "Justér lager",
|
||||||
"restock_quantity_label": "Købt mængde",
|
"restock_quantity_label": "Købt mængde",
|
||||||
"consumes_parts_label": "Forbruger dele",
|
"consumes_parts_label": "Forbruger dele",
|
||||||
|
"shared_parts_other_objects": "Dele fra andre objekter",
|
||||||
|
"shared_parts_help": "Flere objekter kan dele det samme lager. Når opgaven fuldføres, trækkes der fra det ejende objekt.",
|
||||||
|
"shared_part_unknown": "Ukendt del",
|
||||||
"parts_load_failed": "Kunne ikke indlæse objektets reservedele — forbrugsindstillingerne er ikke tilgængelige lige nu.",
|
"parts_load_failed": "Kunne ikke indlæse objektets reservedele — forbrugsindstillingerne er ikke tilgængelige lige nu.",
|
||||||
"settings_export_selection": "Begræns til valgte objekter (valgfrit)",
|
"settings_export_selection": "Begræns til valgte objekter (valgfrit)",
|
||||||
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Trigger-Wert",
|
"trigger_val": "Trigger-Wert",
|
||||||
"complete_title": "Erledigt: ",
|
"complete_title": "Erledigt: ",
|
||||||
"checklist": "Checkliste",
|
"checklist": "Checkliste",
|
||||||
|
"require_on_completion": "Beim Abschließen verlangen",
|
||||||
"checklist_steps_optional": "Checkliste-Schritte (optional)",
|
"checklist_steps_optional": "Checkliste-Schritte (optional)",
|
||||||
"checklist_placeholder": "Filter reinigen\nDichtung ersetzen\nDruck testen",
|
"checklist_placeholder": "Filter reinigen\nDichtung ersetzen\nDruck testen",
|
||||||
"checklist_help": "Ein Schritt pro Zeile. Max. 100 Einträge.",
|
"checklist_help": "Ein Schritt pro Zeile. Max. 100 Einträge.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Leer = alle Status zeigen.",
|
"card_filter_status_help": "Leer = alle Status zeigen.",
|
||||||
"card_filter_objects": "Nach Objekten filtern",
|
"card_filter_objects": "Nach Objekten filtern",
|
||||||
"card_filter_objects_help": "Leer = alle Objekte zeigen.",
|
"card_filter_objects_help": "Leer = alle Objekte zeigen.",
|
||||||
|
"card_filter_areas": "Nach Bereichen filtern",
|
||||||
|
"card_filter_areas_help": "Leer = alle Bereiche zeigen.",
|
||||||
"card_filter_entities": "Nach Entitäten filtern (entity_ids)",
|
"card_filter_entities": "Nach Entitäten filtern (entity_ids)",
|
||||||
"card_filter_entities_help": "Wähle Sensor-/Binary-Sensor-Entitäten dieser Integration. Leer = alle.",
|
"card_filter_entities_help": "Wähle Sensor-/Binary-Sensor-Entitäten dieser Integration. Leer = alle.",
|
||||||
"card_loading_objects": "Lade Objekte…",
|
"card_loading_objects": "Lade Objekte…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Panel-Titel",
|
"settings_panel_title": "Panel-Titel",
|
||||||
"settings_notifications": "Benachrichtigungen",
|
"settings_notifications": "Benachrichtigungen",
|
||||||
"settings_notify_service": "Benachrichtigungsdienst",
|
"settings_notify_service": "Benachrichtigungsdienst",
|
||||||
|
"settings_install_assist_sentences": "Assist-Sätze installieren",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopiert die Sprachbefehle in deine Konfiguration, damit der klassische Assist-Agent sie erkennt. Eine selbst bearbeitete Datei wird nie überschrieben.",
|
||||||
"test_notification": "Test-Benachrichtigung",
|
"test_notification": "Test-Benachrichtigung",
|
||||||
"send_test": "Test senden",
|
"send_test": "Test senden",
|
||||||
"testing": "Sende…",
|
"testing": "Sende…",
|
||||||
"test_notification_success": "Test-Benachrichtigung gesendet",
|
"test_notification_success": "Test-Benachrichtigung gesendet",
|
||||||
"test_notification_failed": "Test-Benachrichtigung fehlgeschlagen",
|
"test_notification_failed": "Test-Benachrichtigung fehlgeschlagen",
|
||||||
|
"notify_per_person": "Zustellung pro Person",
|
||||||
|
"notify_no_own_device": "Kein eigenes Gerät — nutzt den Haushaltsdienst",
|
||||||
"settings_notify_due_soon": "Bei baldiger Fälligkeit benachrichtigen",
|
"settings_notify_due_soon": "Bei baldiger Fälligkeit benachrichtigen",
|
||||||
"settings_notify_overdue": "Bei Überfälligkeit benachrichtigen",
|
"settings_notify_overdue": "Bei Überfälligkeit benachrichtigen",
|
||||||
"settings_notify_triggered": "Bei Auslösung benachrichtigen",
|
"settings_notify_triggered": "Bei Auslösung benachrichtigen",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Nach Verantwortlichem",
|
"groupby_user": "Nach Verantwortlichem",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Benutzer",
|
"user_label": "Benutzer",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sortierung",
|
"sort_label": "Sortierung",
|
||||||
"group_by_label": "Gruppieren nach",
|
"group_by_label": "Gruppieren nach",
|
||||||
"state_value_help": "Verwende den HA-Zustandswert (meist kleingeschrieben, z. B. \"on\"/\"off\"). Groß-/Kleinschreibung wird beim Speichern normalisiert.",
|
"state_value_help": "Verwende den HA-Zustandswert (meist kleingeschrieben, z. B. \"on\"/\"off\"). Groß-/Kleinschreibung wird beim Speichern normalisiert.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Bestand anpassen",
|
"part_restock": "Bestand anpassen",
|
||||||
"restock_quantity_label": "Gekaufte Menge",
|
"restock_quantity_label": "Gekaufte Menge",
|
||||||
"consumes_parts_label": "Verbraucht Teile",
|
"consumes_parts_label": "Verbraucht Teile",
|
||||||
|
"shared_parts_other_objects": "Teile anderer Objekte",
|
||||||
|
"shared_parts_help": "Mehrere Objekte können sich einen Bestand teilen. Beim Abschließen wird vom besitzenden Objekt abgebucht.",
|
||||||
|
"shared_part_unknown": "Unbekanntes Teil",
|
||||||
"parts_load_failed": "Die Teile dieses Objekts konnten nicht geladen werden — die Teileverbrauch-Optionen sind gerade nicht verfügbar.",
|
"parts_load_failed": "Die Teile dieses Objekts konnten nicht geladen werden — die Teileverbrauch-Optionen sind gerade nicht verfügbar.",
|
||||||
"settings_export_selection": "Auf ausgewählte Objekte beschränken (optional)",
|
"settings_export_selection": "Auf ausgewählte Objekte beschränken (optional)",
|
||||||
"settings_docs_archive": "Dokumentenarchiv (mit Dateien)",
|
"settings_docs_archive": "Dokumentenarchiv (mit Dateien)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Trigger value",
|
"trigger_val": "Trigger value",
|
||||||
"complete_title": "Complete: ",
|
"complete_title": "Complete: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Require on completion",
|
||||||
"checklist_steps_optional": "Checklist steps (optional)",
|
"checklist_steps_optional": "Checklist steps (optional)",
|
||||||
"checklist_placeholder": "Clean filter\nReplace seal\nTest pressure",
|
"checklist_placeholder": "Clean filter\nReplace seal\nTest pressure",
|
||||||
"checklist_help": "One step per line. Max 100 items.",
|
"checklist_help": "One step per line. Max 100 items.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Empty = show all statuses.",
|
"card_filter_status_help": "Empty = show all statuses.",
|
||||||
"card_filter_objects": "Filter by objects",
|
"card_filter_objects": "Filter by objects",
|
||||||
"card_filter_objects_help": "Empty = show all objects.",
|
"card_filter_objects_help": "Empty = show all objects.",
|
||||||
|
"card_filter_areas": "Filter by areas",
|
||||||
|
"card_filter_areas_help": "Empty = show all areas.",
|
||||||
"card_filter_entities": "Filter by entities (entity_ids)",
|
"card_filter_entities": "Filter by entities (entity_ids)",
|
||||||
"card_filter_entities_help": "Pick sensor / binary_sensor entities from this integration. Empty = all.",
|
"card_filter_entities_help": "Pick sensor / binary_sensor entities from this integration. Empty = all.",
|
||||||
"card_loading_objects": "Loading objects…",
|
"card_loading_objects": "Loading objects…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Sidebar panel title",
|
"settings_panel_title": "Sidebar panel title",
|
||||||
"settings_notifications": "Notifications",
|
"settings_notifications": "Notifications",
|
||||||
"settings_notify_service": "Notification service",
|
"settings_notify_service": "Notification service",
|
||||||
|
"settings_install_assist_sentences": "Install Assist sentences",
|
||||||
|
"settings_install_assist_sentences_hint": "Copies the voice sentences into your configuration so the classic Assist agent recognises them. A file you edited yourself is never overwritten.",
|
||||||
"test_notification": "Test notification",
|
"test_notification": "Test notification",
|
||||||
"send_test": "Send test",
|
"send_test": "Send test",
|
||||||
"testing": "Sending…",
|
"testing": "Sending…",
|
||||||
"test_notification_success": "Test notification sent",
|
"test_notification_success": "Test notification sent",
|
||||||
"test_notification_failed": "Test notification failed",
|
"test_notification_failed": "Test notification failed",
|
||||||
|
"notify_per_person": "Per-person delivery",
|
||||||
|
"notify_no_own_device": "No own device — uses the household service",
|
||||||
"settings_notify_due_soon": "Notify when due soon",
|
"settings_notify_due_soon": "Notify when due soon",
|
||||||
"settings_notify_overdue": "Notify when overdue",
|
"settings_notify_overdue": "Notify when overdue",
|
||||||
"settings_notify_triggered": "Notify when triggered",
|
"settings_notify_triggered": "Notify when triggered",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "By user",
|
"groupby_user": "By user",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "User",
|
"user_label": "User",
|
||||||
|
"photo_label": "Photo",
|
||||||
"sort_label": "Sort",
|
"sort_label": "Sort",
|
||||||
"group_by_label": "Group by",
|
"group_by_label": "Group by",
|
||||||
"state_value_help": "Use the HA state value (usually lowercase, e.g. \"on\"/\"off\"). Case is normalised on save.",
|
"state_value_help": "Use the HA state value (usually lowercase, e.g. \"on\"/\"off\"). Case is normalised on save.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Adjust stock",
|
"part_restock": "Adjust stock",
|
||||||
"restock_quantity_label": "Quantity bought",
|
"restock_quantity_label": "Quantity bought",
|
||||||
"consumes_parts_label": "Consumes parts",
|
"consumes_parts_label": "Consumes parts",
|
||||||
|
"shared_parts_other_objects": "Parts from other objects",
|
||||||
|
"shared_parts_help": "Several objects can share one stock. Completing this task takes from the owning object.",
|
||||||
|
"shared_part_unknown": "Unknown part",
|
||||||
"parts_load_failed": "Couldn't load this object's parts — the consumes-parts options are unavailable right now.",
|
"parts_load_failed": "Couldn't load this object's parts — the consumes-parts options are unavailable right now.",
|
||||||
"adopt_problem_button": "Adopt problem sensors",
|
"adopt_problem_button": "Adopt problem sensors",
|
||||||
"adopt_problem_title": "Adopt problem sensors",
|
"adopt_problem_title": "Adopt problem sensors",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valor del disparador",
|
"trigger_val": "Valor del disparador",
|
||||||
"complete_title": "Completada: ",
|
"complete_title": "Completada: ",
|
||||||
"checklist": "Lista de verificación",
|
"checklist": "Lista de verificación",
|
||||||
|
"require_on_completion": "Exigir al completar",
|
||||||
"checklist_steps_optional": "Pasos de la lista de verificación (opcional)",
|
"checklist_steps_optional": "Pasos de la lista de verificación (opcional)",
|
||||||
"checklist_placeholder": "Limpiar filtro\nReemplazar junta\nProbar presión",
|
"checklist_placeholder": "Limpiar filtro\nReemplazar junta\nProbar presión",
|
||||||
"checklist_help": "Un paso por línea. Máx. 100 elementos.",
|
"checklist_help": "Un paso por línea. Máx. 100 elementos.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vacío = mostrar todos los estados.",
|
"card_filter_status_help": "Vacío = mostrar todos los estados.",
|
||||||
"card_filter_objects": "Filtrar por objetos",
|
"card_filter_objects": "Filtrar por objetos",
|
||||||
"card_filter_objects_help": "Vacío = mostrar todos los objetos.",
|
"card_filter_objects_help": "Vacío = mostrar todos los objetos.",
|
||||||
|
"card_filter_areas": "Filtrar por áreas",
|
||||||
|
"card_filter_areas_help": "Vacío = mostrar todas las áreas.",
|
||||||
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
||||||
"card_filter_entities_help": "Selecciona entidades sensor / binary_sensor de esta integración. Vacío = todas.",
|
"card_filter_entities_help": "Selecciona entidades sensor / binary_sensor de esta integración. Vacío = todas.",
|
||||||
"card_loading_objects": "Cargando objetos…",
|
"card_loading_objects": "Cargando objetos…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Título del panel lateral",
|
"settings_panel_title": "Título del panel lateral",
|
||||||
"settings_notifications": "Notificaciones",
|
"settings_notifications": "Notificaciones",
|
||||||
"settings_notify_service": "Servicio de notificación",
|
"settings_notify_service": "Servicio de notificación",
|
||||||
|
"settings_install_assist_sentences": "Instalar frases de Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia las frases de voz en tu configuración para que el agente clásico de Assist las reconozca. Un archivo que hayas editado nunca se sobrescribe.",
|
||||||
"test_notification": "Notificación de prueba",
|
"test_notification": "Notificación de prueba",
|
||||||
"send_test": "Enviar prueba",
|
"send_test": "Enviar prueba",
|
||||||
"testing": "Enviando…",
|
"testing": "Enviando…",
|
||||||
"test_notification_success": "Notificación de prueba enviada",
|
"test_notification_success": "Notificación de prueba enviada",
|
||||||
"test_notification_failed": "La notificación de prueba falló",
|
"test_notification_failed": "La notificación de prueba falló",
|
||||||
|
"notify_per_person": "Entrega por persona",
|
||||||
|
"notify_no_own_device": "Sin dispositivo propio — usa el servicio del hogar",
|
||||||
"settings_notify_due_soon": "Notificar cuando esté próxima",
|
"settings_notify_due_soon": "Notificar cuando esté próxima",
|
||||||
"settings_notify_overdue": "Notificar cuando esté vencida",
|
"settings_notify_overdue": "Notificar cuando esté vencida",
|
||||||
"settings_notify_triggered": "Notificar cuando se active",
|
"settings_notify_triggered": "Notificar cuando se active",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Por usuario",
|
"groupby_user": "Por usuario",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Usuario",
|
"user_label": "Usuario",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordenar",
|
"sort_label": "Ordenar",
|
||||||
"group_by_label": "Agrupar por",
|
"group_by_label": "Agrupar por",
|
||||||
"state_value_help": "Usa el valor de estado de HA (normalmente en minúsculas, p. ej. \"on\"/\"off\"). Las mayúsculas se normalizan al guardar.",
|
"state_value_help": "Usa el valor de estado de HA (normalmente en minúsculas, p. ej. \"on\"/\"off\"). Las mayúsculas se normalizan al guardar.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Ajustar existencias",
|
"part_restock": "Ajustar existencias",
|
||||||
"restock_quantity_label": "Cantidad comprada",
|
"restock_quantity_label": "Cantidad comprada",
|
||||||
"consumes_parts_label": "Consume piezas",
|
"consumes_parts_label": "Consume piezas",
|
||||||
|
"shared_parts_other_objects": "Piezas de otros objetos",
|
||||||
|
"shared_parts_help": "Varios objetos pueden compartir un mismo stock. Al completar esta tarea se descuenta del objeto propietario.",
|
||||||
|
"shared_part_unknown": "Pieza desconocida",
|
||||||
"parts_load_failed": "No se pudieron cargar las piezas de este objeto — las opciones de consumo de piezas no están disponibles ahora.",
|
"parts_load_failed": "No se pudieron cargar las piezas de este objeto — las opciones de consumo de piezas no están disponibles ahora.",
|
||||||
"settings_export_selection": "Limitar a los objetos seleccionados (opcional)",
|
"settings_export_selection": "Limitar a los objetos seleccionados (opcional)",
|
||||||
"settings_docs_archive": "Archivo de documentos (con archivos)",
|
"settings_docs_archive": "Archivo de documentos (con archivos)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Laukaisuarvo",
|
"trigger_val": "Laukaisuarvo",
|
||||||
"complete_title": "Suorita: ",
|
"complete_title": "Suorita: ",
|
||||||
"checklist": "Tarkistuslista",
|
"checklist": "Tarkistuslista",
|
||||||
|
"require_on_completion": "Vaadi valmistuessa",
|
||||||
"checklist_steps_optional": "Tarkistuslistan vaiheet (valinnainen)",
|
"checklist_steps_optional": "Tarkistuslistan vaiheet (valinnainen)",
|
||||||
"checklist_placeholder": "Puhdista suodatin\nVaihda tiiviste\nTarkista paine",
|
"checklist_placeholder": "Puhdista suodatin\nVaihda tiiviste\nTarkista paine",
|
||||||
"checklist_help": "Yksi vaihe riviä kohden. Enintään 100 kohdetta.",
|
"checklist_help": "Yksi vaihe riviä kohden. Enintään 100 kohdetta.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Tyhjä = näytä kaikki tilat.",
|
"card_filter_status_help": "Tyhjä = näytä kaikki tilat.",
|
||||||
"card_filter_objects": "Suodata kohteiden mukaan",
|
"card_filter_objects": "Suodata kohteiden mukaan",
|
||||||
"card_filter_objects_help": "Tyhjä = näytä kaikki kohteet.",
|
"card_filter_objects_help": "Tyhjä = näytä kaikki kohteet.",
|
||||||
|
"card_filter_areas": "Suodata alueiden mukaan",
|
||||||
|
"card_filter_areas_help": "Tyhjä = näytä kaikki alueet.",
|
||||||
"card_filter_entities": "Suodata entiteettien mukaan (entity_id)",
|
"card_filter_entities": "Suodata entiteettien mukaan (entity_id)",
|
||||||
"card_filter_entities_help": "Valitse sensor- / binary_sensor-entiteetit tästä integraatiosta. Tyhjä = kaikki.",
|
"card_filter_entities_help": "Valitse sensor- / binary_sensor-entiteetit tästä integraatiosta. Tyhjä = kaikki.",
|
||||||
"card_loading_objects": "Ladataan kohteita…",
|
"card_loading_objects": "Ladataan kohteita…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Sivupalkin paneelin otsikko",
|
"settings_panel_title": "Sivupalkin paneelin otsikko",
|
||||||
"settings_notifications": "Ilmoitukset",
|
"settings_notifications": "Ilmoitukset",
|
||||||
"settings_notify_service": "Ilmoituspalvelu",
|
"settings_notify_service": "Ilmoituspalvelu",
|
||||||
|
"settings_install_assist_sentences": "Asenna Assist-lauseet",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopioi äänikomennot asetuksiisi, jotta perinteinen Assist-agentti tunnistaa ne. Itse muokkaamaasi tiedostoa ei koskaan korvata.",
|
||||||
"test_notification": "Testi-ilmoitus",
|
"test_notification": "Testi-ilmoitus",
|
||||||
"send_test": "Lähetä testi",
|
"send_test": "Lähetä testi",
|
||||||
"testing": "Lähetetään…",
|
"testing": "Lähetetään…",
|
||||||
"test_notification_success": "Testi-ilmoitus lähetetty",
|
"test_notification_success": "Testi-ilmoitus lähetetty",
|
||||||
"test_notification_failed": "Testi-ilmoitus epäonnistui",
|
"test_notification_failed": "Testi-ilmoitus epäonnistui",
|
||||||
|
"notify_per_person": "Toimitus henkilöittäin",
|
||||||
|
"notify_no_own_device": "Ei omaa laitetta — käyttää kotitalouden palvelua",
|
||||||
"settings_notify_due_soon": "Ilmoita, kun erääntyy pian",
|
"settings_notify_due_soon": "Ilmoita, kun erääntyy pian",
|
||||||
"settings_notify_overdue": "Ilmoita, kun myöhässä",
|
"settings_notify_overdue": "Ilmoita, kun myöhässä",
|
||||||
"settings_notify_triggered": "Ilmoita, kun laukaistu",
|
"settings_notify_triggered": "Ilmoita, kun laukaistu",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Käyttäjän mukaan",
|
"groupby_user": "Käyttäjän mukaan",
|
||||||
"filter_label": "Suodata",
|
"filter_label": "Suodata",
|
||||||
"user_label": "Käyttäjä",
|
"user_label": "Käyttäjä",
|
||||||
|
"photo_label": "Valokuva",
|
||||||
"sort_label": "Lajittele",
|
"sort_label": "Lajittele",
|
||||||
"group_by_label": "Ryhmittele",
|
"group_by_label": "Ryhmittele",
|
||||||
"state_value_help": "Käytä HA:n tila-arvoa (yleensä pienillä kirjaimilla, esim. \"on\"/\"off\"). Kirjainkoko normalisoidaan tallennettaessa.",
|
"state_value_help": "Käytä HA:n tila-arvoa (yleensä pienillä kirjaimilla, esim. \"on\"/\"off\"). Kirjainkoko normalisoidaan tallennettaessa.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Muuta varastoa",
|
"part_restock": "Muuta varastoa",
|
||||||
"restock_quantity_label": "Ostettu määrä",
|
"restock_quantity_label": "Ostettu määrä",
|
||||||
"consumes_parts_label": "Kuluttaa osia",
|
"consumes_parts_label": "Kuluttaa osia",
|
||||||
|
"shared_parts_other_objects": "Muiden kohteiden osat",
|
||||||
|
"shared_parts_help": "Useat kohteet voivat jakaa saman varaston. Tämän tehtävän suorittaminen vähentää omistavan kohteen varastoa.",
|
||||||
|
"shared_part_unknown": "Tuntematon osa",
|
||||||
"parts_load_failed": "Kohteen osia ei voitu ladata — osien kulutusvalinnat eivät ole juuri nyt käytettävissä.",
|
"parts_load_failed": "Kohteen osia ei voitu ladata — osien kulutusvalinnat eivät ole juuri nyt käytettävissä.",
|
||||||
"settings_export_selection": "Rajaa valittuihin kohteisiin (valinnainen)",
|
"settings_export_selection": "Rajaa valittuihin kohteisiin (valinnainen)",
|
||||||
"settings_docs_archive": "Asiakirja-arkisto (tiedostoineen)",
|
"settings_docs_archive": "Asiakirja-arkisto (tiedostoineen)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valeur du déclencheur",
|
"trigger_val": "Valeur du déclencheur",
|
||||||
"complete_title": "Terminé : ",
|
"complete_title": "Terminé : ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Exiger à la clôture",
|
||||||
"checklist_steps_optional": "Étapes de la checklist (optionnel)",
|
"checklist_steps_optional": "Étapes de la checklist (optionnel)",
|
||||||
"checklist_placeholder": "Nettoyer le filtre\nRemplacer le joint\nTester la pression",
|
"checklist_placeholder": "Nettoyer le filtre\nRemplacer le joint\nTester la pression",
|
||||||
"checklist_help": "Une étape par ligne. Max 100 éléments.",
|
"checklist_help": "Une étape par ligne. Max 100 éléments.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vide = afficher tous les statuts.",
|
"card_filter_status_help": "Vide = afficher tous les statuts.",
|
||||||
"card_filter_objects": "Filtrer par objets",
|
"card_filter_objects": "Filtrer par objets",
|
||||||
"card_filter_objects_help": "Vide = afficher tous les objets.",
|
"card_filter_objects_help": "Vide = afficher tous les objets.",
|
||||||
|
"card_filter_areas": "Filtrer par zones",
|
||||||
|
"card_filter_areas_help": "Vide = afficher toutes les zones.",
|
||||||
"card_filter_entities": "Filtrer par entités (entity_ids)",
|
"card_filter_entities": "Filtrer par entités (entity_ids)",
|
||||||
"card_filter_entities_help": "Choisissez des entités sensor / binary_sensor de cette intégration. Vide = toutes.",
|
"card_filter_entities_help": "Choisissez des entités sensor / binary_sensor de cette intégration. Vide = toutes.",
|
||||||
"card_loading_objects": "Chargement des objets…",
|
"card_loading_objects": "Chargement des objets…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Titre du panneau latéral",
|
"settings_panel_title": "Titre du panneau latéral",
|
||||||
"settings_notifications": "Notifications",
|
"settings_notifications": "Notifications",
|
||||||
"settings_notify_service": "Service de notification",
|
"settings_notify_service": "Service de notification",
|
||||||
|
"settings_install_assist_sentences": "Installer les phrases Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copie les phrases vocales dans votre configuration afin que l'agent Assist classique les reconnaisse. Un fichier que vous avez modifié n'est jamais écrasé.",
|
||||||
"test_notification": "Notification de test",
|
"test_notification": "Notification de test",
|
||||||
"send_test": "Envoyer le test",
|
"send_test": "Envoyer le test",
|
||||||
"testing": "Envoi en cours…",
|
"testing": "Envoi en cours…",
|
||||||
"test_notification_success": "Notification de test envoyée",
|
"test_notification_success": "Notification de test envoyée",
|
||||||
"test_notification_failed": "Échec de la notification de test",
|
"test_notification_failed": "Échec de la notification de test",
|
||||||
|
"notify_per_person": "Distribution par personne",
|
||||||
|
"notify_no_own_device": "Aucun appareil propre — utilise le service du foyer",
|
||||||
"settings_notify_due_soon": "Notifier quand bientôt dû",
|
"settings_notify_due_soon": "Notifier quand bientôt dû",
|
||||||
"settings_notify_overdue": "Notifier quand en retard",
|
"settings_notify_overdue": "Notifier quand en retard",
|
||||||
"settings_notify_triggered": "Notifier quand déclenché",
|
"settings_notify_triggered": "Notifier quand déclenché",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Par utilisateur",
|
"groupby_user": "Par utilisateur",
|
||||||
"filter_label": "Filtre",
|
"filter_label": "Filtre",
|
||||||
"user_label": "Utilisateur",
|
"user_label": "Utilisateur",
|
||||||
|
"photo_label": "Photo",
|
||||||
"sort_label": "Tri",
|
"sort_label": "Tri",
|
||||||
"group_by_label": "Grouper par",
|
"group_by_label": "Grouper par",
|
||||||
"state_value_help": "Utilisez la valeur d'état HA (généralement en minuscules, p. ex. \"on\"/\"off\"). La casse est normalisée à l'enregistrement.",
|
"state_value_help": "Utilisez la valeur d'état HA (généralement en minuscules, p. ex. \"on\"/\"off\"). La casse est normalisée à l'enregistrement.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Ajuster le stock",
|
"part_restock": "Ajuster le stock",
|
||||||
"restock_quantity_label": "Quantité achetée",
|
"restock_quantity_label": "Quantité achetée",
|
||||||
"consumes_parts_label": "Consomme des pièces",
|
"consumes_parts_label": "Consomme des pièces",
|
||||||
|
"shared_parts_other_objects": "Pièces d'autres objets",
|
||||||
|
"shared_parts_help": "Plusieurs objets peuvent partager un même stock. Terminer cette tâche décompte du stock de l'objet propriétaire.",
|
||||||
|
"shared_part_unknown": "Pièce inconnue",
|
||||||
"parts_load_failed": "Impossible de charger les pièces de cet objet — les options de consommation de pièces sont indisponibles pour le moment.",
|
"parts_load_failed": "Impossible de charger les pièces de cet objet — les options de consommation de pièces sont indisponibles pour le moment.",
|
||||||
"settings_export_selection": "Limiter aux objets sélectionnés (facultatif)",
|
"settings_export_selection": "Limiter aux objets sélectionnés (facultatif)",
|
||||||
"settings_docs_archive": "Archive de documents (avec fichiers)",
|
"settings_docs_archive": "Archive de documents (avec fichiers)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "ट्रिगर मान",
|
"trigger_val": "ट्रिगर मान",
|
||||||
"complete_title": "पूर्ण करें: ",
|
"complete_title": "पूर्ण करें: ",
|
||||||
"checklist": "चेकलिस्ट",
|
"checklist": "चेकलिस्ट",
|
||||||
|
"require_on_completion": "पूर्ण करते समय आवश्यक",
|
||||||
"checklist_steps_optional": "चेकलिस्ट चरण (वैकल्पिक)",
|
"checklist_steps_optional": "चेकलिस्ट चरण (वैकल्पिक)",
|
||||||
"checklist_placeholder": "फ़िल्टर साफ़ करें\nसील बदलें\nदबाव जाँचें",
|
"checklist_placeholder": "फ़िल्टर साफ़ करें\nसील बदलें\nदबाव जाँचें",
|
||||||
"checklist_help": "प्रति पंक्ति एक चरण। अधिकतम 100 आइटम।",
|
"checklist_help": "प्रति पंक्ति एक चरण। अधिकतम 100 आइटम।",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "खाली = सभी स्थितियाँ दिखाएँ।",
|
"card_filter_status_help": "खाली = सभी स्थितियाँ दिखाएँ।",
|
||||||
"card_filter_objects": "वस्तुओं के अनुसार फ़िल्टर करें",
|
"card_filter_objects": "वस्तुओं के अनुसार फ़िल्टर करें",
|
||||||
"card_filter_objects_help": "खाली = सभी वस्तुएँ दिखाएँ।",
|
"card_filter_objects_help": "खाली = सभी वस्तुएँ दिखाएँ।",
|
||||||
|
"card_filter_areas": "क्षेत्रों के अनुसार फ़िल्टर करें",
|
||||||
|
"card_filter_areas_help": "खाली = सभी क्षेत्र दिखाएँ।",
|
||||||
"card_filter_entities": "एंटिटी के अनुसार फ़िल्टर करें (entity_ids)",
|
"card_filter_entities": "एंटिटी के अनुसार फ़िल्टर करें (entity_ids)",
|
||||||
"card_filter_entities_help": "इस इंटीग्रेशन से sensor / binary_sensor एंटिटी चुनें। खाली = सभी।",
|
"card_filter_entities_help": "इस इंटीग्रेशन से sensor / binary_sensor एंटिटी चुनें। खाली = सभी।",
|
||||||
"card_loading_objects": "वस्तुएँ लोड हो रही हैं…",
|
"card_loading_objects": "वस्तुएँ लोड हो रही हैं…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "साइडबार पैनल शीर्षक",
|
"settings_panel_title": "साइडबार पैनल शीर्षक",
|
||||||
"settings_notifications": "सूचनाएँ",
|
"settings_notifications": "सूचनाएँ",
|
||||||
"settings_notify_service": "सूचना सेवा",
|
"settings_notify_service": "सूचना सेवा",
|
||||||
|
"settings_install_assist_sentences": "Assist वाक्य इंस्टॉल करें",
|
||||||
|
"settings_install_assist_sentences_hint": "वॉइस वाक्यों को आपके कॉन्फ़िगरेशन में कॉपी करता है ताकि क्लासिक Assist एजेंट उन्हें पहचान सके। आपके द्वारा संपादित फ़ाइल कभी अधिलेखित नहीं होती।",
|
||||||
"test_notification": "परीक्षण सूचना",
|
"test_notification": "परीक्षण सूचना",
|
||||||
"send_test": "परीक्षण भेजें",
|
"send_test": "परीक्षण भेजें",
|
||||||
"testing": "भेजा जा रहा है…",
|
"testing": "भेजा जा रहा है…",
|
||||||
"test_notification_success": "परीक्षण सूचना भेजी गई",
|
"test_notification_success": "परीक्षण सूचना भेजी गई",
|
||||||
"test_notification_failed": "परीक्षण सूचना विफल",
|
"test_notification_failed": "परीक्षण सूचना विफल",
|
||||||
|
"notify_per_person": "प्रति व्यक्ति वितरण",
|
||||||
|
"notify_no_own_device": "कोई निजी डिवाइस नहीं — घरेलू सेवा का उपयोग करता है",
|
||||||
"settings_notify_due_soon": "जल्द देय होने पर सूचित करें",
|
"settings_notify_due_soon": "जल्द देय होने पर सूचित करें",
|
||||||
"settings_notify_overdue": "अतिदेय होने पर सूचित करें",
|
"settings_notify_overdue": "अतिदेय होने पर सूचित करें",
|
||||||
"settings_notify_triggered": "ट्रिगर होने पर सूचित करें",
|
"settings_notify_triggered": "ट्रिगर होने पर सूचित करें",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "उपयोगकर्ता के अनुसार",
|
"groupby_user": "उपयोगकर्ता के अनुसार",
|
||||||
"filter_label": "फ़िल्टर",
|
"filter_label": "फ़िल्टर",
|
||||||
"user_label": "उपयोगकर्ता",
|
"user_label": "उपयोगकर्ता",
|
||||||
|
"photo_label": "फ़ोटो",
|
||||||
"sort_label": "क्रमबद्ध करें",
|
"sort_label": "क्रमबद्ध करें",
|
||||||
"group_by_label": "इसके अनुसार समूहित करें",
|
"group_by_label": "इसके अनुसार समूहित करें",
|
||||||
"state_value_help": "HA स्थिति मान का उपयोग करें (आमतौर पर लोअरकेस, उदा. \"on\"/\"off\")। सहेजने पर केस सामान्यीकृत हो जाता है।",
|
"state_value_help": "HA स्थिति मान का उपयोग करें (आमतौर पर लोअरकेस, उदा. \"on\"/\"off\")। सहेजने पर केस सामान्यीकृत हो जाता है।",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "स्टॉक समायोजित करें",
|
"part_restock": "स्टॉक समायोजित करें",
|
||||||
"restock_quantity_label": "खरीदी गई मात्रा",
|
"restock_quantity_label": "खरीदी गई मात्रा",
|
||||||
"consumes_parts_label": "पुर्ज़े खपत",
|
"consumes_parts_label": "पुर्ज़े खपत",
|
||||||
|
"shared_parts_other_objects": "अन्य वस्तुओं के पुर्ज़े",
|
||||||
|
"shared_parts_help": "कई वस्तुएँ एक ही स्टॉक साझा कर सकती हैं। यह कार्य पूरा करने पर स्वामी वस्तु के स्टॉक से घटाया जाता है।",
|
||||||
|
"shared_part_unknown": "अज्ञात पुर्ज़ा",
|
||||||
"parts_load_failed": "इस ऑब्जेक्ट के पुर्ज़े लोड नहीं हो सके — पुर्ज़ा-खपत विकल्प अभी उपलब्ध नहीं हैं।",
|
"parts_load_failed": "इस ऑब्जेक्ट के पुर्ज़े लोड नहीं हो सके — पुर्ज़ा-खपत विकल्प अभी उपलब्ध नहीं हैं।",
|
||||||
"settings_export_selection": "चयनित ऑब्जेक्ट तक सीमित करें (वैकल्पिक)",
|
"settings_export_selection": "चयनित ऑब्जेक्ट तक सीमित करें (वैकल्पिक)",
|
||||||
"settings_docs_archive": "दस्तावेज़ संग्रह (फ़ाइलों सहित)",
|
"settings_docs_archive": "दस्तावेज़ संग्रह (फ़ाइलों सहित)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Kiváltó érték",
|
"trigger_val": "Kiváltó érték",
|
||||||
"complete_title": "Elvégzés: ",
|
"complete_title": "Elvégzés: ",
|
||||||
"checklist": "Ellenőrzőlista",
|
"checklist": "Ellenőrzőlista",
|
||||||
|
"require_on_completion": "Befejezéskor kötelező",
|
||||||
"checklist_steps_optional": "Ellenőrzőlista lépései (opcionális)",
|
"checklist_steps_optional": "Ellenőrzőlista lépései (opcionális)",
|
||||||
"checklist_placeholder": "Szűrő tisztítása\nTömítés cseréje\nNyomáspróba",
|
"checklist_placeholder": "Szűrő tisztítása\nTömítés cseréje\nNyomáspróba",
|
||||||
"checklist_help": "Soronként egy lépés. Legfeljebb 100 elem.",
|
"checklist_help": "Soronként egy lépés. Legfeljebb 100 elem.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Üres = minden állapot megjelenik.",
|
"card_filter_status_help": "Üres = minden állapot megjelenik.",
|
||||||
"card_filter_objects": "Szűrés objektumok szerint",
|
"card_filter_objects": "Szűrés objektumok szerint",
|
||||||
"card_filter_objects_help": "Üres = minden objektum megjelenik.",
|
"card_filter_objects_help": "Üres = minden objektum megjelenik.",
|
||||||
|
"card_filter_areas": "Szűrés területek szerint",
|
||||||
|
"card_filter_areas_help": "Üres = minden terület megjelenik.",
|
||||||
"card_filter_entities": "Szűrés entitások szerint (entity_id-k)",
|
"card_filter_entities": "Szűrés entitások szerint (entity_id-k)",
|
||||||
"card_filter_entities_help": "Válasszon sensor / binary_sensor entitásokat ebből az integrációból. Üres = mind.",
|
"card_filter_entities_help": "Válasszon sensor / binary_sensor entitásokat ebből az integrációból. Üres = mind.",
|
||||||
"card_loading_objects": "Objektumok betöltése…",
|
"card_loading_objects": "Objektumok betöltése…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Oldalsáv-panel címe",
|
"settings_panel_title": "Oldalsáv-panel címe",
|
||||||
"settings_notifications": "Értesítések",
|
"settings_notifications": "Értesítések",
|
||||||
"settings_notify_service": "Értesítési szolgáltatás",
|
"settings_notify_service": "Értesítési szolgáltatás",
|
||||||
|
"settings_install_assist_sentences": "Assist mondatok telepítése",
|
||||||
|
"settings_install_assist_sentences_hint": "Átmásolja a hangmondatokat a konfigurációdba, hogy a klasszikus Assist ügynök felismerje őket. Az általad szerkesztett fájlt soha nem írja felül.",
|
||||||
"test_notification": "Tesztértesítés",
|
"test_notification": "Tesztértesítés",
|
||||||
"send_test": "Teszt küldése",
|
"send_test": "Teszt küldése",
|
||||||
"testing": "Küldés…",
|
"testing": "Küldés…",
|
||||||
"test_notification_success": "Tesztértesítés elküldve",
|
"test_notification_success": "Tesztértesítés elküldve",
|
||||||
"test_notification_failed": "A tesztértesítés nem sikerült",
|
"test_notification_failed": "A tesztértesítés nem sikerült",
|
||||||
|
"notify_per_person": "Kézbesítés személyenként",
|
||||||
|
"notify_no_own_device": "Nincs saját eszköz — a háztartási szolgáltatást használja",
|
||||||
"settings_notify_due_soon": "Értesítés, ha hamarosan esedékes",
|
"settings_notify_due_soon": "Értesítés, ha hamarosan esedékes",
|
||||||
"settings_notify_overdue": "Értesítés lejáratkor",
|
"settings_notify_overdue": "Értesítés lejáratkor",
|
||||||
"settings_notify_triggered": "Értesítés kiváltáskor",
|
"settings_notify_triggered": "Értesítés kiváltáskor",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "Felhasználó szerint",
|
"groupby_user": "Felhasználó szerint",
|
||||||
"filter_label": "Szűrő",
|
"filter_label": "Szűrő",
|
||||||
"user_label": "Felhasználó",
|
"user_label": "Felhasználó",
|
||||||
|
"photo_label": "Fénykép",
|
||||||
"sort_label": "Rendezés",
|
"sort_label": "Rendezés",
|
||||||
"group_by_label": "Csoportosítás",
|
"group_by_label": "Csoportosítás",
|
||||||
"state_value_help": "A HA állapotértékét használja (általában kisbetűs, pl. „on”/„off”). A kis- és nagybetűk mentéskor normalizálódnak.",
|
"state_value_help": "A HA állapotértékét használja (általában kisbetűs, pl. „on”/„off”). A kis- és nagybetűk mentéskor normalizálódnak.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Készlet módosítása",
|
"part_restock": "Készlet módosítása",
|
||||||
"restock_quantity_label": "Vásárolt mennyiség",
|
"restock_quantity_label": "Vásárolt mennyiség",
|
||||||
"consumes_parts_label": "Felhasznált alkatrészek",
|
"consumes_parts_label": "Felhasznált alkatrészek",
|
||||||
|
"shared_parts_other_objects": "Más objektumok alkatrészei",
|
||||||
|
"shared_parts_help": "Több objektum is használhatja ugyanazt a készletet. A feladat elvégzése a tulajdonos objektum készletéből von le.",
|
||||||
|
"shared_part_unknown": "Ismeretlen alkatrész",
|
||||||
"parts_load_failed": "Az objektum alkatrészei nem tölthetők be — a felhasznált alkatrészek beállításai most nem érhetők el.",
|
"parts_load_failed": "Az objektum alkatrészei nem tölthetők be — a felhasznált alkatrészek beállításai most nem érhetők el.",
|
||||||
"adopt_problem_button": "Problémaérzékelők átvétele",
|
"adopt_problem_button": "Problémaérzékelők átvétele",
|
||||||
"adopt_problem_title": "Problémaérzékelők átvétele",
|
"adopt_problem_title": "Problémaérzékelők átvétele",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valore trigger",
|
"trigger_val": "Valore trigger",
|
||||||
"complete_title": "Completato: ",
|
"complete_title": "Completato: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Richiedi al completamento",
|
||||||
"checklist_steps_optional": "Passaggi della checklist (opzionale)",
|
"checklist_steps_optional": "Passaggi della checklist (opzionale)",
|
||||||
"checklist_placeholder": "Pulire il filtro\nSostituire la guarnizione\nTestare la pressione",
|
"checklist_placeholder": "Pulire il filtro\nSostituire la guarnizione\nTestare la pressione",
|
||||||
"checklist_help": "Un passaggio per riga. Max 100 elementi.",
|
"checklist_help": "Un passaggio per riga. Max 100 elementi.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vuoto = mostra tutti gli stati.",
|
"card_filter_status_help": "Vuoto = mostra tutti gli stati.",
|
||||||
"card_filter_objects": "Filtra per oggetti",
|
"card_filter_objects": "Filtra per oggetti",
|
||||||
"card_filter_objects_help": "Vuoto = mostra tutti gli oggetti.",
|
"card_filter_objects_help": "Vuoto = mostra tutti gli oggetti.",
|
||||||
|
"card_filter_areas": "Filtra per aree",
|
||||||
|
"card_filter_areas_help": "Vuoto = mostra tutte le aree.",
|
||||||
"card_filter_entities": "Filtra per entità (entity_ids)",
|
"card_filter_entities": "Filtra per entità (entity_ids)",
|
||||||
"card_filter_entities_help": "Seleziona entità sensor / binary_sensor da questa integrazione. Vuoto = tutte.",
|
"card_filter_entities_help": "Seleziona entità sensor / binary_sensor da questa integrazione. Vuoto = tutte.",
|
||||||
"card_loading_objects": "Caricamento oggetti…",
|
"card_loading_objects": "Caricamento oggetti…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Titolo pannello laterale",
|
"settings_panel_title": "Titolo pannello laterale",
|
||||||
"settings_notifications": "Notifiche",
|
"settings_notifications": "Notifiche",
|
||||||
"settings_notify_service": "Servizio di notifica",
|
"settings_notify_service": "Servizio di notifica",
|
||||||
|
"settings_install_assist_sentences": "Installa le frasi di Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia le frasi vocali nella tua configurazione affinché l'agente Assist classico le riconosca. Un file modificato da te non viene mai sovrascritto.",
|
||||||
"test_notification": "Notifica di test",
|
"test_notification": "Notifica di test",
|
||||||
"send_test": "Invia test",
|
"send_test": "Invia test",
|
||||||
"testing": "Invio in corso…",
|
"testing": "Invio in corso…",
|
||||||
"test_notification_success": "Notifica di test inviata",
|
"test_notification_success": "Notifica di test inviata",
|
||||||
"test_notification_failed": "Notifica di test non riuscita",
|
"test_notification_failed": "Notifica di test non riuscita",
|
||||||
|
"notify_per_person": "Consegna per persona",
|
||||||
|
"notify_no_own_device": "Nessun dispositivo proprio — usa il servizio della casa",
|
||||||
"settings_notify_due_soon": "Notifica quando in scadenza",
|
"settings_notify_due_soon": "Notifica quando in scadenza",
|
||||||
"settings_notify_overdue": "Notifica quando scaduto",
|
"settings_notify_overdue": "Notifica quando scaduto",
|
||||||
"settings_notify_triggered": "Notifica quando attivato",
|
"settings_notify_triggered": "Notifica quando attivato",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Per utente",
|
"groupby_user": "Per utente",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Utente",
|
"user_label": "Utente",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordinamento",
|
"sort_label": "Ordinamento",
|
||||||
"group_by_label": "Raggruppa per",
|
"group_by_label": "Raggruppa per",
|
||||||
"state_value_help": "Usa il valore di stato HA (di solito minuscolo, es. \"on\"/\"off\"). Il case viene normalizzato al salvataggio.",
|
"state_value_help": "Usa il valore di stato HA (di solito minuscolo, es. \"on\"/\"off\"). Il case viene normalizzato al salvataggio.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Correggi scorta",
|
"part_restock": "Correggi scorta",
|
||||||
"restock_quantity_label": "Quantità acquistata",
|
"restock_quantity_label": "Quantità acquistata",
|
||||||
"consumes_parts_label": "Consuma ricambi",
|
"consumes_parts_label": "Consuma ricambi",
|
||||||
|
"shared_parts_other_objects": "Ricambi di altri oggetti",
|
||||||
|
"shared_parts_help": "Più oggetti possono condividere una sola scorta. Completando questa attività si preleva dall'oggetto proprietario.",
|
||||||
|
"shared_part_unknown": "Ricambio sconosciuto",
|
||||||
"parts_load_failed": "Impossibile caricare i ricambi di questo oggetto — le opzioni di consumo ricambi non sono al momento disponibili.",
|
"parts_load_failed": "Impossibile caricare i ricambi di questo oggetto — le opzioni di consumo ricambi non sono al momento disponibili.",
|
||||||
"settings_export_selection": "Limita agli oggetti selezionati (facoltativo)",
|
"settings_export_selection": "Limita agli oggetti selezionati (facoltativo)",
|
||||||
"settings_docs_archive": "Archivio documenti (con file)",
|
"settings_docs_archive": "Archivio documenti (con file)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "トリガー値",
|
"trigger_val": "トリガー値",
|
||||||
"complete_title": "完了: ",
|
"complete_title": "完了: ",
|
||||||
"checklist": "チェックリスト",
|
"checklist": "チェックリスト",
|
||||||
|
"require_on_completion": "完了時に必須",
|
||||||
"checklist_steps_optional": "チェックリストの手順(任意)",
|
"checklist_steps_optional": "チェックリストの手順(任意)",
|
||||||
"checklist_placeholder": "フィルター清掃\nシール交換\n圧力テスト",
|
"checklist_placeholder": "フィルター清掃\nシール交換\n圧力テスト",
|
||||||
"checklist_help": "1行に1手順。最大100項目。",
|
"checklist_help": "1行に1手順。最大100項目。",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "空欄=すべての状態を表示。",
|
"card_filter_status_help": "空欄=すべての状態を表示。",
|
||||||
"card_filter_objects": "対象で絞り込み",
|
"card_filter_objects": "対象で絞り込み",
|
||||||
"card_filter_objects_help": "空欄=すべての対象を表示。",
|
"card_filter_objects_help": "空欄=すべての対象を表示。",
|
||||||
|
"card_filter_areas": "エリアで絞り込み",
|
||||||
|
"card_filter_areas_help": "空欄=すべてのエリアを表示。",
|
||||||
"card_filter_entities": "エンティティで絞り込み(entity_ids)",
|
"card_filter_entities": "エンティティで絞り込み(entity_ids)",
|
||||||
"card_filter_entities_help": "この統合のsensor/binary_sensorエンティティを選択。空欄=すべて。",
|
"card_filter_entities_help": "この統合のsensor/binary_sensorエンティティを選択。空欄=すべて。",
|
||||||
"card_loading_objects": "対象を読み込み中…",
|
"card_loading_objects": "対象を読み込み中…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "サイドバーパネルのタイトル",
|
"settings_panel_title": "サイドバーパネルのタイトル",
|
||||||
"settings_notifications": "通知",
|
"settings_notifications": "通知",
|
||||||
"settings_notify_service": "通知サービス",
|
"settings_notify_service": "通知サービス",
|
||||||
|
"settings_install_assist_sentences": "Assist の文を導入する",
|
||||||
|
"settings_install_assist_sentences_hint": "音声フレーズを設定に複製し、従来の Assist エージェントが認識できるようにします。自分で編集したファイルが上書きされることはありません。",
|
||||||
"test_notification": "テスト通知",
|
"test_notification": "テスト通知",
|
||||||
"send_test": "テスト送信",
|
"send_test": "テスト送信",
|
||||||
"testing": "送信中…",
|
"testing": "送信中…",
|
||||||
"test_notification_success": "テスト通知を送信しました",
|
"test_notification_success": "テスト通知を送信しました",
|
||||||
"test_notification_failed": "テスト通知に失敗しました",
|
"test_notification_failed": "テスト通知に失敗しました",
|
||||||
|
"notify_per_person": "メンバーごとの配信",
|
||||||
|
"notify_no_own_device": "個人の端末なし — 家庭用サービスを使用",
|
||||||
"settings_notify_due_soon": "期限間近で通知",
|
"settings_notify_due_soon": "期限間近で通知",
|
||||||
"settings_notify_overdue": "期限超過で通知",
|
"settings_notify_overdue": "期限超過で通知",
|
||||||
"settings_notify_triggered": "トリガー発生で通知",
|
"settings_notify_triggered": "トリガー発生で通知",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "ユーザー別",
|
"groupby_user": "ユーザー別",
|
||||||
"filter_label": "絞り込み",
|
"filter_label": "絞り込み",
|
||||||
"user_label": "ユーザー",
|
"user_label": "ユーザー",
|
||||||
|
"photo_label": "写真",
|
||||||
"sort_label": "並べ替え",
|
"sort_label": "並べ替え",
|
||||||
"group_by_label": "グループ化",
|
"group_by_label": "グループ化",
|
||||||
"state_value_help": "HAの状態値を使用してください(通常は小文字、例: \"on\"/\"off\")。保存時に大文字小文字は正規化されます。",
|
"state_value_help": "HAの状態値を使用してください(通常は小文字、例: \"on\"/\"off\")。保存時に大文字小文字は正規化されます。",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "在庫を調整",
|
"part_restock": "在庫を調整",
|
||||||
"restock_quantity_label": "購入数量",
|
"restock_quantity_label": "購入数量",
|
||||||
"consumes_parts_label": "部品を消費",
|
"consumes_parts_label": "部品を消費",
|
||||||
|
"shared_parts_other_objects": "他の対象の部品",
|
||||||
|
"shared_parts_help": "複数の対象で同じ在庫を共有できます。このタスクを完了すると、所有する対象の在庫から差し引かれます。",
|
||||||
|
"shared_part_unknown": "不明な部品",
|
||||||
"parts_load_failed": "このオブジェクトの部品を読み込めませんでした — 部品消費オプションは現在利用できません。",
|
"parts_load_failed": "このオブジェクトの部品を読み込めませんでした — 部品消費オプションは現在利用できません。",
|
||||||
"settings_export_selection": "選択したオブジェクトに限定(任意)",
|
"settings_export_selection": "選択したオブジェクトに限定(任意)",
|
||||||
"settings_docs_archive": "ドキュメントアーカイブ(ファイル付き)",
|
"settings_docs_archive": "ドキュメントアーカイブ(ファイル付き)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "트리거 값",
|
"trigger_val": "트리거 값",
|
||||||
"complete_title": "완료: ",
|
"complete_title": "완료: ",
|
||||||
"checklist": "체크리스트",
|
"checklist": "체크리스트",
|
||||||
|
"require_on_completion": "완료 시 필수 입력",
|
||||||
"checklist_steps_optional": "체크리스트 단계 (선택)",
|
"checklist_steps_optional": "체크리스트 단계 (선택)",
|
||||||
"checklist_placeholder": "필터 청소\n씰 교체\n압력 테스트",
|
"checklist_placeholder": "필터 청소\n씰 교체\n압력 테스트",
|
||||||
"checklist_help": "한 줄에 한 단계씩 입력하세요. 최대 100개.",
|
"checklist_help": "한 줄에 한 단계씩 입력하세요. 최대 100개.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "비워두면 모든 상태를 표시합니다.",
|
"card_filter_status_help": "비워두면 모든 상태를 표시합니다.",
|
||||||
"card_filter_objects": "객체로 필터",
|
"card_filter_objects": "객체로 필터",
|
||||||
"card_filter_objects_help": "비워두면 모든 객체를 표시합니다.",
|
"card_filter_objects_help": "비워두면 모든 객체를 표시합니다.",
|
||||||
|
"card_filter_areas": "구역으로 필터",
|
||||||
|
"card_filter_areas_help": "비워두면 모든 구역을 표시합니다.",
|
||||||
"card_filter_entities": "엔티티로 필터 (entity_ids)",
|
"card_filter_entities": "엔티티로 필터 (entity_ids)",
|
||||||
"card_filter_entities_help": "이 통합구성요소의 sensor / binary_sensor 엔티티를 선택하세요. 비워두면 전체.",
|
"card_filter_entities_help": "이 통합구성요소의 sensor / binary_sensor 엔티티를 선택하세요. 비워두면 전체.",
|
||||||
"card_loading_objects": "객체 불러오는 중…",
|
"card_loading_objects": "객체 불러오는 중…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "사이드바 패널 제목",
|
"settings_panel_title": "사이드바 패널 제목",
|
||||||
"settings_notifications": "알림",
|
"settings_notifications": "알림",
|
||||||
"settings_notify_service": "알림 서비스",
|
"settings_notify_service": "알림 서비스",
|
||||||
|
"settings_install_assist_sentences": "Assist 문장 설치",
|
||||||
|
"settings_install_assist_sentences_hint": "음성 문장을 설정에 복사하여 기존 Assist 에이전트가 인식하도록 합니다. 직접 수정한 파일은 절대 덮어쓰지 않습니다.",
|
||||||
"test_notification": "테스트 알림",
|
"test_notification": "테스트 알림",
|
||||||
"send_test": "테스트 보내기",
|
"send_test": "테스트 보내기",
|
||||||
"testing": "보내는 중…",
|
"testing": "보내는 중…",
|
||||||
"test_notification_success": "테스트 알림을 보냈습니다",
|
"test_notification_success": "테스트 알림을 보냈습니다",
|
||||||
"test_notification_failed": "테스트 알림 전송 실패",
|
"test_notification_failed": "테스트 알림 전송 실패",
|
||||||
|
"notify_per_person": "사용자별 전송",
|
||||||
|
"notify_no_own_device": "개인 기기 없음 — 가정 서비스 사용",
|
||||||
"settings_notify_due_soon": "기한 임박 시 알림",
|
"settings_notify_due_soon": "기한 임박 시 알림",
|
||||||
"settings_notify_overdue": "기한 초과 시 알림",
|
"settings_notify_overdue": "기한 초과 시 알림",
|
||||||
"settings_notify_triggered": "트리거 시 알림",
|
"settings_notify_triggered": "트리거 시 알림",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "사용자별",
|
"groupby_user": "사용자별",
|
||||||
"filter_label": "필터",
|
"filter_label": "필터",
|
||||||
"user_label": "사용자",
|
"user_label": "사용자",
|
||||||
|
"photo_label": "사진",
|
||||||
"sort_label": "정렬",
|
"sort_label": "정렬",
|
||||||
"group_by_label": "그룹화",
|
"group_by_label": "그룹화",
|
||||||
"state_value_help": "HA 상태 값을 사용하세요(보통 소문자, 예: \"on\"/\"off\"). 대소문자는 저장 시 정규화됩니다.",
|
"state_value_help": "HA 상태 값을 사용하세요(보통 소문자, 예: \"on\"/\"off\"). 대소문자는 저장 시 정규화됩니다.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "재고 조정",
|
"part_restock": "재고 조정",
|
||||||
"restock_quantity_label": "구매 수량",
|
"restock_quantity_label": "구매 수량",
|
||||||
"consumes_parts_label": "사용하는 부품",
|
"consumes_parts_label": "사용하는 부품",
|
||||||
|
"shared_parts_other_objects": "다른 객체의 부품",
|
||||||
|
"shared_parts_help": "여러 객체가 하나의 재고를 공유할 수 있습니다. 이 작업을 완료하면 소유 객체의 재고에서 차감됩니다.",
|
||||||
|
"shared_part_unknown": "알 수 없는 부품",
|
||||||
"parts_load_failed": "이 객체의 부품을 불러올 수 없습니다 — 부품 사용 옵션을 지금은 쓸 수 없습니다.",
|
"parts_load_failed": "이 객체의 부품을 불러올 수 없습니다 — 부품 사용 옵션을 지금은 쓸 수 없습니다.",
|
||||||
"adopt_problem_button": "문제 센서 가져오기",
|
"adopt_problem_button": "문제 센서 가져오기",
|
||||||
"adopt_problem_title": "문제 센서 가져오기",
|
"adopt_problem_title": "문제 센서 가져오기",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Utløserverdi",
|
"trigger_val": "Utløserverdi",
|
||||||
"complete_title": "Fullfør: ",
|
"complete_title": "Fullfør: ",
|
||||||
"checklist": "Sjekkliste",
|
"checklist": "Sjekkliste",
|
||||||
|
"require_on_completion": "Krev ved fullføring",
|
||||||
"checklist_steps_optional": "Sjekklistetrinn (valgfritt)",
|
"checklist_steps_optional": "Sjekklistetrinn (valgfritt)",
|
||||||
"checklist_placeholder": "Rengjør filter\nBytt pakning\nTest trykk",
|
"checklist_placeholder": "Rengjør filter\nBytt pakning\nTest trykk",
|
||||||
"checklist_help": "Ett trinn per linje. Maks 100 elementer.",
|
"checklist_help": "Ett trinn per linje. Maks 100 elementer.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Tom = vis alle statuser.",
|
"card_filter_status_help": "Tom = vis alle statuser.",
|
||||||
"card_filter_objects": "Filtrer etter objekter",
|
"card_filter_objects": "Filtrer etter objekter",
|
||||||
"card_filter_objects_help": "Tom = vis alle objekter.",
|
"card_filter_objects_help": "Tom = vis alle objekter.",
|
||||||
|
"card_filter_areas": "Filtrer etter områder",
|
||||||
|
"card_filter_areas_help": "Tom = vis alle områder.",
|
||||||
"card_filter_entities": "Filtrer etter entiteter (entity_ids)",
|
"card_filter_entities": "Filtrer etter entiteter (entity_ids)",
|
||||||
"card_filter_entities_help": "Velg sensor-/binary_sensor-entiteter fra denne integrasjonen. Tom = alle.",
|
"card_filter_entities_help": "Velg sensor-/binary_sensor-entiteter fra denne integrasjonen. Tom = alle.",
|
||||||
"card_loading_objects": "Laster objekter…",
|
"card_loading_objects": "Laster objekter…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Tittel på sidepanel",
|
"settings_panel_title": "Tittel på sidepanel",
|
||||||
"settings_notifications": "Varsler",
|
"settings_notifications": "Varsler",
|
||||||
"settings_notify_service": "Varslingstjeneste",
|
"settings_notify_service": "Varslingstjeneste",
|
||||||
|
"settings_install_assist_sentences": "Installer Assist-setninger",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopierer talesetningene til konfigurasjonen din slik at den klassiske Assist-agenten gjenkjenner dem. En fil du selv har endret, blir aldri overskrevet.",
|
||||||
"test_notification": "Testvarsel",
|
"test_notification": "Testvarsel",
|
||||||
"send_test": "Send test",
|
"send_test": "Send test",
|
||||||
"testing": "Sender…",
|
"testing": "Sender…",
|
||||||
"test_notification_success": "Testvarsel sendt",
|
"test_notification_success": "Testvarsel sendt",
|
||||||
"test_notification_failed": "Testvarsel mislyktes",
|
"test_notification_failed": "Testvarsel mislyktes",
|
||||||
|
"notify_per_person": "Levering per person",
|
||||||
|
"notify_no_own_device": "Ingen egen enhet — bruker husstandens tjeneste",
|
||||||
"settings_notify_due_soon": "Varsle når noe forfaller snart",
|
"settings_notify_due_soon": "Varsle når noe forfaller snart",
|
||||||
"settings_notify_overdue": "Varsle når noe er forfalt",
|
"settings_notify_overdue": "Varsle når noe er forfalt",
|
||||||
"settings_notify_triggered": "Varsle når noe utløses",
|
"settings_notify_triggered": "Varsle når noe utløses",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Etter bruker",
|
"groupby_user": "Etter bruker",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Bruker",
|
"user_label": "Bruker",
|
||||||
|
"photo_label": "Bilde",
|
||||||
"sort_label": "Sorter",
|
"sort_label": "Sorter",
|
||||||
"group_by_label": "Grupper etter",
|
"group_by_label": "Grupper etter",
|
||||||
"state_value_help": "Bruk HA-tilstandsverdien (vanligvis små bokstaver, f.eks. \"on\"/\"off\"). Store/små bokstaver normaliseres ved lagring.",
|
"state_value_help": "Bruk HA-tilstandsverdien (vanligvis små bokstaver, f.eks. \"on\"/\"off\"). Store/små bokstaver normaliseres ved lagring.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Juster lager",
|
"part_restock": "Juster lager",
|
||||||
"restock_quantity_label": "Kjøpt mengde",
|
"restock_quantity_label": "Kjøpt mengde",
|
||||||
"consumes_parts_label": "Forbruker deler",
|
"consumes_parts_label": "Forbruker deler",
|
||||||
|
"shared_parts_other_objects": "Deler fra andre objekter",
|
||||||
|
"shared_parts_help": "Flere objekter kan dele samme lager. Når oppgaven fullføres, trekkes det fra det eiende objektet.",
|
||||||
|
"shared_part_unknown": "Ukjent del",
|
||||||
"parts_load_failed": "Kunne ikke laste objektets deler — forbruksvalgene er ikke tilgjengelige nå.",
|
"parts_load_failed": "Kunne ikke laste objektets deler — forbruksvalgene er ikke tilgjengelige nå.",
|
||||||
"settings_export_selection": "Begrens til valgte objekter (valgfritt)",
|
"settings_export_selection": "Begrens til valgte objekter (valgfritt)",
|
||||||
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Triggerwaarde",
|
"trigger_val": "Triggerwaarde",
|
||||||
"complete_title": "Voltooid: ",
|
"complete_title": "Voltooid: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Vereisen bij afronden",
|
||||||
"checklist_steps_optional": "Checklist-stappen (optioneel)",
|
"checklist_steps_optional": "Checklist-stappen (optioneel)",
|
||||||
"checklist_placeholder": "Filter schoonmaken\nPakking vervangen\nDruk testen",
|
"checklist_placeholder": "Filter schoonmaken\nPakking vervangen\nDruk testen",
|
||||||
"checklist_help": "Eén stap per regel. Max. 100 items.",
|
"checklist_help": "Eén stap per regel. Max. 100 items.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Leeg = alle statussen tonen.",
|
"card_filter_status_help": "Leeg = alle statussen tonen.",
|
||||||
"card_filter_objects": "Filteren op objecten",
|
"card_filter_objects": "Filteren op objecten",
|
||||||
"card_filter_objects_help": "Leeg = alle objecten tonen.",
|
"card_filter_objects_help": "Leeg = alle objecten tonen.",
|
||||||
|
"card_filter_areas": "Filteren op gebieden",
|
||||||
|
"card_filter_areas_help": "Leeg = alle gebieden tonen.",
|
||||||
"card_filter_entities": "Filteren op entiteiten (entity_ids)",
|
"card_filter_entities": "Filteren op entiteiten (entity_ids)",
|
||||||
"card_filter_entities_help": "Kies sensor/binary_sensor entiteiten van deze integratie. Leeg = alle.",
|
"card_filter_entities_help": "Kies sensor/binary_sensor entiteiten van deze integratie. Leeg = alle.",
|
||||||
"card_loading_objects": "Objecten laden…",
|
"card_loading_objects": "Objecten laden…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Titel zijbalkpaneel",
|
"settings_panel_title": "Titel zijbalkpaneel",
|
||||||
"settings_notifications": "Meldingen",
|
"settings_notifications": "Meldingen",
|
||||||
"settings_notify_service": "Meldingsservice",
|
"settings_notify_service": "Meldingsservice",
|
||||||
|
"settings_install_assist_sentences": "Assist-zinnen installeren",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopieert de spraakzinnen naar je configuratie zodat de klassieke Assist-agent ze herkent. Een bestand dat je zelf hebt bewerkt wordt nooit overschreven.",
|
||||||
"test_notification": "Testmelding",
|
"test_notification": "Testmelding",
|
||||||
"send_test": "Test versturen",
|
"send_test": "Test versturen",
|
||||||
"testing": "Verzenden…",
|
"testing": "Verzenden…",
|
||||||
"test_notification_success": "Testmelding verzonden",
|
"test_notification_success": "Testmelding verzonden",
|
||||||
"test_notification_failed": "Testmelding mislukt",
|
"test_notification_failed": "Testmelding mislukt",
|
||||||
|
"notify_per_person": "Bezorging per persoon",
|
||||||
|
"notify_no_own_device": "Geen eigen apparaat — gebruikt de huishoudelijke dienst",
|
||||||
"settings_notify_due_soon": "Melding bij bijna verlopen",
|
"settings_notify_due_soon": "Melding bij bijna verlopen",
|
||||||
"settings_notify_overdue": "Melding bij achterstallig",
|
"settings_notify_overdue": "Melding bij achterstallig",
|
||||||
"settings_notify_triggered": "Melding bij geactiveerd",
|
"settings_notify_triggered": "Melding bij geactiveerd",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Per gebruiker",
|
"groupby_user": "Per gebruiker",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Gebruiker",
|
"user_label": "Gebruiker",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sorteren",
|
"sort_label": "Sorteren",
|
||||||
"group_by_label": "Groeperen op",
|
"group_by_label": "Groeperen op",
|
||||||
"state_value_help": "Gebruik de HA-statuswaarde (meestal in kleine letters, bv. \"on\"/\"off\"). Hoofdletters worden bij opslaan genormaliseerd.",
|
"state_value_help": "Gebruik de HA-statuswaarde (meestal in kleine letters, bv. \"on\"/\"off\"). Hoofdletters worden bij opslaan genormaliseerd.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Voorraad aanpassen",
|
"part_restock": "Voorraad aanpassen",
|
||||||
"restock_quantity_label": "Gekochte hoeveelheid",
|
"restock_quantity_label": "Gekochte hoeveelheid",
|
||||||
"consumes_parts_label": "Verbruikt onderdelen",
|
"consumes_parts_label": "Verbruikt onderdelen",
|
||||||
|
"shared_parts_other_objects": "Onderdelen van andere objecten",
|
||||||
|
"shared_parts_help": "Meerdere objecten kunnen één voorraad delen. Bij afronden wordt van het eigenaarsobject afgeboekt.",
|
||||||
|
"shared_part_unknown": "Onbekend onderdeel",
|
||||||
"parts_load_failed": "Kon de onderdelen van dit object niet laden — de verbruiksopties zijn nu niet beschikbaar.",
|
"parts_load_failed": "Kon de onderdelen van dit object niet laden — de verbruiksopties zijn nu niet beschikbaar.",
|
||||||
"settings_export_selection": "Beperken tot geselecteerde objecten (optioneel)",
|
"settings_export_selection": "Beperken tot geselecteerde objecten (optioneel)",
|
||||||
"settings_docs_archive": "Documentenarchief (met bestanden)",
|
"settings_docs_archive": "Documentenarchief (met bestanden)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Wartość wyzwalacza",
|
"trigger_val": "Wartość wyzwalacza",
|
||||||
"complete_title": "Wykonaj: ",
|
"complete_title": "Wykonaj: ",
|
||||||
"checklist": "Lista kontrolna",
|
"checklist": "Lista kontrolna",
|
||||||
|
"require_on_completion": "Wymagaj przy zakończeniu",
|
||||||
"checklist_steps_optional": "Kroki listy kontrolnej (opcjonalne)",
|
"checklist_steps_optional": "Kroki listy kontrolnej (opcjonalne)",
|
||||||
"checklist_placeholder": "Wyczyść filtr\nWymień uszczelkę\nSprawdź ciśnienie",
|
"checklist_placeholder": "Wyczyść filtr\nWymień uszczelkę\nSprawdź ciśnienie",
|
||||||
"checklist_help": "Jeden krok na linię. Maks. 100 elementów.",
|
"checklist_help": "Jeden krok na linię. Maks. 100 elementów.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Puste = pokaż wszystkie statusy.",
|
"card_filter_status_help": "Puste = pokaż wszystkie statusy.",
|
||||||
"card_filter_objects": "Filtruj wg obiektów",
|
"card_filter_objects": "Filtruj wg obiektów",
|
||||||
"card_filter_objects_help": "Puste = pokaż wszystkie obiekty.",
|
"card_filter_objects_help": "Puste = pokaż wszystkie obiekty.",
|
||||||
|
"card_filter_areas": "Filtruj wg obszarów",
|
||||||
|
"card_filter_areas_help": "Puste = pokaż wszystkie obszary.",
|
||||||
"card_filter_entities": "Filtruj wg encji (entity_ids)",
|
"card_filter_entities": "Filtruj wg encji (entity_ids)",
|
||||||
"card_filter_entities_help": "Wybierz encje sensor / binary_sensor z tej integracji. Puste = wszystkie.",
|
"card_filter_entities_help": "Wybierz encje sensor / binary_sensor z tej integracji. Puste = wszystkie.",
|
||||||
"card_loading_objects": "Ładowanie obiektów…",
|
"card_loading_objects": "Ładowanie obiektów…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Tytuł panelu bocznego",
|
"settings_panel_title": "Tytuł panelu bocznego",
|
||||||
"settings_notifications": "Powiadomienia",
|
"settings_notifications": "Powiadomienia",
|
||||||
"settings_notify_service": "Usługa powiadomień",
|
"settings_notify_service": "Usługa powiadomień",
|
||||||
|
"settings_install_assist_sentences": "Zainstaluj zdania Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopiuje zdania głosowe do Twojej konfiguracji, aby klasyczny agent Assist je rozpoznawał. Plik zmieniony przez Ciebie nigdy nie zostanie nadpisany.",
|
||||||
"test_notification": "Powiadomienie testowe",
|
"test_notification": "Powiadomienie testowe",
|
||||||
"send_test": "Wyślij test",
|
"send_test": "Wyślij test",
|
||||||
"testing": "Wysyłanie…",
|
"testing": "Wysyłanie…",
|
||||||
"test_notification_success": "Powiadomienie testowe wysłane",
|
"test_notification_success": "Powiadomienie testowe wysłane",
|
||||||
"test_notification_failed": "Powiadomienie testowe nie powiodło się",
|
"test_notification_failed": "Powiadomienie testowe nie powiodło się",
|
||||||
|
"notify_per_person": "Dostarczanie dla każdej osoby",
|
||||||
|
"notify_no_own_device": "Brak własnego urządzenia — używa usługi domowej",
|
||||||
"settings_notify_due_soon": "Powiadom gdy wkrótce",
|
"settings_notify_due_soon": "Powiadom gdy wkrótce",
|
||||||
"settings_notify_overdue": "Powiadom gdy zaległe",
|
"settings_notify_overdue": "Powiadom gdy zaległe",
|
||||||
"settings_notify_triggered": "Powiadom gdy wyzwolone",
|
"settings_notify_triggered": "Powiadom gdy wyzwolone",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Wg użytkownika",
|
"groupby_user": "Wg użytkownika",
|
||||||
"filter_label": "Filtr",
|
"filter_label": "Filtr",
|
||||||
"user_label": "Użytkownik",
|
"user_label": "Użytkownik",
|
||||||
|
"photo_label": "Zdjęcie",
|
||||||
"sort_label": "Sortowanie",
|
"sort_label": "Sortowanie",
|
||||||
"group_by_label": "Grupuj wg",
|
"group_by_label": "Grupuj wg",
|
||||||
"state_value_help": "Użyj wartości stanu HA (zwykle małymi literami, np. \"on\"/\"off\"). Wielkość liter jest normalizowana przy zapisie.",
|
"state_value_help": "Użyj wartości stanu HA (zwykle małymi literami, np. \"on\"/\"off\"). Wielkość liter jest normalizowana przy zapisie.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Koryguj stan",
|
"part_restock": "Koryguj stan",
|
||||||
"restock_quantity_label": "Kupiona ilość",
|
"restock_quantity_label": "Kupiona ilość",
|
||||||
"consumes_parts_label": "Zużywa części",
|
"consumes_parts_label": "Zużywa części",
|
||||||
|
"shared_parts_other_objects": "Części z innych obiektów",
|
||||||
|
"shared_parts_help": "Kilka obiektów może korzystać z jednego zapasu. Wykonanie tego zadania odejmuje ze stanu obiektu będącego właścicielem.",
|
||||||
|
"shared_part_unknown": "Nieznana część",
|
||||||
"parts_load_failed": "Nie udało się wczytać części tego obiektu — opcje zużycia części są teraz niedostępne.",
|
"parts_load_failed": "Nie udało się wczytać części tego obiektu — opcje zużycia części są teraz niedostępne.",
|
||||||
"settings_export_selection": "Ogranicz do wybranych obiektów (opcjonalnie)",
|
"settings_export_selection": "Ogranicz do wybranych obiektów (opcjonalnie)",
|
||||||
"settings_docs_archive": "Archiwum dokumentów (z plikami)",
|
"settings_docs_archive": "Archiwum dokumentów (z plikami)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Valor do gatilho",
|
"trigger_val": "Valor do gatilho",
|
||||||
"complete_title": "Concluir: ",
|
"complete_title": "Concluir: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Exigir ao concluir",
|
||||||
"checklist_steps_optional": "Etapas do checklist (opcional)",
|
"checklist_steps_optional": "Etapas do checklist (opcional)",
|
||||||
"checklist_placeholder": "Limpar o filtro\nTrocar a vedação\nTestar a pressão",
|
"checklist_placeholder": "Limpar o filtro\nTrocar a vedação\nTestar a pressão",
|
||||||
"checklist_help": "Uma etapa por linha. Máx. 100 itens.",
|
"checklist_help": "Uma etapa por linha. Máx. 100 itens.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Vazio = mostrar todos os status.",
|
"card_filter_status_help": "Vazio = mostrar todos os status.",
|
||||||
"card_filter_objects": "Filtrar por objetos",
|
"card_filter_objects": "Filtrar por objetos",
|
||||||
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
||||||
|
"card_filter_areas": "Filtrar por áreas",
|
||||||
|
"card_filter_areas_help": "Vazio = mostrar todas as áreas.",
|
||||||
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
||||||
"card_filter_entities_help": "Escolha entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
"card_filter_entities_help": "Escolha entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
||||||
"card_loading_objects": "Carregando objetos…",
|
"card_loading_objects": "Carregando objetos…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Título do painel na barra lateral",
|
"settings_panel_title": "Título do painel na barra lateral",
|
||||||
"settings_notifications": "Notificações",
|
"settings_notifications": "Notificações",
|
||||||
"settings_notify_service": "Serviço de notificação",
|
"settings_notify_service": "Serviço de notificação",
|
||||||
|
"settings_install_assist_sentences": "Instalar frases do Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia as frases de voz para a sua configuração para que o agente Assist clássico as reconheça. Um arquivo que você editou nunca é sobrescrito.",
|
||||||
"test_notification": "Notificação de teste",
|
"test_notification": "Notificação de teste",
|
||||||
"send_test": "Enviar teste",
|
"send_test": "Enviar teste",
|
||||||
"testing": "Enviando…",
|
"testing": "Enviando…",
|
||||||
"test_notification_success": "Notificação de teste enviada",
|
"test_notification_success": "Notificação de teste enviada",
|
||||||
"test_notification_failed": "Falha na notificação de teste",
|
"test_notification_failed": "Falha na notificação de teste",
|
||||||
|
"notify_per_person": "Entrega por pessoa",
|
||||||
|
"notify_no_own_device": "Sem dispositivo próprio — usa o serviço da casa",
|
||||||
"settings_notify_due_soon": "Notificar quando vencer em breve",
|
"settings_notify_due_soon": "Notificar quando vencer em breve",
|
||||||
"settings_notify_overdue": "Notificar quando atrasada",
|
"settings_notify_overdue": "Notificar quando atrasada",
|
||||||
"settings_notify_triggered": "Notificar quando acionada",
|
"settings_notify_triggered": "Notificar quando acionada",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "Por usuário",
|
"groupby_user": "Por usuário",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Usuário",
|
"user_label": "Usuário",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordenar",
|
"sort_label": "Ordenar",
|
||||||
"group_by_label": "Agrupar por",
|
"group_by_label": "Agrupar por",
|
||||||
"state_value_help": "Use o valor de estado do HA (geralmente minúsculo, ex.: \"on\"/\"off\"). Maiúsculas e minúsculas são normalizadas ao salvar.",
|
"state_value_help": "Use o valor de estado do HA (geralmente minúsculo, ex.: \"on\"/\"off\"). Maiúsculas e minúsculas são normalizadas ao salvar.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Ajustar estoque",
|
"part_restock": "Ajustar estoque",
|
||||||
"restock_quantity_label": "Quantidade comprada",
|
"restock_quantity_label": "Quantidade comprada",
|
||||||
"consumes_parts_label": "Consome peças",
|
"consumes_parts_label": "Consome peças",
|
||||||
|
"shared_parts_other_objects": "Peças de outros objetos",
|
||||||
|
"shared_parts_help": "Vários objetos podem compartilhar o mesmo estoque. Concluir esta tarefa desconta do objeto proprietário.",
|
||||||
|
"shared_part_unknown": "Peça desconhecida",
|
||||||
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis no momento.",
|
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis no momento.",
|
||||||
"adopt_problem_button": "Adotar sensores de problema",
|
"adopt_problem_button": "Adotar sensores de problema",
|
||||||
"adopt_problem_title": "Adotar sensores de problema",
|
"adopt_problem_title": "Adotar sensores de problema",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valor do acionador",
|
"trigger_val": "Valor do acionador",
|
||||||
"complete_title": "Concluída: ",
|
"complete_title": "Concluída: ",
|
||||||
"checklist": "Lista de verificação",
|
"checklist": "Lista de verificação",
|
||||||
|
"require_on_completion": "Exigir ao concluir",
|
||||||
"checklist_steps_optional": "Passos da lista de verificação (opcional)",
|
"checklist_steps_optional": "Passos da lista de verificação (opcional)",
|
||||||
"checklist_placeholder": "Limpar filtro\nSubstituir vedação\nTestar pressão",
|
"checklist_placeholder": "Limpar filtro\nSubstituir vedação\nTestar pressão",
|
||||||
"checklist_help": "Um passo por linha. Máx. 100 itens.",
|
"checklist_help": "Um passo por linha. Máx. 100 itens.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vazio = mostrar todos os estados.",
|
"card_filter_status_help": "Vazio = mostrar todos os estados.",
|
||||||
"card_filter_objects": "Filtrar por objetos",
|
"card_filter_objects": "Filtrar por objetos",
|
||||||
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
||||||
|
"card_filter_areas": "Filtrar por áreas",
|
||||||
|
"card_filter_areas_help": "Vazio = mostrar todas as áreas.",
|
||||||
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
||||||
"card_filter_entities_help": "Selecione entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
"card_filter_entities_help": "Selecione entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
||||||
"card_loading_objects": "A carregar objetos…",
|
"card_loading_objects": "A carregar objetos…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Título do painel lateral",
|
"settings_panel_title": "Título do painel lateral",
|
||||||
"settings_notifications": "Notificações",
|
"settings_notifications": "Notificações",
|
||||||
"settings_notify_service": "Serviço de notificação",
|
"settings_notify_service": "Serviço de notificação",
|
||||||
|
"settings_install_assist_sentences": "Instalar frases do Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia as frases de voz para a sua configuração para que o agente Assist clássico as reconheça. Um ficheiro que editou nunca é substituído.",
|
||||||
"test_notification": "Notificação de teste",
|
"test_notification": "Notificação de teste",
|
||||||
"send_test": "Enviar teste",
|
"send_test": "Enviar teste",
|
||||||
"testing": "A enviar…",
|
"testing": "A enviar…",
|
||||||
"test_notification_success": "Notificação de teste enviada",
|
"test_notification_success": "Notificação de teste enviada",
|
||||||
"test_notification_failed": "Falha na notificação de teste",
|
"test_notification_failed": "Falha na notificação de teste",
|
||||||
|
"notify_per_person": "Entrega por pessoa",
|
||||||
|
"notify_no_own_device": "Sem dispositivo próprio — usa o serviço da casa",
|
||||||
"settings_notify_due_soon": "Notificar quando próxima",
|
"settings_notify_due_soon": "Notificar quando próxima",
|
||||||
"settings_notify_overdue": "Notificar quando atrasada",
|
"settings_notify_overdue": "Notificar quando atrasada",
|
||||||
"settings_notify_triggered": "Notificar quando acionada",
|
"settings_notify_triggered": "Notificar quando acionada",
|
||||||
@@ -483,6 +490,7 @@
|
|||||||
"sort_group": "Grupo",
|
"sort_group": "Grupo",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Utilizador",
|
"user_label": "Utilizador",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordenar",
|
"sort_label": "Ordenar",
|
||||||
"group_by_label": "Agrupar por",
|
"group_by_label": "Agrupar por",
|
||||||
"state_value_help": "Use o valor de estado HA (normalmente em minúsculas, p. ex. \"on\"/\"off\"). As maiúsculas são normalizadas ao guardar.",
|
"state_value_help": "Use o valor de estado HA (normalmente em minúsculas, p. ex. \"on\"/\"off\"). As maiúsculas são normalizadas ao guardar.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Ajustar estoque",
|
"part_restock": "Ajustar estoque",
|
||||||
"restock_quantity_label": "Quantidade comprada",
|
"restock_quantity_label": "Quantidade comprada",
|
||||||
"consumes_parts_label": "Consome peças",
|
"consumes_parts_label": "Consome peças",
|
||||||
|
"shared_parts_other_objects": "Peças de outros objetos",
|
||||||
|
"shared_parts_help": "Vários objetos podem partilhar o mesmo stock. Concluir esta tarefa desconta do objeto proprietário.",
|
||||||
|
"shared_part_unknown": "Peça desconhecida",
|
||||||
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis.",
|
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis.",
|
||||||
"settings_export_selection": "Limitar aos objetos selecionados (opcional)",
|
"settings_export_selection": "Limitar aos objetos selecionados (opcional)",
|
||||||
"settings_docs_archive": "Arquivo de documentos (com ficheiros)",
|
"settings_docs_archive": "Arquivo de documentos (com ficheiros)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Значение триггера",
|
"trigger_val": "Значение триггера",
|
||||||
"complete_title": "Выполнить: ",
|
"complete_title": "Выполнить: ",
|
||||||
"checklist": "Контрольный список",
|
"checklist": "Контрольный список",
|
||||||
|
"require_on_completion": "Требовать при завершении",
|
||||||
"checklist_steps_optional": "Шаги контрольного списка (необязательно)",
|
"checklist_steps_optional": "Шаги контрольного списка (необязательно)",
|
||||||
"checklist_placeholder": "Очистить фильтр\nЗаменить уплотнитель\nПроверить давление",
|
"checklist_placeholder": "Очистить фильтр\nЗаменить уплотнитель\nПроверить давление",
|
||||||
"checklist_help": "Один шаг на строку. Макс. 100 элементов.",
|
"checklist_help": "Один шаг на строку. Макс. 100 элементов.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Пусто = показать все статусы.",
|
"card_filter_status_help": "Пусто = показать все статусы.",
|
||||||
"card_filter_objects": "Фильтровать по объектам",
|
"card_filter_objects": "Фильтровать по объектам",
|
||||||
"card_filter_objects_help": "Пусто = показать все объекты.",
|
"card_filter_objects_help": "Пусто = показать все объекты.",
|
||||||
|
"card_filter_areas": "Фильтровать по зонам",
|
||||||
|
"card_filter_areas_help": "Пусто = показать все зоны.",
|
||||||
"card_filter_entities": "Фильтровать по сущностям (entity_ids)",
|
"card_filter_entities": "Фильтровать по сущностям (entity_ids)",
|
||||||
"card_filter_entities_help": "Выберите сущности sensor / binary_sensor из этой интеграции. Пусто = все.",
|
"card_filter_entities_help": "Выберите сущности sensor / binary_sensor из этой интеграции. Пусто = все.",
|
||||||
"card_loading_objects": "Загрузка объектов…",
|
"card_loading_objects": "Загрузка объектов…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Заголовок панели",
|
"settings_panel_title": "Заголовок панели",
|
||||||
"settings_notifications": "Уведомления",
|
"settings_notifications": "Уведомления",
|
||||||
"settings_notify_service": "Сервис уведомлений",
|
"settings_notify_service": "Сервис уведомлений",
|
||||||
|
"settings_install_assist_sentences": "Установить фразы Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Копирует голосовые фразы в вашу конфигурацию, чтобы классический агент Assist их распознавал. Файл, который вы изменили, никогда не перезаписывается.",
|
||||||
"test_notification": "Тестовое уведомление",
|
"test_notification": "Тестовое уведомление",
|
||||||
"send_test": "Отправить тест",
|
"send_test": "Отправить тест",
|
||||||
"testing": "Отправка…",
|
"testing": "Отправка…",
|
||||||
"test_notification_success": "Тестовое уведомление отправлено",
|
"test_notification_success": "Тестовое уведомление отправлено",
|
||||||
"test_notification_failed": "Не удалось отправить тестовое уведомление",
|
"test_notification_failed": "Не удалось отправить тестовое уведомление",
|
||||||
|
"notify_per_person": "Доставка по пользователям",
|
||||||
|
"notify_no_own_device": "Нет своего устройства — используется общий сервис",
|
||||||
"settings_notify_due_soon": "Уведомлять, когда срок скоро истекает",
|
"settings_notify_due_soon": "Уведомлять, когда срок скоро истекает",
|
||||||
"settings_notify_overdue": "Уведомлять при просрочке",
|
"settings_notify_overdue": "Уведомлять при просрочке",
|
||||||
"settings_notify_triggered": "Уведомлять при срабатывании",
|
"settings_notify_triggered": "Уведомлять при срабатывании",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "По пользователю",
|
"groupby_user": "По пользователю",
|
||||||
"filter_label": "Фильтр",
|
"filter_label": "Фильтр",
|
||||||
"user_label": "Пользователь",
|
"user_label": "Пользователь",
|
||||||
|
"photo_label": "Фото",
|
||||||
"sort_label": "Сортировка",
|
"sort_label": "Сортировка",
|
||||||
"group_by_label": "Группировать по",
|
"group_by_label": "Группировать по",
|
||||||
"state_value_help": "Используйте значение состояния HA (обычно в нижнем регистре, напр. \"on\"/\"off\"). Регистр нормализуется при сохранении.",
|
"state_value_help": "Используйте значение состояния HA (обычно в нижнем регистре, напр. \"on\"/\"off\"). Регистр нормализуется при сохранении.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Изменить запас",
|
"part_restock": "Изменить запас",
|
||||||
"restock_quantity_label": "Куплено, шт.",
|
"restock_quantity_label": "Куплено, шт.",
|
||||||
"consumes_parts_label": "Расходует детали",
|
"consumes_parts_label": "Расходует детали",
|
||||||
|
"shared_parts_other_objects": "Детали других объектов",
|
||||||
|
"shared_parts_help": "Несколько объектов могут использовать один запас. Выполнение этой задачи списывает детали у объекта-владельца.",
|
||||||
|
"shared_part_unknown": "Неизвестная деталь",
|
||||||
"parts_load_failed": "Не удалось загрузить запчасти этого объекта — параметры расхода запчастей сейчас недоступны.",
|
"parts_load_failed": "Не удалось загрузить запчасти этого объекта — параметры расхода запчастей сейчас недоступны.",
|
||||||
"settings_export_selection": "Ограничить выбранными объектами (необязательно)",
|
"settings_export_selection": "Ограничить выбранными объектами (необязательно)",
|
||||||
"settings_docs_archive": "Архив документов (с файлами)",
|
"settings_docs_archive": "Архив документов (с файлами)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Utlösarvärde",
|
"trigger_val": "Utlösarvärde",
|
||||||
"complete_title": "Slutför: ",
|
"complete_title": "Slutför: ",
|
||||||
"checklist": "Checklista",
|
"checklist": "Checklista",
|
||||||
|
"require_on_completion": "Kräv vid slutförande",
|
||||||
"checklist_steps_optional": "Checkliststeg (valfritt)",
|
"checklist_steps_optional": "Checkliststeg (valfritt)",
|
||||||
"checklist_placeholder": "Rengör filter\nByt tätning\nTesta tryck",
|
"checklist_placeholder": "Rengör filter\nByt tätning\nTesta tryck",
|
||||||
"checklist_help": "Ett steg per rad. Max 100 objekt.",
|
"checklist_help": "Ett steg per rad. Max 100 objekt.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Tomt = visa alla statusar.",
|
"card_filter_status_help": "Tomt = visa alla statusar.",
|
||||||
"card_filter_objects": "Filtrera efter objekt",
|
"card_filter_objects": "Filtrera efter objekt",
|
||||||
"card_filter_objects_help": "Tomt = visa alla objekt.",
|
"card_filter_objects_help": "Tomt = visa alla objekt.",
|
||||||
|
"card_filter_areas": "Filtrera efter områden",
|
||||||
|
"card_filter_areas_help": "Tomt = visa alla områden.",
|
||||||
"card_filter_entities": "Filtrera efter entiteter (entity_ids)",
|
"card_filter_entities": "Filtrera efter entiteter (entity_ids)",
|
||||||
"card_filter_entities_help": "Välj sensor- / binary_sensor-entiteter från denna integration. Tomt = alla.",
|
"card_filter_entities_help": "Välj sensor- / binary_sensor-entiteter från denna integration. Tomt = alla.",
|
||||||
"card_loading_objects": "Laddar objekt…",
|
"card_loading_objects": "Laddar objekt…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Sidopanelens titel",
|
"settings_panel_title": "Sidopanelens titel",
|
||||||
"settings_notifications": "Notifikationer",
|
"settings_notifications": "Notifikationer",
|
||||||
"settings_notify_service": "Notifikationstjänst",
|
"settings_notify_service": "Notifikationstjänst",
|
||||||
|
"settings_install_assist_sentences": "Installera Assist-meningar",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopierar rösmeningarna till din konfiguration så att den klassiska Assist-agenten känner igen dem. En fil du själv har ändrat skrivs aldrig över.",
|
||||||
"test_notification": "Testnotifikation",
|
"test_notification": "Testnotifikation",
|
||||||
"send_test": "Skicka test",
|
"send_test": "Skicka test",
|
||||||
"testing": "Skickar…",
|
"testing": "Skickar…",
|
||||||
"test_notification_success": "Testnotifikation skickad",
|
"test_notification_success": "Testnotifikation skickad",
|
||||||
"test_notification_failed": "Testnotifikation misslyckades",
|
"test_notification_failed": "Testnotifikation misslyckades",
|
||||||
|
"notify_per_person": "Leverans per person",
|
||||||
|
"notify_no_own_device": "Ingen egen enhet — använder hushållets tjänst",
|
||||||
"settings_notify_due_soon": "Notifiera när snart förfallande",
|
"settings_notify_due_soon": "Notifiera när snart förfallande",
|
||||||
"settings_notify_overdue": "Notifiera när försenad",
|
"settings_notify_overdue": "Notifiera när försenad",
|
||||||
"settings_notify_triggered": "Notifiera när utlöst",
|
"settings_notify_triggered": "Notifiera när utlöst",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Per användare",
|
"groupby_user": "Per användare",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Användare",
|
"user_label": "Användare",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sortering",
|
"sort_label": "Sortering",
|
||||||
"group_by_label": "Gruppera efter",
|
"group_by_label": "Gruppera efter",
|
||||||
"state_value_help": "Använd HA-tillståndsvärdet (vanligtvis med små bokstäver, t.ex. \"on\"/\"off\"). Versaler normaliseras vid sparande.",
|
"state_value_help": "Använd HA-tillståndsvärdet (vanligtvis med små bokstäver, t.ex. \"on\"/\"off\"). Versaler normaliseras vid sparande.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Justera lager",
|
"part_restock": "Justera lager",
|
||||||
"restock_quantity_label": "Köpt antal",
|
"restock_quantity_label": "Köpt antal",
|
||||||
"consumes_parts_label": "Förbrukar delar",
|
"consumes_parts_label": "Förbrukar delar",
|
||||||
|
"shared_parts_other_objects": "Delar från andra objekt",
|
||||||
|
"shared_parts_help": "Flera objekt kan dela samma lager. När uppgiften slutförs dras det från det ägande objektet.",
|
||||||
|
"shared_part_unknown": "Okänd del",
|
||||||
"parts_load_failed": "Kunde inte läsa in objektets delar — förbrukningsalternativen är inte tillgängliga just nu.",
|
"parts_load_failed": "Kunde inte läsa in objektets delar — förbrukningsalternativen är inte tillgängliga just nu.",
|
||||||
"settings_export_selection": "Begränsa till valda objekt (valfritt)",
|
"settings_export_selection": "Begränsa till valda objekt (valfritt)",
|
||||||
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Tetikleme değeri",
|
"trigger_val": "Tetikleme değeri",
|
||||||
"complete_title": "Tamamla: ",
|
"complete_title": "Tamamla: ",
|
||||||
"checklist": "Kontrol listesi",
|
"checklist": "Kontrol listesi",
|
||||||
|
"require_on_completion": "Tamamlarken zorunlu tut",
|
||||||
"checklist_steps_optional": "Kontrol listesi adımları (isteğe bağlı)",
|
"checklist_steps_optional": "Kontrol listesi adımları (isteğe bağlı)",
|
||||||
"checklist_placeholder": "Filtreyi temizle\nContayı değiştir\nBasıncı test et",
|
"checklist_placeholder": "Filtreyi temizle\nContayı değiştir\nBasıncı test et",
|
||||||
"checklist_help": "Her satıra bir adım. En fazla 100 madde.",
|
"checklist_help": "Her satıra bir adım. En fazla 100 madde.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Boş = tüm durumları göster.",
|
"card_filter_status_help": "Boş = tüm durumları göster.",
|
||||||
"card_filter_objects": "Nesnelere göre filtrele",
|
"card_filter_objects": "Nesnelere göre filtrele",
|
||||||
"card_filter_objects_help": "Boş = tüm nesneleri göster.",
|
"card_filter_objects_help": "Boş = tüm nesneleri göster.",
|
||||||
|
"card_filter_areas": "Alanlara göre filtrele",
|
||||||
|
"card_filter_areas_help": "Boş = tüm alanları göster.",
|
||||||
"card_filter_entities": "Varlıklara göre filtrele (entity_id)",
|
"card_filter_entities": "Varlıklara göre filtrele (entity_id)",
|
||||||
"card_filter_entities_help": "Bu entegrasyonun sensor / binary_sensor varlıklarını seçin. Boş = tümü.",
|
"card_filter_entities_help": "Bu entegrasyonun sensor / binary_sensor varlıklarını seçin. Boş = tümü.",
|
||||||
"card_loading_objects": "Nesneler yükleniyor…",
|
"card_loading_objects": "Nesneler yükleniyor…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Kenar çubuğu paneli başlığı",
|
"settings_panel_title": "Kenar çubuğu paneli başlığı",
|
||||||
"settings_notifications": "Bildirimler",
|
"settings_notifications": "Bildirimler",
|
||||||
"settings_notify_service": "Bildirim servisi",
|
"settings_notify_service": "Bildirim servisi",
|
||||||
|
"settings_install_assist_sentences": "Assist cümlelerini yükle",
|
||||||
|
"settings_install_assist_sentences_hint": "Sesli komut cümlelerini yapılandırmanıza kopyalar, böylece klasik Assist aracısı bunları tanır. Kendi düzenlediğiniz bir dosyanın üzerine asla yazılmaz.",
|
||||||
"test_notification": "Test bildirimi",
|
"test_notification": "Test bildirimi",
|
||||||
"send_test": "Test gönder",
|
"send_test": "Test gönder",
|
||||||
"testing": "Gönderiliyor…",
|
"testing": "Gönderiliyor…",
|
||||||
"test_notification_success": "Test bildirimi gönderildi",
|
"test_notification_success": "Test bildirimi gönderildi",
|
||||||
"test_notification_failed": "Test bildirimi başarısız oldu",
|
"test_notification_failed": "Test bildirimi başarısız oldu",
|
||||||
|
"notify_per_person": "Kişi bazında iletim",
|
||||||
|
"notify_no_own_device": "Kendi cihazı yok — ev servisini kullanır",
|
||||||
"settings_notify_due_soon": "Vade yaklaştığında bildir",
|
"settings_notify_due_soon": "Vade yaklaştığında bildir",
|
||||||
"settings_notify_overdue": "Geciktiğinde bildir",
|
"settings_notify_overdue": "Geciktiğinde bildir",
|
||||||
"settings_notify_triggered": "Tetiklendiğinde bildir",
|
"settings_notify_triggered": "Tetiklendiğinde bildir",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "Kullanıcıya göre",
|
"groupby_user": "Kullanıcıya göre",
|
||||||
"filter_label": "Filtre",
|
"filter_label": "Filtre",
|
||||||
"user_label": "Kullanıcı",
|
"user_label": "Kullanıcı",
|
||||||
|
"photo_label": "Fotoğraf",
|
||||||
"sort_label": "Sırala",
|
"sort_label": "Sırala",
|
||||||
"group_by_label": "Grupla",
|
"group_by_label": "Grupla",
|
||||||
"state_value_help": "HA durum değerini kullanın (genellikle küçük harf, örn. \"on\"/\"off\"). Büyük/küçük harf kaydederken normalleştirilir.",
|
"state_value_help": "HA durum değerini kullanın (genellikle küçük harf, örn. \"on\"/\"off\"). Büyük/küçük harf kaydederken normalleştirilir.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Stoku ayarla",
|
"part_restock": "Stoku ayarla",
|
||||||
"restock_quantity_label": "Satın alınan miktar",
|
"restock_quantity_label": "Satın alınan miktar",
|
||||||
"consumes_parts_label": "Parça tüketir",
|
"consumes_parts_label": "Parça tüketir",
|
||||||
|
"shared_parts_other_objects": "Diğer nesnelerin parçaları",
|
||||||
|
"shared_parts_help": "Birden fazla nesne aynı stoğu paylaşabilir. Bu görev tamamlandığında stok, sahibi olan nesneden düşülür.",
|
||||||
|
"shared_part_unknown": "Bilinmeyen parça",
|
||||||
"parts_load_failed": "Bu nesnenin parçaları yüklenemedi — parça tüketimi seçenekleri şu anda kullanılamıyor.",
|
"parts_load_failed": "Bu nesnenin parçaları yüklenemedi — parça tüketimi seçenekleri şu anda kullanılamıyor.",
|
||||||
"adopt_problem_button": "Sorun sensörlerini devral",
|
"adopt_problem_button": "Sorun sensörlerini devral",
|
||||||
"adopt_problem_title": "Sorun sensörlerini devral",
|
"adopt_problem_title": "Sorun sensörlerini devral",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Значення тригера",
|
"trigger_val": "Значення тригера",
|
||||||
"complete_title": "Виконати: ",
|
"complete_title": "Виконати: ",
|
||||||
"checklist": "Чекліст",
|
"checklist": "Чекліст",
|
||||||
|
"require_on_completion": "Вимагати при завершенні",
|
||||||
"checklist_steps_optional": "Кроки чекліста (необов'язково)",
|
"checklist_steps_optional": "Кроки чекліста (необов'язково)",
|
||||||
"checklist_placeholder": "Очистити фільтр\nЗамінити ущільнювач\nПеревірити тиск",
|
"checklist_placeholder": "Очистити фільтр\nЗамінити ущільнювач\nПеревірити тиск",
|
||||||
"checklist_help": "Один крок на рядок. Макс. 100 елементів.",
|
"checklist_help": "Один крок на рядок. Макс. 100 елементів.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Порожньо = показати всі статуси.",
|
"card_filter_status_help": "Порожньо = показати всі статуси.",
|
||||||
"card_filter_objects": "Фільтрувати за об'єктами",
|
"card_filter_objects": "Фільтрувати за об'єктами",
|
||||||
"card_filter_objects_help": "Порожньо = показати всі об'єкти.",
|
"card_filter_objects_help": "Порожньо = показати всі об'єкти.",
|
||||||
|
"card_filter_areas": "Фільтрувати за зонами",
|
||||||
|
"card_filter_areas_help": "Порожньо = показати всі зони.",
|
||||||
"card_filter_entities": "Фільтрувати за сутностями (entity_ids)",
|
"card_filter_entities": "Фільтрувати за сутностями (entity_ids)",
|
||||||
"card_filter_entities_help": "Виберіть сутності sensor / binary_sensor з цієї інтеграції. Порожньо = всі.",
|
"card_filter_entities_help": "Виберіть сутності sensor / binary_sensor з цієї інтеграції. Порожньо = всі.",
|
||||||
"card_loading_objects": "Завантаження об'єктів…",
|
"card_loading_objects": "Завантаження об'єктів…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Заголовок панелі",
|
"settings_panel_title": "Заголовок панелі",
|
||||||
"settings_notifications": "Сповіщення",
|
"settings_notifications": "Сповіщення",
|
||||||
"settings_notify_service": "Служба сповіщень",
|
"settings_notify_service": "Служба сповіщень",
|
||||||
|
"settings_install_assist_sentences": "Встановити фрази Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Копіює голосові фрази до вашої конфігурації, щоб класичний агент Assist їх розпізнавав. Файл, який ви редагували, ніколи не перезаписується.",
|
||||||
"test_notification": "Тестове сповіщення",
|
"test_notification": "Тестове сповіщення",
|
||||||
"send_test": "Надіслати тест",
|
"send_test": "Надіслати тест",
|
||||||
"testing": "Надсилання…",
|
"testing": "Надсилання…",
|
||||||
"test_notification_success": "Тестове сповіщення надіслано",
|
"test_notification_success": "Тестове сповіщення надіслано",
|
||||||
"test_notification_failed": "Не вдалося надіслати тестове сповіщення",
|
"test_notification_failed": "Не вдалося надіслати тестове сповіщення",
|
||||||
|
"notify_per_person": "Доставка за особами",
|
||||||
|
"notify_no_own_device": "Немає власного пристрою — використовується загальна служба",
|
||||||
"settings_notify_due_soon": "Сповіщати, коли термін наближається",
|
"settings_notify_due_soon": "Сповіщати, коли термін наближається",
|
||||||
"settings_notify_overdue": "Сповіщати про прострочення",
|
"settings_notify_overdue": "Сповіщати про прострочення",
|
||||||
"settings_notify_triggered": "Сповіщати про спрацювання",
|
"settings_notify_triggered": "Сповіщати про спрацювання",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "За користувачем",
|
"groupby_user": "За користувачем",
|
||||||
"filter_label": "Фільтр",
|
"filter_label": "Фільтр",
|
||||||
"user_label": "Користувач",
|
"user_label": "Користувач",
|
||||||
|
"photo_label": "Фото",
|
||||||
"sort_label": "Сортування",
|
"sort_label": "Сортування",
|
||||||
"group_by_label": "Групувати за",
|
"group_by_label": "Групувати за",
|
||||||
"state_value_help": "Використовуйте значення стану HA (зазвичай у нижньому регістрі, напр. \"on\"/\"off\"). Регістр нормалізується при збереженні.",
|
"state_value_help": "Використовуйте значення стану HA (зазвичай у нижньому регістрі, напр. \"on\"/\"off\"). Регістр нормалізується при збереженні.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Змінити запас",
|
"part_restock": "Змінити запас",
|
||||||
"restock_quantity_label": "Куплена кількість",
|
"restock_quantity_label": "Куплена кількість",
|
||||||
"consumes_parts_label": "Витрачає деталі",
|
"consumes_parts_label": "Витрачає деталі",
|
||||||
|
"shared_parts_other_objects": "Деталі інших об'єктів",
|
||||||
|
"shared_parts_help": "Кілька об'єктів можуть використовувати один запас. Виконання цього завдання списує деталі з об'єкта-власника.",
|
||||||
|
"shared_part_unknown": "Невідома деталь",
|
||||||
"parts_load_failed": "Не вдалося завантажити запчастини цього об'єкта — параметри витрати запчастин зараз недоступні.",
|
"parts_load_failed": "Не вдалося завантажити запчастини цього об'єкта — параметри витрати запчастин зараз недоступні.",
|
||||||
"settings_export_selection": "Обмежити вибраними об'єктами (необов'язково)",
|
"settings_export_selection": "Обмежити вибраними об'єктами (необов'язково)",
|
||||||
"settings_docs_archive": "Архів документів (з файлами)",
|
"settings_docs_archive": "Архів документів (з файлами)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "触发值",
|
"trigger_val": "触发值",
|
||||||
"complete_title": "完成: ",
|
"complete_title": "完成: ",
|
||||||
"checklist": "检查清单",
|
"checklist": "检查清单",
|
||||||
|
"require_on_completion": "完成时必填",
|
||||||
"checklist_steps_optional": "检查步骤 (可选)",
|
"checklist_steps_optional": "检查步骤 (可选)",
|
||||||
"checklist_placeholder": "清理过滤器\n更换密封圈\n测试压力",
|
"checklist_placeholder": "清理过滤器\n更换密封圈\n测试压力",
|
||||||
"checklist_help": "每行一个步骤。最多 100 项。",
|
"checklist_help": "每行一个步骤。最多 100 项。",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "留空则显示所有状态。",
|
"card_filter_status_help": "留空则显示所有状态。",
|
||||||
"card_filter_objects": "按维护项过滤",
|
"card_filter_objects": "按维护项过滤",
|
||||||
"card_filter_objects_help": "留空则显示所有维护项。",
|
"card_filter_objects_help": "留空则显示所有维护项。",
|
||||||
|
"card_filter_areas": "按区域过滤",
|
||||||
|
"card_filter_areas_help": "留空则显示所有区域。",
|
||||||
"card_filter_entities": "按实体过滤 (entity_ids)",
|
"card_filter_entities": "按实体过滤 (entity_ids)",
|
||||||
"card_filter_entities_help": "选择该集成的传感器或二进制传感器实体。留空则显示全部。",
|
"card_filter_entities_help": "选择该集成的传感器或二进制传感器实体。留空则显示全部。",
|
||||||
"card_loading_objects": "正在加载维护项…",
|
"card_loading_objects": "正在加载维护项…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "侧边栏面板标题",
|
"settings_panel_title": "侧边栏面板标题",
|
||||||
"settings_notifications": "通知",
|
"settings_notifications": "通知",
|
||||||
"settings_notify_service": "通知服务",
|
"settings_notify_service": "通知服务",
|
||||||
|
"settings_install_assist_sentences": "安装 Assist 语句",
|
||||||
|
"settings_install_assist_sentences_hint": "将语音语句复制到你的配置中,让传统 Assist 代理能够识别它们。你自己修改过的文件永远不会被覆盖。",
|
||||||
"test_notification": "测试通知",
|
"test_notification": "测试通知",
|
||||||
"send_test": "发送测试",
|
"send_test": "发送测试",
|
||||||
"testing": "正在发送…",
|
"testing": "正在发送…",
|
||||||
"test_notification_success": "测试通知已发送",
|
"test_notification_success": "测试通知已发送",
|
||||||
"test_notification_failed": "测试通知发送失败",
|
"test_notification_failed": "测试通知发送失败",
|
||||||
|
"notify_per_person": "按成员分别投递",
|
||||||
|
"notify_no_own_device": "无个人设备 — 使用家庭通知服务",
|
||||||
"settings_notify_due_soon": "到期前通知提醒",
|
"settings_notify_due_soon": "到期前通知提醒",
|
||||||
"settings_notify_overdue": "超期后通知提醒",
|
"settings_notify_overdue": "超期后通知提醒",
|
||||||
"settings_notify_triggered": "触发时通知提醒",
|
"settings_notify_triggered": "触发时通知提醒",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "按负责人",
|
"groupby_user": "按负责人",
|
||||||
"filter_label": "过滤器",
|
"filter_label": "过滤器",
|
||||||
"user_label": "用户",
|
"user_label": "用户",
|
||||||
|
"photo_label": "照片",
|
||||||
"sort_label": "排序",
|
"sort_label": "排序",
|
||||||
"group_by_label": "分组依据",
|
"group_by_label": "分组依据",
|
||||||
"state_value_help": "使用 HA 状态值(通常为小写,例如 \"on\"/\"off\")。保存时大小写会自动规范化。",
|
"state_value_help": "使用 HA 状态值(通常为小写,例如 \"on\"/\"off\")。保存时大小写会自动规范化。",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "调整库存",
|
"part_restock": "调整库存",
|
||||||
"restock_quantity_label": "购买数量",
|
"restock_quantity_label": "购买数量",
|
||||||
"consumes_parts_label": "消耗配件",
|
"consumes_parts_label": "消耗配件",
|
||||||
|
"shared_parts_other_objects": "其他设备的配件",
|
||||||
|
"shared_parts_help": "多个设备可以共用同一批库存。完成此任务将从所属设备的库存中扣减。",
|
||||||
|
"shared_part_unknown": "未知配件",
|
||||||
"parts_load_failed": "无法加载此对象的配件 — 配件消耗选项暂时不可用。",
|
"parts_load_failed": "无法加载此对象的配件 — 配件消耗选项暂时不可用。",
|
||||||
"settings_export_selection": "仅限所选对象(可选)",
|
"settings_export_selection": "仅限所选对象(可选)",
|
||||||
"settings_docs_archive": "文档存档(含文件)",
|
"settings_docs_archive": "文档存档(含文件)",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
type CalendarEvent,
|
type CalendarEvent,
|
||||||
} from "./helpers/calendar-bucket";
|
} from "./helpers/calendar-bucket";
|
||||||
import { calendarStyles } from "./calendar-styles";
|
import { calendarStyles } from "./calendar-styles";
|
||||||
import { sharedStyles, DEFAULT_CURRENCY_SYMBOL, t, ensureLocale, isLocaleLoaded, setDateTimePrefs } from "./styles";
|
import { sharedStyles, DEFAULT_CURRENCY_SYMBOL, t, ensureLocale, isLocaleLoaded, setDateTimePrefs, formatDueDays } from "./styles";
|
||||||
import type {
|
import type {
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
MaintenanceObjectResponse,
|
MaintenanceObjectResponse,
|
||||||
@@ -267,7 +267,7 @@ export class MaintenanceCalendarCard extends LitElement {
|
|||||||
const statusClass = `cal-status-${ev.status}`;
|
const statusClass = `cal-status-${ev.status}`;
|
||||||
const projClass = ev.projected ? "cal-event-projected" : "";
|
const projClass = ev.projected ? "cal-event-projected" : "";
|
||||||
const overdueLabel = ev.status === "overdue" && ev.days_until_due != null
|
const overdueLabel = ev.status === "overdue" && ev.days_until_due != null
|
||||||
? ` (${Math.abs(ev.days_until_due)}d ${t("overdue", L).toLowerCase()})`
|
? ` (${formatDueDays(ev.days_until_due, L)})`
|
||||||
: "";
|
: "";
|
||||||
const recurEvery = ev.projected && ev.interval_days
|
const recurEvery = ev.projected && ev.interval_days
|
||||||
? html`<span class="cal-event-recur">${
|
? html`<span class="cal-event-recur">${
|
||||||
|
|||||||
@@ -81,6 +81,18 @@ export class MaintenanceSupporterCardEditor extends LitElement {
|
|||||||
this._valueChanged("filter_objects", [...current]);
|
this._valueChanged("filter_objects", [...current]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _toggleLabel(label: string, on: boolean): void {
|
||||||
|
const current = new Set(this._config.filter_labels || []);
|
||||||
|
if (on) current.add(label); else current.delete(label);
|
||||||
|
this._valueChanged("filter_labels", [...current]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleArea(areaId: string, on: boolean): void {
|
||||||
|
const current = new Set(this._config.filter_areas || []);
|
||||||
|
if (on) current.add(areaId); else current.delete(areaId);
|
||||||
|
this._valueChanged("filter_areas", [...current]);
|
||||||
|
}
|
||||||
|
|
||||||
private _onEntitiesChanged = (e: CustomEvent<{ value: string[] }>): void => {
|
private _onEntitiesChanged = (e: CustomEvent<{ value: string[] }>): void => {
|
||||||
this._valueChanged("entity_ids", e.detail.value || []);
|
this._valueChanged("entity_ids", e.detail.value || []);
|
||||||
};
|
};
|
||||||
@@ -92,6 +104,30 @@ export class MaintenanceSupporterCardEditor extends LitElement {
|
|||||||
const objectNames = [...this._objects]
|
const objectNames = [...this._objects]
|
||||||
.map((o) => o.object.name)
|
.map((o) => o.object.name)
|
||||||
.sort((a, b) => a.localeCompare(b));
|
.sort((a, b) => a.localeCompare(b));
|
||||||
|
// Areas (C8): offer exactly the areas that actually hold an object — an
|
||||||
|
// area with nothing in it could only ever empty the card. Names resolve
|
||||||
|
// through hass.areas; an area HA no longer knows falls back to its raw id
|
||||||
|
// so an existing config stays visible (and un-checkable) instead of
|
||||||
|
// vanishing silently.
|
||||||
|
const selectedAreas = new Set(this._config.filter_areas || []);
|
||||||
|
const areaIds = [
|
||||||
|
...new Set(
|
||||||
|
this._objects
|
||||||
|
.map((o) => o.object.area_id)
|
||||||
|
.filter((a): a is string => !!a)
|
||||||
|
.concat([...selectedAreas]),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
const areaName = (id: string): string => this.hass?.areas?.[id]?.name || id;
|
||||||
|
const areas = areaIds
|
||||||
|
.map((id) => ({ id, name: areaName(id) }))
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
const selectedLabels = new Set(this._config.filter_labels || []);
|
||||||
|
// Labels are free-form per task, so the picker offers exactly the ones in
|
||||||
|
// use — an empty list simply hides the section.
|
||||||
|
const labelNames = [
|
||||||
|
...new Set(this._objects.flatMap((o) => o.tasks.flatMap((tk) => tk.labels || []))),
|
||||||
|
].sort((a, b) => a.localeCompare(b));
|
||||||
// Build the list of OUR sensor + binary_sensor entity_ids so the
|
// Build the list of OUR sensor + binary_sensor entity_ids so the
|
||||||
// ha-entities-picker only shows maintenance_supporter entities, not
|
// ha-entities-picker only shows maintenance_supporter entities, not
|
||||||
// every sensor in HA.
|
// every sensor in HA.
|
||||||
@@ -152,6 +188,38 @@ export class MaintenanceSupporterCardEditor extends LitElement {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Area filter (C8): selects whole objects by the room they sit in.
|
||||||
|
Hidden while no object has an area — the section would be an
|
||||||
|
empty box otherwise. -->
|
||||||
|
${areas.length ? html`
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">${t("card_filter_areas", L)}</div>
|
||||||
|
<div class="object-list">
|
||||||
|
${areas.map((a) => html`
|
||||||
|
<label class="object-row">
|
||||||
|
<input type="checkbox"
|
||||||
|
.checked=${selectedAreas.has(a.id)}
|
||||||
|
@change=${(e: Event) => this._toggleArea(a.id, (e.target as HTMLInputElement).checked)} />
|
||||||
|
<span>${a.name}</span>
|
||||||
|
</label>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
<div class="field-help">${t("card_filter_areas_help", L)}</div>
|
||||||
|
</div>` : nothing}
|
||||||
|
${labelNames.length ? html`
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">${t("labels", L)}</div>
|
||||||
|
<div class="object-list">
|
||||||
|
${labelNames.map((name) => html`
|
||||||
|
<label class="object-row">
|
||||||
|
<input type="checkbox"
|
||||||
|
.checked=${selectedLabels.has(name)}
|
||||||
|
@change=${(e: Event) => this._toggleLabel(name, (e.target as HTMLInputElement).checked)} />
|
||||||
|
<span>${name}</span>
|
||||||
|
</label>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
</div>` : nothing}
|
||||||
|
|
||||||
<!-- Entity-id filter (HA-native pattern). Limited to our integration's
|
<!-- Entity-id filter (HA-native pattern). Limited to our integration's
|
||||||
sensor + binary_sensor entities via includeEntities so the picker
|
sensor + binary_sensor entities via includeEntities so the picker
|
||||||
@@ -219,6 +287,14 @@ export class MaintenanceSupporterCardEditor extends LitElement {
|
|||||||
></ha-switch>
|
></ha-switch>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
|
|
||||||
|
<ha-formfield label="${t("documents", L)}">
|
||||||
|
<ha-switch
|
||||||
|
.checked=${this._config.show_documents !== false}
|
||||||
|
@change=${(e: Event) =>
|
||||||
|
this._valueChanged("show_documents", (e.target as HTMLInputElement).checked)}
|
||||||
|
></ha-switch>
|
||||||
|
</ha-formfield>
|
||||||
|
|
||||||
<ha-formfield label="${t("card_compact", L)}">
|
<ha-formfield label="${t("card_compact", L)}">
|
||||||
<ha-switch
|
<ha-switch
|
||||||
.checked=${this._config.compact || false}
|
.checked=${this._config.compact || false}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { LitElement, html, css, nothing } from "lit";
|
import { LitElement, html, css, nothing } from "lit";
|
||||||
import { property, state } from "lit/decorators.js";
|
import { property, state } from "lit/decorators.js";
|
||||||
import { sharedStyles, STATUS_COLORS, t, ensureLocale, isLocaleLoaded, setDateTimePrefs } from "./styles";
|
import { sharedStyles, STATUS_COLORS, t, ensureLocale, isLocaleLoaded, setDateTimePrefs, formatDueDays } from "./styles";
|
||||||
import type {
|
import type {
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
MaintenanceObjectResponse,
|
MaintenanceObjectResponse,
|
||||||
@@ -13,6 +13,7 @@ import type {
|
|||||||
SavedViewFilters,
|
SavedViewFilters,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { UserService } from "./user-service";
|
import { UserService } from "./user-service";
|
||||||
|
import { partsForCompletion } from "./helpers/shared-parts";
|
||||||
import "./maintenance-card-editor";
|
import "./maintenance-card-editor";
|
||||||
import "./components/complete-dialog";
|
import "./components/complete-dialog";
|
||||||
import {
|
import {
|
||||||
@@ -21,6 +22,13 @@ import {
|
|||||||
openTaskQuickActions,
|
openTaskQuickActions,
|
||||||
} from "./dialog-mount";
|
} from "./dialog-mount";
|
||||||
|
|
||||||
|
interface CardDoc {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
kind: string;
|
||||||
|
url?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
interface FlatTask {
|
interface FlatTask {
|
||||||
entry_id: string;
|
entry_id: string;
|
||||||
object_name: string;
|
object_name: string;
|
||||||
@@ -39,6 +47,9 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
@state() private _userNames: Record<string, string> = {};
|
@state() private _userNames: Record<string, string> = {};
|
||||||
private _userService: UserService | null = null;
|
private _userService: UserService | null = null;
|
||||||
private _userNamesLoaded = false;
|
private _userNamesLoaded = false;
|
||||||
|
/** entry_id → (task_id → documents) for the row chips. */
|
||||||
|
@state() private _taskDocs: Record<string, Record<string, CardDoc[]>> = {};
|
||||||
|
private _docsLoadedFor = new Set<string>();
|
||||||
|
|
||||||
private get _lang(): string {
|
private get _lang(): string {
|
||||||
return this.hass?.language || "en";
|
return this.hass?.language || "en";
|
||||||
@@ -114,6 +125,15 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
) {
|
) {
|
||||||
this._loadUserNames();
|
this._loadUserNames();
|
||||||
}
|
}
|
||||||
|
// Documents: same shape of guard — fetch per object, once, and only for
|
||||||
|
// objects that actually have a document attached to one of their tasks.
|
||||||
|
if (this.hass && this._config.show_documents !== false) {
|
||||||
|
for (const obj of this._objects) {
|
||||||
|
if (this._docsLoadedFor.has(obj.entry_id)) continue;
|
||||||
|
if (!obj.tasks.some((tk) => (tk.document_count ?? 0) > 0)) continue;
|
||||||
|
this._loadDocuments(obj.entry_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (changedProps.has("hass") && this.hass) {
|
if (changedProps.has("hass") && this.hass) {
|
||||||
if (!this._dataLoaded) {
|
if (!this._dataLoaded) {
|
||||||
this._dataLoaded = true;
|
this._dataLoaded = true;
|
||||||
@@ -146,12 +166,6 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
await this._loadViewFilters();
|
await this._loadViewFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolve display names for the assignee badge (best-effort).
|
|
||||||
*
|
|
||||||
* `users/list` is a READ-tier command, so the household members this card
|
|
||||||
* is built for can call it without admin rights. A failure (or a task
|
|
||||||
* whose user was deleted) leaves the name unresolved and the badge simply
|
|
||||||
* does not render — never a raw user id. */
|
|
||||||
/** Display name of the task's responsible user, or "" when the badge must
|
/** Display name of the task's responsible user, or "" when the badge must
|
||||||
* stay hidden (feature off, nobody assigned, or the name not resolved).
|
* stay hidden (feature off, nobody assigned, or the name not resolved).
|
||||||
* With a rotation this is whoever is up next — the pointer the engine
|
* With a rotation this is whoever is up next — the pointer the engine
|
||||||
@@ -163,6 +177,12 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
return this._userNames[id] || "";
|
return this._userNames[id] || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolve display names for the assignee badge (best-effort).
|
||||||
|
*
|
||||||
|
* `users/list` is a READ-tier command, so the household members this card
|
||||||
|
* is built for can call it without admin rights. A failure (or a task
|
||||||
|
* whose user was deleted) leaves the name unresolved and the badge simply
|
||||||
|
* does not render — never a raw user id. */
|
||||||
private async _loadUserNames(): Promise<void> {
|
private async _loadUserNames(): Promise<void> {
|
||||||
this._userNamesLoaded = true;
|
this._userNamesLoaded = true;
|
||||||
if (!this._userService) this._userService = new UserService(this.hass);
|
if (!this._userService) this._userService = new UserService(this.hass);
|
||||||
@@ -175,6 +195,62 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Fetch one object's documents and index them by task.
|
||||||
|
*
|
||||||
|
* `documents/list` is READ tier, like `users/list` — the household members
|
||||||
|
* this card is for may call it. A failure leaves the row without chips
|
||||||
|
* rather than breaking the card. */
|
||||||
|
private async _loadDocuments(entryId: string): Promise<void> {
|
||||||
|
this._docsLoadedFor.add(entryId);
|
||||||
|
try {
|
||||||
|
const res = (await this.hass.connection.sendMessagePromise({
|
||||||
|
type: "maintenance_supporter/documents/list",
|
||||||
|
entry_id: entryId,
|
||||||
|
})) as { documents: Array<CardDoc & { task_ids?: string[] }> };
|
||||||
|
const byTask: Record<string, CardDoc[]> = {};
|
||||||
|
for (const doc of res.documents || []) {
|
||||||
|
for (const taskId of doc.task_ids || []) {
|
||||||
|
(byTask[taskId] ||= []).push({ id: doc.id, title: doc.title, kind: doc.kind, url: doc.url });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._taskDocs = { ...this._taskDocs, [entryId]: byTask };
|
||||||
|
} catch {
|
||||||
|
// no chips for this object; the card is unaffected otherwise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Chips to render on a row: linked documents plus the task's own manual
|
||||||
|
* link, which is the same "the manual is one tap away" affordance. */
|
||||||
|
private _docsFor(entryId: string, task: MaintenanceTask): CardDoc[] {
|
||||||
|
if (this._config.show_documents === false) return [];
|
||||||
|
const linked = this._taskDocs[entryId]?.[task.id] || [];
|
||||||
|
const out = [...linked];
|
||||||
|
if (task.documentation_url) {
|
||||||
|
out.push({ id: `url:${task.id}`, title: t("documentation_label", this._lang), kind: "weblink", url: task.documentation_url });
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Open a chip: a web link directly, a stored file through a signed path
|
||||||
|
* (the same route the panel uses, so it works in the Companion app). */
|
||||||
|
private async _openDoc(doc: CardDoc): Promise<void> {
|
||||||
|
if (doc.kind === "weblink" && doc.url) {
|
||||||
|
window.open(doc.url, "_blank", "noopener");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const win = window.open("about:blank", "_blank");
|
||||||
|
try {
|
||||||
|
const signed = await this.hass.connection.sendMessagePromise<{ path: string }>({
|
||||||
|
type: "auth/sign_path",
|
||||||
|
path: `/api/maintenance_supporter/document/${doc.id}`,
|
||||||
|
expires: 300,
|
||||||
|
});
|
||||||
|
if (win) win.location.href = new URL(signed.path, window.location.origin).href;
|
||||||
|
} catch {
|
||||||
|
if (win) win.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Resolve the configured saved view's filters (best-effort). A missing or
|
/** Resolve the configured saved view's filters (best-effort). A missing or
|
||||||
* deleted view degrades to "no view filter" — same fallback semantics as
|
* deleted view degrades to "no view filter" — same fallback semantics as
|
||||||
* the backend's notification routing, never an inexplicably empty card. */
|
* the backend's notification routing, never an inexplicably empty card. */
|
||||||
@@ -222,6 +298,8 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
entity_ids,
|
entity_ids,
|
||||||
filter_due_min_days,
|
filter_due_min_days,
|
||||||
filter_due_max_days,
|
filter_due_max_days,
|
||||||
|
filter_labels,
|
||||||
|
filter_areas,
|
||||||
max_items,
|
max_items,
|
||||||
} = this._config;
|
} = this._config;
|
||||||
const entityFilter = entity_ids?.length ? new Set(entity_ids) : null;
|
const entityFilter = entity_ids?.length ? new Set(entity_ids) : null;
|
||||||
@@ -238,6 +316,13 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
|
|
||||||
for (const obj of this._objects) {
|
for (const obj of this._objects) {
|
||||||
if (filter_objects?.length && !filter_objects.includes(obj.object.name)) continue;
|
if (filter_objects?.length && !filter_objects.includes(obj.object.name)) continue;
|
||||||
|
// Areas (C8): object-level, so it selects whole objects like
|
||||||
|
// filter_objects does — "the tasks for this room". An object with no
|
||||||
|
// area_id can never satisfy a non-empty list.
|
||||||
|
if (filter_areas?.length) {
|
||||||
|
const areaId = obj.object.area_id;
|
||||||
|
if (!areaId || !filter_areas.includes(areaId)) continue;
|
||||||
|
}
|
||||||
for (const task of obj.tasks) {
|
for (const task of obj.tasks) {
|
||||||
// Completed one-time tasks ("done") are hidden from the active list.
|
// Completed one-time tasks ("done") are hidden from the active list.
|
||||||
if (task.is_done) continue;
|
if (task.is_done) continue;
|
||||||
@@ -245,6 +330,8 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
// never shown on the Lovelace card.
|
// never shown on the Lovelace card.
|
||||||
if (task.archived || obj.object.archived) continue;
|
if (task.archived || obj.object.archived) continue;
|
||||||
if (filter_status?.length && !filter_status.includes(task.status)) continue;
|
if (filter_status?.length && !filter_status.includes(task.status)) continue;
|
||||||
|
// Labels: a task passes when it carries at least one configured label.
|
||||||
|
if (filter_labels?.length && !(task.labels || []).some((lb) => filter_labels.includes(lb))) continue;
|
||||||
// entity_ids: HA-native filter — match the task's sensor or
|
// entity_ids: HA-native filter — match the task's sensor or
|
||||||
// binary_sensor entity_id. Both fields come pre-resolved from the
|
// binary_sensor entity_id. Both fields come pre-resolved from the
|
||||||
// backend WS response (see _build_task_summary in websocket/__init__.py).
|
// backend WS response (see _build_task_summary in websocket/__init__.py).
|
||||||
@@ -384,13 +471,26 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
</div>`
|
</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
|
${this._docsFor(entry_id, task).length
|
||||||
|
? html`<div class="doc-chips">
|
||||||
|
${this._docsFor(entry_id, task).map((doc) => html`
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="doc-chip"
|
||||||
|
title="${doc.title}"
|
||||||
|
@click=${(e: Event) => { e.stopPropagation(); void this._openDoc(doc); }}
|
||||||
|
>
|
||||||
|
<ha-icon icon=${doc.kind === "weblink" ? "mdi:link-variant" : "mdi:file-document-outline"}></ha-icon>
|
||||||
|
<span>${doc.title}</span>
|
||||||
|
</button>
|
||||||
|
`)}
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
<div class="task-due">
|
<div class="task-due">
|
||||||
${task.days_until_due !== null && task.days_until_due !== undefined
|
${task.days_until_due !== null && task.days_until_due !== undefined
|
||||||
? task.days_until_due < 0
|
? task.days_until_due < 0
|
||||||
? html`<span class="overdue-text">${Math.abs(task.days_until_due)}${L.startsWith("de") ? "T" : "d"}</span>`
|
? html`<span class="overdue-text">${formatDueDays(task.days_until_due, L)}</span>`
|
||||||
: task.days_until_due === 0
|
: formatDueDays(task.days_until_due, L)
|
||||||
? t("today", L)
|
|
||||||
: `${task.days_until_due}${L.startsWith("de") ? "T" : "d"}`
|
|
||||||
: task.trigger_active
|
: task.trigger_active
|
||||||
? "⚡"
|
? "⚡"
|
||||||
: "—"}
|
: "—"}
|
||||||
@@ -411,13 +511,17 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
dlg.adaptiveEnabled = !!task.adaptive_config?.enabled;
|
dlg.adaptiveEnabled = !!task.adaptive_config?.enabled;
|
||||||
dlg.taskType = task.type || "";
|
dlg.taskType = task.type || "";
|
||||||
dlg.readingUnit = (task as any).reading_unit || "";
|
dlg.readingUnit = (task as any).reading_unit || "";
|
||||||
|
dlg.requiredFields = task.required_completion_fields || [];
|
||||||
dlg.lang = L;
|
dlg.lang = L;
|
||||||
// #99: editable per-completion parts selection
|
// #99: editable per-completion parts selection
|
||||||
// (skip on buy tasks — those restock instead).
|
// (skip on buy tasks — those restock instead).
|
||||||
const obj = this._objects.find((o) => o.entry_id === entry_id);
|
// #111: the list also carries the shared pools
|
||||||
|
// this task draws on, each named after its
|
||||||
|
// owner — resolving against the object's own
|
||||||
|
// parts alone left a foreign link invisible.
|
||||||
const isBuy = !!(task as any).part_ref;
|
const isBuy = !!(task as any).part_ref;
|
||||||
dlg.parts = isBuy ? [] : (obj?.parts || []);
|
dlg.parts = isBuy ? [] : partsForCompletion(task, entry_id, this._objects, L);
|
||||||
dlg.consumesParts = isBuy ? [] : ((task as any).consumes_parts || []);
|
dlg.consumesParts = isBuy ? [] : (task.consumes_parts || []);
|
||||||
dlg.open();
|
dlg.open();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -534,7 +638,37 @@ export class MaintenanceSupporterCard extends LitElement {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-due { font-size: 13px; color: var(--secondary-text-color); min-width: 40px; text-align: right; }
|
.doc-chips {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
margin-right: 6px;
|
||||||
|
max-width: 45%;
|
||||||
|
}
|
||||||
|
.doc-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3px;
|
||||||
|
max-width: 14ch;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border: 1px solid var(--divider-color, #e0e0e0);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: none;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
font: inherit;
|
||||||
|
font-size: 11px;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.doc-chip:hover { color: var(--primary-color); border-color: var(--primary-color); }
|
||||||
|
.doc-chip ha-icon { --mdc-icon-size: 12px; width: 12px; height: 12px; }
|
||||||
|
/* nowrap: the due label is localized via formatDueDays ("5 d overdue",
|
||||||
|
"5 T überfällig") — without it a narrow phone card wraps that onto a
|
||||||
|
second line and the row grows taller. The name column ellipsizes
|
||||||
|
instead, which it already does by design. */
|
||||||
|
.task-due { font-size: 13px; color: var(--secondary-text-color); min-width: 40px; text-align: right; white-space: nowrap; }
|
||||||
.overdue-text { color: var(--error-color); font-weight: 500; }
|
.overdue-text { color: var(--error-color); font-weight: 500; }
|
||||||
|
|
||||||
.complete-btn {
|
.complete-btn {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { warrantyStatus } from "./helpers/warranty";
|
|||||||
import { OBJECT_COLUMNS, DEFAULT_OBJECTS_TABLE_COLUMNS, sanitizeColumns } from "./helpers/object-columns";
|
import { OBJECT_COLUMNS, DEFAULT_OBJECTS_TABLE_COLUMNS, sanitizeColumns } from "./helpers/object-columns";
|
||||||
import { downloadTextFile } from "./helpers/download";
|
import { downloadTextFile } from "./helpers/download";
|
||||||
import { buildTaskWorksheetHtml, type WorksheetExcerpt, type WorksheetLabels } from "./helpers/worksheet";
|
import { buildTaskWorksheetHtml, type WorksheetExcerpt, type WorksheetLabels } from "./helpers/worksheet";
|
||||||
|
import { describePartLink, partsForCompletion } from "./helpers/shared-parts";
|
||||||
import { describeWsError } from "./ws-errors";
|
import { describeWsError } from "./ws-errors";
|
||||||
import { panelStyles } from "./panel-styles";
|
import { panelStyles } from "./panel-styles";
|
||||||
import type {
|
import type {
|
||||||
@@ -1759,17 +1760,13 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
statusLabel: (st: string) => t(st, L),
|
statusLabel: (st: string) => t(st, L),
|
||||||
parts: t("consumes_parts_label", L),
|
parts: t("consumes_parts_label", L),
|
||||||
};
|
};
|
||||||
// Required parts as checkable lines: qty × name (stock unit) — location.
|
// Required parts as checkable lines: qty × name (owner) (stock unit) —
|
||||||
const wsParts = obj.parts || [];
|
// location. A pool owned by another object (#111) names that object, and
|
||||||
const partsLines = (task.consumes_parts || [])
|
// a link that resolves to nothing prints "Unknown part" rather than the
|
||||||
.map((link) => {
|
// blank line the old own-parts-only lookup produced.
|
||||||
const pt = wsParts.find((x) => x.id === link.part_id);
|
const partsLines = (task.consumes_parts || []).map((link) =>
|
||||||
if (!pt) return "";
|
describePartLink(link, obj.entry_id, this._objects, L),
|
||||||
const stock = pt.stock !== null && pt.stock !== undefined ? ` (${pt.stock}${pt.unit ? " " + pt.unit : ""})` : "";
|
);
|
||||||
const loc = pt.storage_location ? ` — ${pt.storage_location}` : "";
|
|
||||||
return `${link.quantity}× ${pt.name}${stock}${loc}`;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
const html = buildTaskWorksheetHtml(
|
const html = buildTaskWorksheetHtml(
|
||||||
task, obj.object.name, labels,
|
task, obj.object.name, labels,
|
||||||
(iso) => formatDate(iso, L),
|
(iso) => formatDate(iso, L),
|
||||||
@@ -1804,24 +1801,22 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
?.tasks.find((tsk) => tsk.id === taskId);
|
?.tasks.find((tsk) => tsk.id === taskId);
|
||||||
dlg.taskType = tk?.type || "";
|
dlg.taskType = tk?.type || "";
|
||||||
dlg.readingUnit = tk?.reading_unit || "";
|
dlg.readingUnit = tk?.reading_unit || "";
|
||||||
|
dlg.requiredFields = tk?.required_completion_fields || [];
|
||||||
// Spare parts: a buy task gets an editable restock-qty field; a consuming
|
// Spare parts: a buy task gets an editable restock-qty field; a consuming
|
||||||
// task shows what it will decrement (incl. the storage location).
|
// task shows what it will decrement (incl. the storage location).
|
||||||
const objParts = this._objects.find((o) => o.entry_id === entryId)?.parts || [];
|
const objParts = this._objects.find((o) => o.entry_id === entryId)?.parts || [];
|
||||||
const partById = new Map(objParts.map((pt) => [pt.id, pt]));
|
const refPart = tk?.part_ref ? objParts.find((pt) => pt.id === tk.part_ref!.part_id) : undefined;
|
||||||
const refPart = tk?.part_ref ? partById.get(tk.part_ref.part_id) : undefined;
|
|
||||||
dlg.restockDefault = tk?.part_ref ? (refPart?.restock_quantity ?? 1) : null;
|
dlg.restockDefault = tk?.part_ref ? (refPart?.restock_quantity ?? 1) : null;
|
||||||
dlg.consumesInfo = (tk?.consumes_parts || [])
|
// #111: a link may point at another object's pool — name that object, and
|
||||||
.map((link) => {
|
// never drop a line that fails to resolve (the old .filter(Boolean) hid it).
|
||||||
const pt = partById.get(link.part_id);
|
dlg.consumesInfo = (tk?.consumes_parts || []).map((link) =>
|
||||||
if (!pt) return "";
|
describePartLink(link, entryId, this._objects, this._lang),
|
||||||
const loc = pt.storage_location ? ` — ${pt.storage_location}` : "";
|
);
|
||||||
const stock = pt.stock !== null && pt.stock !== undefined ? ` (${pt.stock}${pt.unit ? " " + pt.unit : ""})` : "";
|
|
||||||
return `${link.quantity}× ${pt.name}${stock}${loc}`;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
// #99: editable per-completion parts selection (not on buy tasks — those
|
// #99: editable per-completion parts selection (not on buy tasks — those
|
||||||
// RESTOCK via the qty field instead of consuming).
|
// RESTOCK via the qty field instead of consuming). The list carries the
|
||||||
dlg.parts = tk?.part_ref ? [] : objParts;
|
// object's own parts plus the shared pools this task draws on, so a foreign
|
||||||
|
// link is visible and untickable rather than silently absent.
|
||||||
|
dlg.parts = tk?.part_ref ? [] : partsForCompletion(tk, entryId, this._objects, this._lang);
|
||||||
dlg.consumesParts = tk?.part_ref ? [] : (tk?.consumes_parts || []);
|
dlg.consumesParts = tk?.part_ref ? [] : (tk?.consumes_parts || []);
|
||||||
dlg.open();
|
dlg.open();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,6 +164,8 @@ export interface MaintenanceTask {
|
|||||||
labels?: string[];
|
labels?: string[];
|
||||||
assignee_pool?: string[];
|
assignee_pool?: string[];
|
||||||
rotation_strategy?: string | null;
|
rotation_strategy?: string | null;
|
||||||
|
/** Details this task demands on completion (v2.44): notes/cost/duration/photo/user. */
|
||||||
|
required_completion_fields?: string[];
|
||||||
earliest_completion_days?: number | null;
|
earliest_completion_days?: number | null;
|
||||||
// v1.3.0: completion-action + quick-complete (gated by completion_actions feature)
|
// v1.3.0: completion-action + quick-complete (gated by completion_actions feature)
|
||||||
on_complete_action?: {
|
on_complete_action?: {
|
||||||
@@ -236,11 +238,25 @@ export interface MaintenanceTask {
|
|||||||
sensor_entity_id?: string | null;
|
sensor_entity_id?: string | null;
|
||||||
binary_sensor_entity_id?: string | null;
|
binary_sensor_entity_id?: string | null;
|
||||||
/** Spare parts consumed by completing this task. */
|
/** Spare parts consumed by completing this task. */
|
||||||
consumes_parts?: Array<{ part_id: string; quantity: number }> | null;
|
consumes_parts?: TaskPartLink[] | null;
|
||||||
/** Present on an auto-created "buy" reminder: the owning part. */
|
/** Present on an auto-created "buy" reminder: the owning part. */
|
||||||
part_ref?: { part_id: string } | null;
|
part_ref?: { part_id: string } | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** One entry of a task's `consumes_parts`.
|
||||||
|
*
|
||||||
|
* `entry_id` ABSENT = the part belongs to the task's own object. That is what
|
||||||
|
* every link written before #111 looks like and what is still written for own
|
||||||
|
* parts — nothing emits an entry_id for them. PRESENT = the task draws on a
|
||||||
|
* stock pool owned by that other object (three vacuums, one box of dust bags),
|
||||||
|
* and completing the task decrements the other object's stock.
|
||||||
|
*/
|
||||||
|
export interface TaskPartLink {
|
||||||
|
part_id: string;
|
||||||
|
quantity: number;
|
||||||
|
entry_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** A spare part / consumable on an object (full definition + derived state). */
|
/** A spare part / consumable on an object (full definition + derived state). */
|
||||||
export interface MaintenancePart {
|
export interface MaintenancePart {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -328,6 +344,18 @@ export interface CardConfig {
|
|||||||
// Defaults to ON — with rotations the row is the only place a household
|
// Defaults to ON — with rotations the row is the only place a household
|
||||||
// sees who is up next. Rows without an assignee simply render nothing.
|
// sees who is up next. Rows without an assignee simply render nothing.
|
||||||
show_assignee?: boolean;
|
show_assignee?: boolean;
|
||||||
|
// Labels to limit the card to (v2.44). A task passes when it carries at
|
||||||
|
// least one of them — same OR semantics as filter_status / filter_objects.
|
||||||
|
filter_labels?: string[];
|
||||||
|
// HA area ids to limit the card to (C8). A task passes when its parent
|
||||||
|
// OBJECT sits in one of these areas — same OR semantics as filter_objects,
|
||||||
|
// and ANDed with every other filter. Objects without an area never match a
|
||||||
|
// non-empty list. Empty / unset = no area filtering.
|
||||||
|
filter_areas?: string[];
|
||||||
|
// Show the task's linked documents (and its documentation link) as chips
|
||||||
|
// on the row, so the manual is one tap away. Defaults to ON; rows without
|
||||||
|
// a document render nothing extra.
|
||||||
|
show_documents?: boolean;
|
||||||
// Saved-view scope (v2.26): apply a saved view's task-selecting filters
|
// Saved-view scope (v2.26): apply a saved view's task-selecting filters
|
||||||
// (status / user / label) ON TOP of the card's own filters. The view's
|
// (status / user / label) ON TOP of the card's own filters. The view's
|
||||||
// sort/group dimensions are panel display state and are not applied here.
|
// sort/group dimensions are panel display state and are not applied here.
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Hodnota spouštěče",
|
"trigger_val": "Hodnota spouštěče",
|
||||||
"complete_title": "Dokončit: ",
|
"complete_title": "Dokončit: ",
|
||||||
"checklist": "Kontrolní seznam",
|
"checklist": "Kontrolní seznam",
|
||||||
|
"require_on_completion": "Vyžadovat při dokončení",
|
||||||
"checklist_steps_optional": "Kroky kontrolního seznamu (volitelné)",
|
"checklist_steps_optional": "Kroky kontrolního seznamu (volitelné)",
|
||||||
"checklist_placeholder": "Vyčistit filtr\nVyměnit těsnění\nOtestovat tlak",
|
"checklist_placeholder": "Vyčistit filtr\nVyměnit těsnění\nOtestovat tlak",
|
||||||
"checklist_help": "Jeden krok na řádek. Max 100 položek.",
|
"checklist_help": "Jeden krok na řádek. Max 100 položek.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Prázdné = zobrazit všechny stavy.",
|
"card_filter_status_help": "Prázdné = zobrazit všechny stavy.",
|
||||||
"card_filter_objects": "Filtrovat podle objektů",
|
"card_filter_objects": "Filtrovat podle objektů",
|
||||||
"card_filter_objects_help": "Prázdné = zobrazit všechny objekty.",
|
"card_filter_objects_help": "Prázdné = zobrazit všechny objekty.",
|
||||||
|
"card_filter_areas": "Filtrovat podle oblastí",
|
||||||
|
"card_filter_areas_help": "Prázdné = zobrazit všechny oblasti.",
|
||||||
"card_filter_entities": "Filtrovat podle entit (entity_ids)",
|
"card_filter_entities": "Filtrovat podle entit (entity_ids)",
|
||||||
"card_filter_entities_help": "Vyberte entity sensor / binary_sensor z této integrace. Prázdné = všechny.",
|
"card_filter_entities_help": "Vyberte entity sensor / binary_sensor z této integrace. Prázdné = všechny.",
|
||||||
"card_loading_objects": "Načítání objektů…",
|
"card_loading_objects": "Načítání objektů…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Název panelu",
|
"settings_panel_title": "Název panelu",
|
||||||
"settings_notifications": "Oznámení",
|
"settings_notifications": "Oznámení",
|
||||||
"settings_notify_service": "Služba oznámení",
|
"settings_notify_service": "Služba oznámení",
|
||||||
|
"settings_install_assist_sentences": "Nainstalovat věty pro Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Zkopíruje hlasové věty do vaší konfigurace, aby je klasický agent Assist rozpoznal. Soubor, který jste upravili, nebude nikdy přepsán.",
|
||||||
"test_notification": "Testovací oznámení",
|
"test_notification": "Testovací oznámení",
|
||||||
"send_test": "Odeslat test",
|
"send_test": "Odeslat test",
|
||||||
"testing": "Odesílání…",
|
"testing": "Odesílání…",
|
||||||
"test_notification_success": "Testovací oznámení odesláno",
|
"test_notification_success": "Testovací oznámení odesláno",
|
||||||
"test_notification_failed": "Testovací oznámení se nezdařilo",
|
"test_notification_failed": "Testovací oznámení se nezdařilo",
|
||||||
|
"notify_per_person": "Doručování podle osoby",
|
||||||
|
"notify_no_own_device": "Žádné vlastní zařízení — použije domácí službu",
|
||||||
"settings_notify_due_soon": "Oznámit když brzy",
|
"settings_notify_due_soon": "Oznámit když brzy",
|
||||||
"settings_notify_overdue": "Oznámit když po termínu",
|
"settings_notify_overdue": "Oznámit když po termínu",
|
||||||
"settings_notify_triggered": "Oznámit když spuštěno",
|
"settings_notify_triggered": "Oznámit když spuštěno",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Podle uživatele",
|
"groupby_user": "Podle uživatele",
|
||||||
"filter_label": "Filtr",
|
"filter_label": "Filtr",
|
||||||
"user_label": "Uživatel",
|
"user_label": "Uživatel",
|
||||||
|
"photo_label": "Fotografie",
|
||||||
"sort_label": "Řazení",
|
"sort_label": "Řazení",
|
||||||
"group_by_label": "Seskupit podle",
|
"group_by_label": "Seskupit podle",
|
||||||
"state_value_help": "Použijte hodnotu stavu HA (obvykle malými písmeny, např. \"on\"/\"off\"). Velikost písmen se při uložení normalizuje.",
|
"state_value_help": "Použijte hodnotu stavu HA (obvykle malými písmeny, např. \"on\"/\"off\"). Velikost písmen se při uložení normalizuje.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Upravit zásobu",
|
"part_restock": "Upravit zásobu",
|
||||||
"restock_quantity_label": "Zakoupené množství",
|
"restock_quantity_label": "Zakoupené množství",
|
||||||
"consumes_parts_label": "Spotřebovává díly",
|
"consumes_parts_label": "Spotřebovává díly",
|
||||||
|
"shared_parts_other_objects": "Díly z jiných objektů",
|
||||||
|
"shared_parts_help": "Několik objektů může sdílet jeden sklad. Dokončení tohoto úkolu odečte zásobu z vlastnícího objektu.",
|
||||||
|
"shared_part_unknown": "Neznámý díl",
|
||||||
"parts_load_failed": "Nepodařilo se načíst díly tohoto objektu — možnosti spotřeby dílů nyní nejsou k dispozici.",
|
"parts_load_failed": "Nepodařilo se načíst díly tohoto objektu — možnosti spotřeby dílů nyní nejsou k dispozici.",
|
||||||
"settings_export_selection": "Omezit na vybrané objekty (volitelné)",
|
"settings_export_selection": "Omezit na vybrané objekty (volitelné)",
|
||||||
"settings_docs_archive": "Archiv dokumentů (se soubory)",
|
"settings_docs_archive": "Archiv dokumentů (se soubory)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Udløserværdi",
|
"trigger_val": "Udløserværdi",
|
||||||
"complete_title": "Fuldfør: ",
|
"complete_title": "Fuldfør: ",
|
||||||
"checklist": "Tjekliste",
|
"checklist": "Tjekliste",
|
||||||
|
"require_on_completion": "Kræv ved fuldførelse",
|
||||||
"checklist_steps_optional": "Tjeklistetrin (valgfrit)",
|
"checklist_steps_optional": "Tjeklistetrin (valgfrit)",
|
||||||
"checklist_placeholder": "Rengør filter\nUdskift pakning\nTest tryk",
|
"checklist_placeholder": "Rengør filter\nUdskift pakning\nTest tryk",
|
||||||
"checklist_help": "Ét trin pr. linje. Maks. 100 elementer.",
|
"checklist_help": "Ét trin pr. linje. Maks. 100 elementer.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Tom = vis alle statusser.",
|
"card_filter_status_help": "Tom = vis alle statusser.",
|
||||||
"card_filter_objects": "Filtrer efter objekter",
|
"card_filter_objects": "Filtrer efter objekter",
|
||||||
"card_filter_objects_help": "Tom = vis alle objekter.",
|
"card_filter_objects_help": "Tom = vis alle objekter.",
|
||||||
|
"card_filter_areas": "Filtrer efter områder",
|
||||||
|
"card_filter_areas_help": "Tom = vis alle områder.",
|
||||||
"card_filter_entities": "Filtrer efter enheder (entity_ids)",
|
"card_filter_entities": "Filtrer efter enheder (entity_ids)",
|
||||||
"card_filter_entities_help": "Vælg sensor- / binary_sensor-enheder fra denne integration. Tom = alle.",
|
"card_filter_entities_help": "Vælg sensor- / binary_sensor-enheder fra denne integration. Tom = alle.",
|
||||||
"card_loading_objects": "Indlæser objekter…",
|
"card_loading_objects": "Indlæser objekter…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Sidepanelets titel",
|
"settings_panel_title": "Sidepanelets titel",
|
||||||
"settings_notifications": "Notifikationer",
|
"settings_notifications": "Notifikationer",
|
||||||
"settings_notify_service": "Notifikationstjeneste",
|
"settings_notify_service": "Notifikationstjeneste",
|
||||||
|
"settings_install_assist_sentences": "Installer Assist-sætninger",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopierer stemmesætningerne til din konfiguration, så den klassiske Assist-agent genkender dem. En fil, du selv har redigeret, overskrives aldrig.",
|
||||||
"test_notification": "Testnotifikation",
|
"test_notification": "Testnotifikation",
|
||||||
"send_test": "Send test",
|
"send_test": "Send test",
|
||||||
"testing": "Sender…",
|
"testing": "Sender…",
|
||||||
"test_notification_success": "Testnotifikation sendt",
|
"test_notification_success": "Testnotifikation sendt",
|
||||||
"test_notification_failed": "Testnotifikation mislykkedes",
|
"test_notification_failed": "Testnotifikation mislykkedes",
|
||||||
|
"notify_per_person": "Levering pr. person",
|
||||||
|
"notify_no_own_device": "Ingen egen enhed — bruger husstandens tjeneste",
|
||||||
"settings_notify_due_soon": "Notificer ved snart forfalden",
|
"settings_notify_due_soon": "Notificer ved snart forfalden",
|
||||||
"settings_notify_overdue": "Notificer ved forfalden",
|
"settings_notify_overdue": "Notificer ved forfalden",
|
||||||
"settings_notify_triggered": "Notificer ved udløst",
|
"settings_notify_triggered": "Notificer ved udløst",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Efter bruger",
|
"groupby_user": "Efter bruger",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Bruger",
|
"user_label": "Bruger",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sortering",
|
"sort_label": "Sortering",
|
||||||
"group_by_label": "Grupper efter",
|
"group_by_label": "Grupper efter",
|
||||||
"state_value_help": "Brug HA-tilstandsværdien (normalt med små bogstaver, f.eks. \"on\"/\"off\"). Store/små bogstaver normaliseres ved lagring.",
|
"state_value_help": "Brug HA-tilstandsværdien (normalt med små bogstaver, f.eks. \"on\"/\"off\"). Store/små bogstaver normaliseres ved lagring.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Justér lager",
|
"part_restock": "Justér lager",
|
||||||
"restock_quantity_label": "Købt mængde",
|
"restock_quantity_label": "Købt mængde",
|
||||||
"consumes_parts_label": "Forbruger dele",
|
"consumes_parts_label": "Forbruger dele",
|
||||||
|
"shared_parts_other_objects": "Dele fra andre objekter",
|
||||||
|
"shared_parts_help": "Flere objekter kan dele det samme lager. Når opgaven fuldføres, trækkes der fra det ejende objekt.",
|
||||||
|
"shared_part_unknown": "Ukendt del",
|
||||||
"parts_load_failed": "Kunne ikke indlæse objektets reservedele — forbrugsindstillingerne er ikke tilgængelige lige nu.",
|
"parts_load_failed": "Kunne ikke indlæse objektets reservedele — forbrugsindstillingerne er ikke tilgængelige lige nu.",
|
||||||
"settings_export_selection": "Begræns til valgte objekter (valgfrit)",
|
"settings_export_selection": "Begræns til valgte objekter (valgfrit)",
|
||||||
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Trigger-Wert",
|
"trigger_val": "Trigger-Wert",
|
||||||
"complete_title": "Erledigt: ",
|
"complete_title": "Erledigt: ",
|
||||||
"checklist": "Checkliste",
|
"checklist": "Checkliste",
|
||||||
|
"require_on_completion": "Beim Abschließen verlangen",
|
||||||
"checklist_steps_optional": "Checkliste-Schritte (optional)",
|
"checklist_steps_optional": "Checkliste-Schritte (optional)",
|
||||||
"checklist_placeholder": "Filter reinigen\nDichtung ersetzen\nDruck testen",
|
"checklist_placeholder": "Filter reinigen\nDichtung ersetzen\nDruck testen",
|
||||||
"checklist_help": "Ein Schritt pro Zeile. Max. 100 Einträge.",
|
"checklist_help": "Ein Schritt pro Zeile. Max. 100 Einträge.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Leer = alle Status zeigen.",
|
"card_filter_status_help": "Leer = alle Status zeigen.",
|
||||||
"card_filter_objects": "Nach Objekten filtern",
|
"card_filter_objects": "Nach Objekten filtern",
|
||||||
"card_filter_objects_help": "Leer = alle Objekte zeigen.",
|
"card_filter_objects_help": "Leer = alle Objekte zeigen.",
|
||||||
|
"card_filter_areas": "Nach Bereichen filtern",
|
||||||
|
"card_filter_areas_help": "Leer = alle Bereiche zeigen.",
|
||||||
"card_filter_entities": "Nach Entitäten filtern (entity_ids)",
|
"card_filter_entities": "Nach Entitäten filtern (entity_ids)",
|
||||||
"card_filter_entities_help": "Wähle Sensor-/Binary-Sensor-Entitäten dieser Integration. Leer = alle.",
|
"card_filter_entities_help": "Wähle Sensor-/Binary-Sensor-Entitäten dieser Integration. Leer = alle.",
|
||||||
"card_loading_objects": "Lade Objekte…",
|
"card_loading_objects": "Lade Objekte…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Panel-Titel",
|
"settings_panel_title": "Panel-Titel",
|
||||||
"settings_notifications": "Benachrichtigungen",
|
"settings_notifications": "Benachrichtigungen",
|
||||||
"settings_notify_service": "Benachrichtigungsdienst",
|
"settings_notify_service": "Benachrichtigungsdienst",
|
||||||
|
"settings_install_assist_sentences": "Assist-Sätze installieren",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopiert die Sprachbefehle in deine Konfiguration, damit der klassische Assist-Agent sie erkennt. Eine selbst bearbeitete Datei wird nie überschrieben.",
|
||||||
"test_notification": "Test-Benachrichtigung",
|
"test_notification": "Test-Benachrichtigung",
|
||||||
"send_test": "Test senden",
|
"send_test": "Test senden",
|
||||||
"testing": "Sende…",
|
"testing": "Sende…",
|
||||||
"test_notification_success": "Test-Benachrichtigung gesendet",
|
"test_notification_success": "Test-Benachrichtigung gesendet",
|
||||||
"test_notification_failed": "Test-Benachrichtigung fehlgeschlagen",
|
"test_notification_failed": "Test-Benachrichtigung fehlgeschlagen",
|
||||||
|
"notify_per_person": "Zustellung pro Person",
|
||||||
|
"notify_no_own_device": "Kein eigenes Gerät — nutzt den Haushaltsdienst",
|
||||||
"settings_notify_due_soon": "Bei baldiger Fälligkeit benachrichtigen",
|
"settings_notify_due_soon": "Bei baldiger Fälligkeit benachrichtigen",
|
||||||
"settings_notify_overdue": "Bei Überfälligkeit benachrichtigen",
|
"settings_notify_overdue": "Bei Überfälligkeit benachrichtigen",
|
||||||
"settings_notify_triggered": "Bei Auslösung benachrichtigen",
|
"settings_notify_triggered": "Bei Auslösung benachrichtigen",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Nach Verantwortlichem",
|
"groupby_user": "Nach Verantwortlichem",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Benutzer",
|
"user_label": "Benutzer",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sortierung",
|
"sort_label": "Sortierung",
|
||||||
"group_by_label": "Gruppieren nach",
|
"group_by_label": "Gruppieren nach",
|
||||||
"state_value_help": "Verwende den HA-Zustandswert (meist kleingeschrieben, z. B. \"on\"/\"off\"). Groß-/Kleinschreibung wird beim Speichern normalisiert.",
|
"state_value_help": "Verwende den HA-Zustandswert (meist kleingeschrieben, z. B. \"on\"/\"off\"). Groß-/Kleinschreibung wird beim Speichern normalisiert.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Bestand anpassen",
|
"part_restock": "Bestand anpassen",
|
||||||
"restock_quantity_label": "Gekaufte Menge",
|
"restock_quantity_label": "Gekaufte Menge",
|
||||||
"consumes_parts_label": "Verbraucht Teile",
|
"consumes_parts_label": "Verbraucht Teile",
|
||||||
|
"shared_parts_other_objects": "Teile anderer Objekte",
|
||||||
|
"shared_parts_help": "Mehrere Objekte können sich einen Bestand teilen. Beim Abschließen wird vom besitzenden Objekt abgebucht.",
|
||||||
|
"shared_part_unknown": "Unbekanntes Teil",
|
||||||
"parts_load_failed": "Die Teile dieses Objekts konnten nicht geladen werden — die Teileverbrauch-Optionen sind gerade nicht verfügbar.",
|
"parts_load_failed": "Die Teile dieses Objekts konnten nicht geladen werden — die Teileverbrauch-Optionen sind gerade nicht verfügbar.",
|
||||||
"settings_export_selection": "Auf ausgewählte Objekte beschränken (optional)",
|
"settings_export_selection": "Auf ausgewählte Objekte beschränken (optional)",
|
||||||
"settings_docs_archive": "Dokumentenarchiv (mit Dateien)",
|
"settings_docs_archive": "Dokumentenarchiv (mit Dateien)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Trigger value",
|
"trigger_val": "Trigger value",
|
||||||
"complete_title": "Complete: ",
|
"complete_title": "Complete: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Require on completion",
|
||||||
"checklist_steps_optional": "Checklist steps (optional)",
|
"checklist_steps_optional": "Checklist steps (optional)",
|
||||||
"checklist_placeholder": "Clean filter\nReplace seal\nTest pressure",
|
"checklist_placeholder": "Clean filter\nReplace seal\nTest pressure",
|
||||||
"checklist_help": "One step per line. Max 100 items.",
|
"checklist_help": "One step per line. Max 100 items.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Empty = show all statuses.",
|
"card_filter_status_help": "Empty = show all statuses.",
|
||||||
"card_filter_objects": "Filter by objects",
|
"card_filter_objects": "Filter by objects",
|
||||||
"card_filter_objects_help": "Empty = show all objects.",
|
"card_filter_objects_help": "Empty = show all objects.",
|
||||||
|
"card_filter_areas": "Filter by areas",
|
||||||
|
"card_filter_areas_help": "Empty = show all areas.",
|
||||||
"card_filter_entities": "Filter by entities (entity_ids)",
|
"card_filter_entities": "Filter by entities (entity_ids)",
|
||||||
"card_filter_entities_help": "Pick sensor / binary_sensor entities from this integration. Empty = all.",
|
"card_filter_entities_help": "Pick sensor / binary_sensor entities from this integration. Empty = all.",
|
||||||
"card_loading_objects": "Loading objects…",
|
"card_loading_objects": "Loading objects…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Sidebar panel title",
|
"settings_panel_title": "Sidebar panel title",
|
||||||
"settings_notifications": "Notifications",
|
"settings_notifications": "Notifications",
|
||||||
"settings_notify_service": "Notification service",
|
"settings_notify_service": "Notification service",
|
||||||
|
"settings_install_assist_sentences": "Install Assist sentences",
|
||||||
|
"settings_install_assist_sentences_hint": "Copies the voice sentences into your configuration so the classic Assist agent recognises them. A file you edited yourself is never overwritten.",
|
||||||
"test_notification": "Test notification",
|
"test_notification": "Test notification",
|
||||||
"send_test": "Send test",
|
"send_test": "Send test",
|
||||||
"testing": "Sending…",
|
"testing": "Sending…",
|
||||||
"test_notification_success": "Test notification sent",
|
"test_notification_success": "Test notification sent",
|
||||||
"test_notification_failed": "Test notification failed",
|
"test_notification_failed": "Test notification failed",
|
||||||
|
"notify_per_person": "Per-person delivery",
|
||||||
|
"notify_no_own_device": "No own device — uses the household service",
|
||||||
"settings_notify_due_soon": "Notify when due soon",
|
"settings_notify_due_soon": "Notify when due soon",
|
||||||
"settings_notify_overdue": "Notify when overdue",
|
"settings_notify_overdue": "Notify when overdue",
|
||||||
"settings_notify_triggered": "Notify when triggered",
|
"settings_notify_triggered": "Notify when triggered",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "By user",
|
"groupby_user": "By user",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "User",
|
"user_label": "User",
|
||||||
|
"photo_label": "Photo",
|
||||||
"sort_label": "Sort",
|
"sort_label": "Sort",
|
||||||
"group_by_label": "Group by",
|
"group_by_label": "Group by",
|
||||||
"state_value_help": "Use the HA state value (usually lowercase, e.g. \"on\"/\"off\"). Case is normalised on save.",
|
"state_value_help": "Use the HA state value (usually lowercase, e.g. \"on\"/\"off\"). Case is normalised on save.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Adjust stock",
|
"part_restock": "Adjust stock",
|
||||||
"restock_quantity_label": "Quantity bought",
|
"restock_quantity_label": "Quantity bought",
|
||||||
"consumes_parts_label": "Consumes parts",
|
"consumes_parts_label": "Consumes parts",
|
||||||
|
"shared_parts_other_objects": "Parts from other objects",
|
||||||
|
"shared_parts_help": "Several objects can share one stock. Completing this task takes from the owning object.",
|
||||||
|
"shared_part_unknown": "Unknown part",
|
||||||
"parts_load_failed": "Couldn't load this object's parts — the consumes-parts options are unavailable right now.",
|
"parts_load_failed": "Couldn't load this object's parts — the consumes-parts options are unavailable right now.",
|
||||||
"adopt_problem_button": "Adopt problem sensors",
|
"adopt_problem_button": "Adopt problem sensors",
|
||||||
"adopt_problem_title": "Adopt problem sensors",
|
"adopt_problem_title": "Adopt problem sensors",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valor del disparador",
|
"trigger_val": "Valor del disparador",
|
||||||
"complete_title": "Completada: ",
|
"complete_title": "Completada: ",
|
||||||
"checklist": "Lista de verificación",
|
"checklist": "Lista de verificación",
|
||||||
|
"require_on_completion": "Exigir al completar",
|
||||||
"checklist_steps_optional": "Pasos de la lista de verificación (opcional)",
|
"checklist_steps_optional": "Pasos de la lista de verificación (opcional)",
|
||||||
"checklist_placeholder": "Limpiar filtro\nReemplazar junta\nProbar presión",
|
"checklist_placeholder": "Limpiar filtro\nReemplazar junta\nProbar presión",
|
||||||
"checklist_help": "Un paso por línea. Máx. 100 elementos.",
|
"checklist_help": "Un paso por línea. Máx. 100 elementos.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vacío = mostrar todos los estados.",
|
"card_filter_status_help": "Vacío = mostrar todos los estados.",
|
||||||
"card_filter_objects": "Filtrar por objetos",
|
"card_filter_objects": "Filtrar por objetos",
|
||||||
"card_filter_objects_help": "Vacío = mostrar todos los objetos.",
|
"card_filter_objects_help": "Vacío = mostrar todos los objetos.",
|
||||||
|
"card_filter_areas": "Filtrar por áreas",
|
||||||
|
"card_filter_areas_help": "Vacío = mostrar todas las áreas.",
|
||||||
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
||||||
"card_filter_entities_help": "Selecciona entidades sensor / binary_sensor de esta integración. Vacío = todas.",
|
"card_filter_entities_help": "Selecciona entidades sensor / binary_sensor de esta integración. Vacío = todas.",
|
||||||
"card_loading_objects": "Cargando objetos…",
|
"card_loading_objects": "Cargando objetos…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Título del panel lateral",
|
"settings_panel_title": "Título del panel lateral",
|
||||||
"settings_notifications": "Notificaciones",
|
"settings_notifications": "Notificaciones",
|
||||||
"settings_notify_service": "Servicio de notificación",
|
"settings_notify_service": "Servicio de notificación",
|
||||||
|
"settings_install_assist_sentences": "Instalar frases de Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia las frases de voz en tu configuración para que el agente clásico de Assist las reconozca. Un archivo que hayas editado nunca se sobrescribe.",
|
||||||
"test_notification": "Notificación de prueba",
|
"test_notification": "Notificación de prueba",
|
||||||
"send_test": "Enviar prueba",
|
"send_test": "Enviar prueba",
|
||||||
"testing": "Enviando…",
|
"testing": "Enviando…",
|
||||||
"test_notification_success": "Notificación de prueba enviada",
|
"test_notification_success": "Notificación de prueba enviada",
|
||||||
"test_notification_failed": "La notificación de prueba falló",
|
"test_notification_failed": "La notificación de prueba falló",
|
||||||
|
"notify_per_person": "Entrega por persona",
|
||||||
|
"notify_no_own_device": "Sin dispositivo propio — usa el servicio del hogar",
|
||||||
"settings_notify_due_soon": "Notificar cuando esté próxima",
|
"settings_notify_due_soon": "Notificar cuando esté próxima",
|
||||||
"settings_notify_overdue": "Notificar cuando esté vencida",
|
"settings_notify_overdue": "Notificar cuando esté vencida",
|
||||||
"settings_notify_triggered": "Notificar cuando se active",
|
"settings_notify_triggered": "Notificar cuando se active",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Por usuario",
|
"groupby_user": "Por usuario",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Usuario",
|
"user_label": "Usuario",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordenar",
|
"sort_label": "Ordenar",
|
||||||
"group_by_label": "Agrupar por",
|
"group_by_label": "Agrupar por",
|
||||||
"state_value_help": "Usa el valor de estado de HA (normalmente en minúsculas, p. ej. \"on\"/\"off\"). Las mayúsculas se normalizan al guardar.",
|
"state_value_help": "Usa el valor de estado de HA (normalmente en minúsculas, p. ej. \"on\"/\"off\"). Las mayúsculas se normalizan al guardar.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Ajustar existencias",
|
"part_restock": "Ajustar existencias",
|
||||||
"restock_quantity_label": "Cantidad comprada",
|
"restock_quantity_label": "Cantidad comprada",
|
||||||
"consumes_parts_label": "Consume piezas",
|
"consumes_parts_label": "Consume piezas",
|
||||||
|
"shared_parts_other_objects": "Piezas de otros objetos",
|
||||||
|
"shared_parts_help": "Varios objetos pueden compartir un mismo stock. Al completar esta tarea se descuenta del objeto propietario.",
|
||||||
|
"shared_part_unknown": "Pieza desconocida",
|
||||||
"parts_load_failed": "No se pudieron cargar las piezas de este objeto — las opciones de consumo de piezas no están disponibles ahora.",
|
"parts_load_failed": "No se pudieron cargar las piezas de este objeto — las opciones de consumo de piezas no están disponibles ahora.",
|
||||||
"settings_export_selection": "Limitar a los objetos seleccionados (opcional)",
|
"settings_export_selection": "Limitar a los objetos seleccionados (opcional)",
|
||||||
"settings_docs_archive": "Archivo de documentos (con archivos)",
|
"settings_docs_archive": "Archivo de documentos (con archivos)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Laukaisuarvo",
|
"trigger_val": "Laukaisuarvo",
|
||||||
"complete_title": "Suorita: ",
|
"complete_title": "Suorita: ",
|
||||||
"checklist": "Tarkistuslista",
|
"checklist": "Tarkistuslista",
|
||||||
|
"require_on_completion": "Vaadi valmistuessa",
|
||||||
"checklist_steps_optional": "Tarkistuslistan vaiheet (valinnainen)",
|
"checklist_steps_optional": "Tarkistuslistan vaiheet (valinnainen)",
|
||||||
"checklist_placeholder": "Puhdista suodatin\nVaihda tiiviste\nTarkista paine",
|
"checklist_placeholder": "Puhdista suodatin\nVaihda tiiviste\nTarkista paine",
|
||||||
"checklist_help": "Yksi vaihe riviä kohden. Enintään 100 kohdetta.",
|
"checklist_help": "Yksi vaihe riviä kohden. Enintään 100 kohdetta.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Tyhjä = näytä kaikki tilat.",
|
"card_filter_status_help": "Tyhjä = näytä kaikki tilat.",
|
||||||
"card_filter_objects": "Suodata kohteiden mukaan",
|
"card_filter_objects": "Suodata kohteiden mukaan",
|
||||||
"card_filter_objects_help": "Tyhjä = näytä kaikki kohteet.",
|
"card_filter_objects_help": "Tyhjä = näytä kaikki kohteet.",
|
||||||
|
"card_filter_areas": "Suodata alueiden mukaan",
|
||||||
|
"card_filter_areas_help": "Tyhjä = näytä kaikki alueet.",
|
||||||
"card_filter_entities": "Suodata entiteettien mukaan (entity_id)",
|
"card_filter_entities": "Suodata entiteettien mukaan (entity_id)",
|
||||||
"card_filter_entities_help": "Valitse sensor- / binary_sensor-entiteetit tästä integraatiosta. Tyhjä = kaikki.",
|
"card_filter_entities_help": "Valitse sensor- / binary_sensor-entiteetit tästä integraatiosta. Tyhjä = kaikki.",
|
||||||
"card_loading_objects": "Ladataan kohteita…",
|
"card_loading_objects": "Ladataan kohteita…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Sivupalkin paneelin otsikko",
|
"settings_panel_title": "Sivupalkin paneelin otsikko",
|
||||||
"settings_notifications": "Ilmoitukset",
|
"settings_notifications": "Ilmoitukset",
|
||||||
"settings_notify_service": "Ilmoituspalvelu",
|
"settings_notify_service": "Ilmoituspalvelu",
|
||||||
|
"settings_install_assist_sentences": "Asenna Assist-lauseet",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopioi äänikomennot asetuksiisi, jotta perinteinen Assist-agentti tunnistaa ne. Itse muokkaamaasi tiedostoa ei koskaan korvata.",
|
||||||
"test_notification": "Testi-ilmoitus",
|
"test_notification": "Testi-ilmoitus",
|
||||||
"send_test": "Lähetä testi",
|
"send_test": "Lähetä testi",
|
||||||
"testing": "Lähetetään…",
|
"testing": "Lähetetään…",
|
||||||
"test_notification_success": "Testi-ilmoitus lähetetty",
|
"test_notification_success": "Testi-ilmoitus lähetetty",
|
||||||
"test_notification_failed": "Testi-ilmoitus epäonnistui",
|
"test_notification_failed": "Testi-ilmoitus epäonnistui",
|
||||||
|
"notify_per_person": "Toimitus henkilöittäin",
|
||||||
|
"notify_no_own_device": "Ei omaa laitetta — käyttää kotitalouden palvelua",
|
||||||
"settings_notify_due_soon": "Ilmoita, kun erääntyy pian",
|
"settings_notify_due_soon": "Ilmoita, kun erääntyy pian",
|
||||||
"settings_notify_overdue": "Ilmoita, kun myöhässä",
|
"settings_notify_overdue": "Ilmoita, kun myöhässä",
|
||||||
"settings_notify_triggered": "Ilmoita, kun laukaistu",
|
"settings_notify_triggered": "Ilmoita, kun laukaistu",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Käyttäjän mukaan",
|
"groupby_user": "Käyttäjän mukaan",
|
||||||
"filter_label": "Suodata",
|
"filter_label": "Suodata",
|
||||||
"user_label": "Käyttäjä",
|
"user_label": "Käyttäjä",
|
||||||
|
"photo_label": "Valokuva",
|
||||||
"sort_label": "Lajittele",
|
"sort_label": "Lajittele",
|
||||||
"group_by_label": "Ryhmittele",
|
"group_by_label": "Ryhmittele",
|
||||||
"state_value_help": "Käytä HA:n tila-arvoa (yleensä pienillä kirjaimilla, esim. \"on\"/\"off\"). Kirjainkoko normalisoidaan tallennettaessa.",
|
"state_value_help": "Käytä HA:n tila-arvoa (yleensä pienillä kirjaimilla, esim. \"on\"/\"off\"). Kirjainkoko normalisoidaan tallennettaessa.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Muuta varastoa",
|
"part_restock": "Muuta varastoa",
|
||||||
"restock_quantity_label": "Ostettu määrä",
|
"restock_quantity_label": "Ostettu määrä",
|
||||||
"consumes_parts_label": "Kuluttaa osia",
|
"consumes_parts_label": "Kuluttaa osia",
|
||||||
|
"shared_parts_other_objects": "Muiden kohteiden osat",
|
||||||
|
"shared_parts_help": "Useat kohteet voivat jakaa saman varaston. Tämän tehtävän suorittaminen vähentää omistavan kohteen varastoa.",
|
||||||
|
"shared_part_unknown": "Tuntematon osa",
|
||||||
"parts_load_failed": "Kohteen osia ei voitu ladata — osien kulutusvalinnat eivät ole juuri nyt käytettävissä.",
|
"parts_load_failed": "Kohteen osia ei voitu ladata — osien kulutusvalinnat eivät ole juuri nyt käytettävissä.",
|
||||||
"settings_export_selection": "Rajaa valittuihin kohteisiin (valinnainen)",
|
"settings_export_selection": "Rajaa valittuihin kohteisiin (valinnainen)",
|
||||||
"settings_docs_archive": "Asiakirja-arkisto (tiedostoineen)",
|
"settings_docs_archive": "Asiakirja-arkisto (tiedostoineen)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valeur du déclencheur",
|
"trigger_val": "Valeur du déclencheur",
|
||||||
"complete_title": "Terminé : ",
|
"complete_title": "Terminé : ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Exiger à la clôture",
|
||||||
"checklist_steps_optional": "Étapes de la checklist (optionnel)",
|
"checklist_steps_optional": "Étapes de la checklist (optionnel)",
|
||||||
"checklist_placeholder": "Nettoyer le filtre\nRemplacer le joint\nTester la pression",
|
"checklist_placeholder": "Nettoyer le filtre\nRemplacer le joint\nTester la pression",
|
||||||
"checklist_help": "Une étape par ligne. Max 100 éléments.",
|
"checklist_help": "Une étape par ligne. Max 100 éléments.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vide = afficher tous les statuts.",
|
"card_filter_status_help": "Vide = afficher tous les statuts.",
|
||||||
"card_filter_objects": "Filtrer par objets",
|
"card_filter_objects": "Filtrer par objets",
|
||||||
"card_filter_objects_help": "Vide = afficher tous les objets.",
|
"card_filter_objects_help": "Vide = afficher tous les objets.",
|
||||||
|
"card_filter_areas": "Filtrer par zones",
|
||||||
|
"card_filter_areas_help": "Vide = afficher toutes les zones.",
|
||||||
"card_filter_entities": "Filtrer par entités (entity_ids)",
|
"card_filter_entities": "Filtrer par entités (entity_ids)",
|
||||||
"card_filter_entities_help": "Choisissez des entités sensor / binary_sensor de cette intégration. Vide = toutes.",
|
"card_filter_entities_help": "Choisissez des entités sensor / binary_sensor de cette intégration. Vide = toutes.",
|
||||||
"card_loading_objects": "Chargement des objets…",
|
"card_loading_objects": "Chargement des objets…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Titre du panneau latéral",
|
"settings_panel_title": "Titre du panneau latéral",
|
||||||
"settings_notifications": "Notifications",
|
"settings_notifications": "Notifications",
|
||||||
"settings_notify_service": "Service de notification",
|
"settings_notify_service": "Service de notification",
|
||||||
|
"settings_install_assist_sentences": "Installer les phrases Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copie les phrases vocales dans votre configuration afin que l'agent Assist classique les reconnaisse. Un fichier que vous avez modifié n'est jamais écrasé.",
|
||||||
"test_notification": "Notification de test",
|
"test_notification": "Notification de test",
|
||||||
"send_test": "Envoyer le test",
|
"send_test": "Envoyer le test",
|
||||||
"testing": "Envoi en cours…",
|
"testing": "Envoi en cours…",
|
||||||
"test_notification_success": "Notification de test envoyée",
|
"test_notification_success": "Notification de test envoyée",
|
||||||
"test_notification_failed": "Échec de la notification de test",
|
"test_notification_failed": "Échec de la notification de test",
|
||||||
|
"notify_per_person": "Distribution par personne",
|
||||||
|
"notify_no_own_device": "Aucun appareil propre — utilise le service du foyer",
|
||||||
"settings_notify_due_soon": "Notifier quand bientôt dû",
|
"settings_notify_due_soon": "Notifier quand bientôt dû",
|
||||||
"settings_notify_overdue": "Notifier quand en retard",
|
"settings_notify_overdue": "Notifier quand en retard",
|
||||||
"settings_notify_triggered": "Notifier quand déclenché",
|
"settings_notify_triggered": "Notifier quand déclenché",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Par utilisateur",
|
"groupby_user": "Par utilisateur",
|
||||||
"filter_label": "Filtre",
|
"filter_label": "Filtre",
|
||||||
"user_label": "Utilisateur",
|
"user_label": "Utilisateur",
|
||||||
|
"photo_label": "Photo",
|
||||||
"sort_label": "Tri",
|
"sort_label": "Tri",
|
||||||
"group_by_label": "Grouper par",
|
"group_by_label": "Grouper par",
|
||||||
"state_value_help": "Utilisez la valeur d'état HA (généralement en minuscules, p. ex. \"on\"/\"off\"). La casse est normalisée à l'enregistrement.",
|
"state_value_help": "Utilisez la valeur d'état HA (généralement en minuscules, p. ex. \"on\"/\"off\"). La casse est normalisée à l'enregistrement.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Ajuster le stock",
|
"part_restock": "Ajuster le stock",
|
||||||
"restock_quantity_label": "Quantité achetée",
|
"restock_quantity_label": "Quantité achetée",
|
||||||
"consumes_parts_label": "Consomme des pièces",
|
"consumes_parts_label": "Consomme des pièces",
|
||||||
|
"shared_parts_other_objects": "Pièces d'autres objets",
|
||||||
|
"shared_parts_help": "Plusieurs objets peuvent partager un même stock. Terminer cette tâche décompte du stock de l'objet propriétaire.",
|
||||||
|
"shared_part_unknown": "Pièce inconnue",
|
||||||
"parts_load_failed": "Impossible de charger les pièces de cet objet — les options de consommation de pièces sont indisponibles pour le moment.",
|
"parts_load_failed": "Impossible de charger les pièces de cet objet — les options de consommation de pièces sont indisponibles pour le moment.",
|
||||||
"settings_export_selection": "Limiter aux objets sélectionnés (facultatif)",
|
"settings_export_selection": "Limiter aux objets sélectionnés (facultatif)",
|
||||||
"settings_docs_archive": "Archive de documents (avec fichiers)",
|
"settings_docs_archive": "Archive de documents (avec fichiers)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "ट्रिगर मान",
|
"trigger_val": "ट्रिगर मान",
|
||||||
"complete_title": "पूर्ण करें: ",
|
"complete_title": "पूर्ण करें: ",
|
||||||
"checklist": "चेकलिस्ट",
|
"checklist": "चेकलिस्ट",
|
||||||
|
"require_on_completion": "पूर्ण करते समय आवश्यक",
|
||||||
"checklist_steps_optional": "चेकलिस्ट चरण (वैकल्पिक)",
|
"checklist_steps_optional": "चेकलिस्ट चरण (वैकल्पिक)",
|
||||||
"checklist_placeholder": "फ़िल्टर साफ़ करें\nसील बदलें\nदबाव जाँचें",
|
"checklist_placeholder": "फ़िल्टर साफ़ करें\nसील बदलें\nदबाव जाँचें",
|
||||||
"checklist_help": "प्रति पंक्ति एक चरण। अधिकतम 100 आइटम।",
|
"checklist_help": "प्रति पंक्ति एक चरण। अधिकतम 100 आइटम।",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "खाली = सभी स्थितियाँ दिखाएँ।",
|
"card_filter_status_help": "खाली = सभी स्थितियाँ दिखाएँ।",
|
||||||
"card_filter_objects": "वस्तुओं के अनुसार फ़िल्टर करें",
|
"card_filter_objects": "वस्तुओं के अनुसार फ़िल्टर करें",
|
||||||
"card_filter_objects_help": "खाली = सभी वस्तुएँ दिखाएँ।",
|
"card_filter_objects_help": "खाली = सभी वस्तुएँ दिखाएँ।",
|
||||||
|
"card_filter_areas": "क्षेत्रों के अनुसार फ़िल्टर करें",
|
||||||
|
"card_filter_areas_help": "खाली = सभी क्षेत्र दिखाएँ।",
|
||||||
"card_filter_entities": "एंटिटी के अनुसार फ़िल्टर करें (entity_ids)",
|
"card_filter_entities": "एंटिटी के अनुसार फ़िल्टर करें (entity_ids)",
|
||||||
"card_filter_entities_help": "इस इंटीग्रेशन से sensor / binary_sensor एंटिटी चुनें। खाली = सभी।",
|
"card_filter_entities_help": "इस इंटीग्रेशन से sensor / binary_sensor एंटिटी चुनें। खाली = सभी।",
|
||||||
"card_loading_objects": "वस्तुएँ लोड हो रही हैं…",
|
"card_loading_objects": "वस्तुएँ लोड हो रही हैं…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "साइडबार पैनल शीर्षक",
|
"settings_panel_title": "साइडबार पैनल शीर्षक",
|
||||||
"settings_notifications": "सूचनाएँ",
|
"settings_notifications": "सूचनाएँ",
|
||||||
"settings_notify_service": "सूचना सेवा",
|
"settings_notify_service": "सूचना सेवा",
|
||||||
|
"settings_install_assist_sentences": "Assist वाक्य इंस्टॉल करें",
|
||||||
|
"settings_install_assist_sentences_hint": "वॉइस वाक्यों को आपके कॉन्फ़िगरेशन में कॉपी करता है ताकि क्लासिक Assist एजेंट उन्हें पहचान सके। आपके द्वारा संपादित फ़ाइल कभी अधिलेखित नहीं होती।",
|
||||||
"test_notification": "परीक्षण सूचना",
|
"test_notification": "परीक्षण सूचना",
|
||||||
"send_test": "परीक्षण भेजें",
|
"send_test": "परीक्षण भेजें",
|
||||||
"testing": "भेजा जा रहा है…",
|
"testing": "भेजा जा रहा है…",
|
||||||
"test_notification_success": "परीक्षण सूचना भेजी गई",
|
"test_notification_success": "परीक्षण सूचना भेजी गई",
|
||||||
"test_notification_failed": "परीक्षण सूचना विफल",
|
"test_notification_failed": "परीक्षण सूचना विफल",
|
||||||
|
"notify_per_person": "प्रति व्यक्ति वितरण",
|
||||||
|
"notify_no_own_device": "कोई निजी डिवाइस नहीं — घरेलू सेवा का उपयोग करता है",
|
||||||
"settings_notify_due_soon": "जल्द देय होने पर सूचित करें",
|
"settings_notify_due_soon": "जल्द देय होने पर सूचित करें",
|
||||||
"settings_notify_overdue": "अतिदेय होने पर सूचित करें",
|
"settings_notify_overdue": "अतिदेय होने पर सूचित करें",
|
||||||
"settings_notify_triggered": "ट्रिगर होने पर सूचित करें",
|
"settings_notify_triggered": "ट्रिगर होने पर सूचित करें",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "उपयोगकर्ता के अनुसार",
|
"groupby_user": "उपयोगकर्ता के अनुसार",
|
||||||
"filter_label": "फ़िल्टर",
|
"filter_label": "फ़िल्टर",
|
||||||
"user_label": "उपयोगकर्ता",
|
"user_label": "उपयोगकर्ता",
|
||||||
|
"photo_label": "फ़ोटो",
|
||||||
"sort_label": "क्रमबद्ध करें",
|
"sort_label": "क्रमबद्ध करें",
|
||||||
"group_by_label": "इसके अनुसार समूहित करें",
|
"group_by_label": "इसके अनुसार समूहित करें",
|
||||||
"state_value_help": "HA स्थिति मान का उपयोग करें (आमतौर पर लोअरकेस, उदा. \"on\"/\"off\")। सहेजने पर केस सामान्यीकृत हो जाता है।",
|
"state_value_help": "HA स्थिति मान का उपयोग करें (आमतौर पर लोअरकेस, उदा. \"on\"/\"off\")। सहेजने पर केस सामान्यीकृत हो जाता है।",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "स्टॉक समायोजित करें",
|
"part_restock": "स्टॉक समायोजित करें",
|
||||||
"restock_quantity_label": "खरीदी गई मात्रा",
|
"restock_quantity_label": "खरीदी गई मात्रा",
|
||||||
"consumes_parts_label": "पुर्ज़े खपत",
|
"consumes_parts_label": "पुर्ज़े खपत",
|
||||||
|
"shared_parts_other_objects": "अन्य वस्तुओं के पुर्ज़े",
|
||||||
|
"shared_parts_help": "कई वस्तुएँ एक ही स्टॉक साझा कर सकती हैं। यह कार्य पूरा करने पर स्वामी वस्तु के स्टॉक से घटाया जाता है।",
|
||||||
|
"shared_part_unknown": "अज्ञात पुर्ज़ा",
|
||||||
"parts_load_failed": "इस ऑब्जेक्ट के पुर्ज़े लोड नहीं हो सके — पुर्ज़ा-खपत विकल्प अभी उपलब्ध नहीं हैं।",
|
"parts_load_failed": "इस ऑब्जेक्ट के पुर्ज़े लोड नहीं हो सके — पुर्ज़ा-खपत विकल्प अभी उपलब्ध नहीं हैं।",
|
||||||
"settings_export_selection": "चयनित ऑब्जेक्ट तक सीमित करें (वैकल्पिक)",
|
"settings_export_selection": "चयनित ऑब्जेक्ट तक सीमित करें (वैकल्पिक)",
|
||||||
"settings_docs_archive": "दस्तावेज़ संग्रह (फ़ाइलों सहित)",
|
"settings_docs_archive": "दस्तावेज़ संग्रह (फ़ाइलों सहित)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Kiváltó érték",
|
"trigger_val": "Kiváltó érték",
|
||||||
"complete_title": "Elvégzés: ",
|
"complete_title": "Elvégzés: ",
|
||||||
"checklist": "Ellenőrzőlista",
|
"checklist": "Ellenőrzőlista",
|
||||||
|
"require_on_completion": "Befejezéskor kötelező",
|
||||||
"checklist_steps_optional": "Ellenőrzőlista lépései (opcionális)",
|
"checklist_steps_optional": "Ellenőrzőlista lépései (opcionális)",
|
||||||
"checklist_placeholder": "Szűrő tisztítása\nTömítés cseréje\nNyomáspróba",
|
"checklist_placeholder": "Szűrő tisztítása\nTömítés cseréje\nNyomáspróba",
|
||||||
"checklist_help": "Soronként egy lépés. Legfeljebb 100 elem.",
|
"checklist_help": "Soronként egy lépés. Legfeljebb 100 elem.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Üres = minden állapot megjelenik.",
|
"card_filter_status_help": "Üres = minden állapot megjelenik.",
|
||||||
"card_filter_objects": "Szűrés objektumok szerint",
|
"card_filter_objects": "Szűrés objektumok szerint",
|
||||||
"card_filter_objects_help": "Üres = minden objektum megjelenik.",
|
"card_filter_objects_help": "Üres = minden objektum megjelenik.",
|
||||||
|
"card_filter_areas": "Szűrés területek szerint",
|
||||||
|
"card_filter_areas_help": "Üres = minden terület megjelenik.",
|
||||||
"card_filter_entities": "Szűrés entitások szerint (entity_id-k)",
|
"card_filter_entities": "Szűrés entitások szerint (entity_id-k)",
|
||||||
"card_filter_entities_help": "Válasszon sensor / binary_sensor entitásokat ebből az integrációból. Üres = mind.",
|
"card_filter_entities_help": "Válasszon sensor / binary_sensor entitásokat ebből az integrációból. Üres = mind.",
|
||||||
"card_loading_objects": "Objektumok betöltése…",
|
"card_loading_objects": "Objektumok betöltése…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Oldalsáv-panel címe",
|
"settings_panel_title": "Oldalsáv-panel címe",
|
||||||
"settings_notifications": "Értesítések",
|
"settings_notifications": "Értesítések",
|
||||||
"settings_notify_service": "Értesítési szolgáltatás",
|
"settings_notify_service": "Értesítési szolgáltatás",
|
||||||
|
"settings_install_assist_sentences": "Assist mondatok telepítése",
|
||||||
|
"settings_install_assist_sentences_hint": "Átmásolja a hangmondatokat a konfigurációdba, hogy a klasszikus Assist ügynök felismerje őket. Az általad szerkesztett fájlt soha nem írja felül.",
|
||||||
"test_notification": "Tesztértesítés",
|
"test_notification": "Tesztértesítés",
|
||||||
"send_test": "Teszt küldése",
|
"send_test": "Teszt küldése",
|
||||||
"testing": "Küldés…",
|
"testing": "Küldés…",
|
||||||
"test_notification_success": "Tesztértesítés elküldve",
|
"test_notification_success": "Tesztértesítés elküldve",
|
||||||
"test_notification_failed": "A tesztértesítés nem sikerült",
|
"test_notification_failed": "A tesztértesítés nem sikerült",
|
||||||
|
"notify_per_person": "Kézbesítés személyenként",
|
||||||
|
"notify_no_own_device": "Nincs saját eszköz — a háztartási szolgáltatást használja",
|
||||||
"settings_notify_due_soon": "Értesítés, ha hamarosan esedékes",
|
"settings_notify_due_soon": "Értesítés, ha hamarosan esedékes",
|
||||||
"settings_notify_overdue": "Értesítés lejáratkor",
|
"settings_notify_overdue": "Értesítés lejáratkor",
|
||||||
"settings_notify_triggered": "Értesítés kiváltáskor",
|
"settings_notify_triggered": "Értesítés kiváltáskor",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "Felhasználó szerint",
|
"groupby_user": "Felhasználó szerint",
|
||||||
"filter_label": "Szűrő",
|
"filter_label": "Szűrő",
|
||||||
"user_label": "Felhasználó",
|
"user_label": "Felhasználó",
|
||||||
|
"photo_label": "Fénykép",
|
||||||
"sort_label": "Rendezés",
|
"sort_label": "Rendezés",
|
||||||
"group_by_label": "Csoportosítás",
|
"group_by_label": "Csoportosítás",
|
||||||
"state_value_help": "A HA állapotértékét használja (általában kisbetűs, pl. „on”/„off”). A kis- és nagybetűk mentéskor normalizálódnak.",
|
"state_value_help": "A HA állapotértékét használja (általában kisbetűs, pl. „on”/„off”). A kis- és nagybetűk mentéskor normalizálódnak.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Készlet módosítása",
|
"part_restock": "Készlet módosítása",
|
||||||
"restock_quantity_label": "Vásárolt mennyiség",
|
"restock_quantity_label": "Vásárolt mennyiség",
|
||||||
"consumes_parts_label": "Felhasznált alkatrészek",
|
"consumes_parts_label": "Felhasznált alkatrészek",
|
||||||
|
"shared_parts_other_objects": "Más objektumok alkatrészei",
|
||||||
|
"shared_parts_help": "Több objektum is használhatja ugyanazt a készletet. A feladat elvégzése a tulajdonos objektum készletéből von le.",
|
||||||
|
"shared_part_unknown": "Ismeretlen alkatrész",
|
||||||
"parts_load_failed": "Az objektum alkatrészei nem tölthetők be — a felhasznált alkatrészek beállításai most nem érhetők el.",
|
"parts_load_failed": "Az objektum alkatrészei nem tölthetők be — a felhasznált alkatrészek beállításai most nem érhetők el.",
|
||||||
"adopt_problem_button": "Problémaérzékelők átvétele",
|
"adopt_problem_button": "Problémaérzékelők átvétele",
|
||||||
"adopt_problem_title": "Problémaérzékelők átvétele",
|
"adopt_problem_title": "Problémaérzékelők átvétele",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valore trigger",
|
"trigger_val": "Valore trigger",
|
||||||
"complete_title": "Completato: ",
|
"complete_title": "Completato: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Richiedi al completamento",
|
||||||
"checklist_steps_optional": "Passaggi della checklist (opzionale)",
|
"checklist_steps_optional": "Passaggi della checklist (opzionale)",
|
||||||
"checklist_placeholder": "Pulire il filtro\nSostituire la guarnizione\nTestare la pressione",
|
"checklist_placeholder": "Pulire il filtro\nSostituire la guarnizione\nTestare la pressione",
|
||||||
"checklist_help": "Un passaggio per riga. Max 100 elementi.",
|
"checklist_help": "Un passaggio per riga. Max 100 elementi.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vuoto = mostra tutti gli stati.",
|
"card_filter_status_help": "Vuoto = mostra tutti gli stati.",
|
||||||
"card_filter_objects": "Filtra per oggetti",
|
"card_filter_objects": "Filtra per oggetti",
|
||||||
"card_filter_objects_help": "Vuoto = mostra tutti gli oggetti.",
|
"card_filter_objects_help": "Vuoto = mostra tutti gli oggetti.",
|
||||||
|
"card_filter_areas": "Filtra per aree",
|
||||||
|
"card_filter_areas_help": "Vuoto = mostra tutte le aree.",
|
||||||
"card_filter_entities": "Filtra per entità (entity_ids)",
|
"card_filter_entities": "Filtra per entità (entity_ids)",
|
||||||
"card_filter_entities_help": "Seleziona entità sensor / binary_sensor da questa integrazione. Vuoto = tutte.",
|
"card_filter_entities_help": "Seleziona entità sensor / binary_sensor da questa integrazione. Vuoto = tutte.",
|
||||||
"card_loading_objects": "Caricamento oggetti…",
|
"card_loading_objects": "Caricamento oggetti…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Titolo pannello laterale",
|
"settings_panel_title": "Titolo pannello laterale",
|
||||||
"settings_notifications": "Notifiche",
|
"settings_notifications": "Notifiche",
|
||||||
"settings_notify_service": "Servizio di notifica",
|
"settings_notify_service": "Servizio di notifica",
|
||||||
|
"settings_install_assist_sentences": "Installa le frasi di Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia le frasi vocali nella tua configurazione affinché l'agente Assist classico le riconosca. Un file modificato da te non viene mai sovrascritto.",
|
||||||
"test_notification": "Notifica di test",
|
"test_notification": "Notifica di test",
|
||||||
"send_test": "Invia test",
|
"send_test": "Invia test",
|
||||||
"testing": "Invio in corso…",
|
"testing": "Invio in corso…",
|
||||||
"test_notification_success": "Notifica di test inviata",
|
"test_notification_success": "Notifica di test inviata",
|
||||||
"test_notification_failed": "Notifica di test non riuscita",
|
"test_notification_failed": "Notifica di test non riuscita",
|
||||||
|
"notify_per_person": "Consegna per persona",
|
||||||
|
"notify_no_own_device": "Nessun dispositivo proprio — usa il servizio della casa",
|
||||||
"settings_notify_due_soon": "Notifica quando in scadenza",
|
"settings_notify_due_soon": "Notifica quando in scadenza",
|
||||||
"settings_notify_overdue": "Notifica quando scaduto",
|
"settings_notify_overdue": "Notifica quando scaduto",
|
||||||
"settings_notify_triggered": "Notifica quando attivato",
|
"settings_notify_triggered": "Notifica quando attivato",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Per utente",
|
"groupby_user": "Per utente",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Utente",
|
"user_label": "Utente",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordinamento",
|
"sort_label": "Ordinamento",
|
||||||
"group_by_label": "Raggruppa per",
|
"group_by_label": "Raggruppa per",
|
||||||
"state_value_help": "Usa il valore di stato HA (di solito minuscolo, es. \"on\"/\"off\"). Il case viene normalizzato al salvataggio.",
|
"state_value_help": "Usa il valore di stato HA (di solito minuscolo, es. \"on\"/\"off\"). Il case viene normalizzato al salvataggio.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Correggi scorta",
|
"part_restock": "Correggi scorta",
|
||||||
"restock_quantity_label": "Quantità acquistata",
|
"restock_quantity_label": "Quantità acquistata",
|
||||||
"consumes_parts_label": "Consuma ricambi",
|
"consumes_parts_label": "Consuma ricambi",
|
||||||
|
"shared_parts_other_objects": "Ricambi di altri oggetti",
|
||||||
|
"shared_parts_help": "Più oggetti possono condividere una sola scorta. Completando questa attività si preleva dall'oggetto proprietario.",
|
||||||
|
"shared_part_unknown": "Ricambio sconosciuto",
|
||||||
"parts_load_failed": "Impossibile caricare i ricambi di questo oggetto — le opzioni di consumo ricambi non sono al momento disponibili.",
|
"parts_load_failed": "Impossibile caricare i ricambi di questo oggetto — le opzioni di consumo ricambi non sono al momento disponibili.",
|
||||||
"settings_export_selection": "Limita agli oggetti selezionati (facoltativo)",
|
"settings_export_selection": "Limita agli oggetti selezionati (facoltativo)",
|
||||||
"settings_docs_archive": "Archivio documenti (con file)",
|
"settings_docs_archive": "Archivio documenti (con file)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "トリガー値",
|
"trigger_val": "トリガー値",
|
||||||
"complete_title": "完了: ",
|
"complete_title": "完了: ",
|
||||||
"checklist": "チェックリスト",
|
"checklist": "チェックリスト",
|
||||||
|
"require_on_completion": "完了時に必須",
|
||||||
"checklist_steps_optional": "チェックリストの手順(任意)",
|
"checklist_steps_optional": "チェックリストの手順(任意)",
|
||||||
"checklist_placeholder": "フィルター清掃\nシール交換\n圧力テスト",
|
"checklist_placeholder": "フィルター清掃\nシール交換\n圧力テスト",
|
||||||
"checklist_help": "1行に1手順。最大100項目。",
|
"checklist_help": "1行に1手順。最大100項目。",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "空欄=すべての状態を表示。",
|
"card_filter_status_help": "空欄=すべての状態を表示。",
|
||||||
"card_filter_objects": "対象で絞り込み",
|
"card_filter_objects": "対象で絞り込み",
|
||||||
"card_filter_objects_help": "空欄=すべての対象を表示。",
|
"card_filter_objects_help": "空欄=すべての対象を表示。",
|
||||||
|
"card_filter_areas": "エリアで絞り込み",
|
||||||
|
"card_filter_areas_help": "空欄=すべてのエリアを表示。",
|
||||||
"card_filter_entities": "エンティティで絞り込み(entity_ids)",
|
"card_filter_entities": "エンティティで絞り込み(entity_ids)",
|
||||||
"card_filter_entities_help": "この統合のsensor/binary_sensorエンティティを選択。空欄=すべて。",
|
"card_filter_entities_help": "この統合のsensor/binary_sensorエンティティを選択。空欄=すべて。",
|
||||||
"card_loading_objects": "対象を読み込み中…",
|
"card_loading_objects": "対象を読み込み中…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "サイドバーパネルのタイトル",
|
"settings_panel_title": "サイドバーパネルのタイトル",
|
||||||
"settings_notifications": "通知",
|
"settings_notifications": "通知",
|
||||||
"settings_notify_service": "通知サービス",
|
"settings_notify_service": "通知サービス",
|
||||||
|
"settings_install_assist_sentences": "Assist の文を導入する",
|
||||||
|
"settings_install_assist_sentences_hint": "音声フレーズを設定に複製し、従来の Assist エージェントが認識できるようにします。自分で編集したファイルが上書きされることはありません。",
|
||||||
"test_notification": "テスト通知",
|
"test_notification": "テスト通知",
|
||||||
"send_test": "テスト送信",
|
"send_test": "テスト送信",
|
||||||
"testing": "送信中…",
|
"testing": "送信中…",
|
||||||
"test_notification_success": "テスト通知を送信しました",
|
"test_notification_success": "テスト通知を送信しました",
|
||||||
"test_notification_failed": "テスト通知に失敗しました",
|
"test_notification_failed": "テスト通知に失敗しました",
|
||||||
|
"notify_per_person": "メンバーごとの配信",
|
||||||
|
"notify_no_own_device": "個人の端末なし — 家庭用サービスを使用",
|
||||||
"settings_notify_due_soon": "期限間近で通知",
|
"settings_notify_due_soon": "期限間近で通知",
|
||||||
"settings_notify_overdue": "期限超過で通知",
|
"settings_notify_overdue": "期限超過で通知",
|
||||||
"settings_notify_triggered": "トリガー発生で通知",
|
"settings_notify_triggered": "トリガー発生で通知",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "ユーザー別",
|
"groupby_user": "ユーザー別",
|
||||||
"filter_label": "絞り込み",
|
"filter_label": "絞り込み",
|
||||||
"user_label": "ユーザー",
|
"user_label": "ユーザー",
|
||||||
|
"photo_label": "写真",
|
||||||
"sort_label": "並べ替え",
|
"sort_label": "並べ替え",
|
||||||
"group_by_label": "グループ化",
|
"group_by_label": "グループ化",
|
||||||
"state_value_help": "HAの状態値を使用してください(通常は小文字、例: \"on\"/\"off\")。保存時に大文字小文字は正規化されます。",
|
"state_value_help": "HAの状態値を使用してください(通常は小文字、例: \"on\"/\"off\")。保存時に大文字小文字は正規化されます。",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "在庫を調整",
|
"part_restock": "在庫を調整",
|
||||||
"restock_quantity_label": "購入数量",
|
"restock_quantity_label": "購入数量",
|
||||||
"consumes_parts_label": "部品を消費",
|
"consumes_parts_label": "部品を消費",
|
||||||
|
"shared_parts_other_objects": "他の対象の部品",
|
||||||
|
"shared_parts_help": "複数の対象で同じ在庫を共有できます。このタスクを完了すると、所有する対象の在庫から差し引かれます。",
|
||||||
|
"shared_part_unknown": "不明な部品",
|
||||||
"parts_load_failed": "このオブジェクトの部品を読み込めませんでした — 部品消費オプションは現在利用できません。",
|
"parts_load_failed": "このオブジェクトの部品を読み込めませんでした — 部品消費オプションは現在利用できません。",
|
||||||
"settings_export_selection": "選択したオブジェクトに限定(任意)",
|
"settings_export_selection": "選択したオブジェクトに限定(任意)",
|
||||||
"settings_docs_archive": "ドキュメントアーカイブ(ファイル付き)",
|
"settings_docs_archive": "ドキュメントアーカイブ(ファイル付き)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "트리거 값",
|
"trigger_val": "트리거 값",
|
||||||
"complete_title": "완료: ",
|
"complete_title": "완료: ",
|
||||||
"checklist": "체크리스트",
|
"checklist": "체크리스트",
|
||||||
|
"require_on_completion": "완료 시 필수 입력",
|
||||||
"checklist_steps_optional": "체크리스트 단계 (선택)",
|
"checklist_steps_optional": "체크리스트 단계 (선택)",
|
||||||
"checklist_placeholder": "필터 청소\n씰 교체\n압력 테스트",
|
"checklist_placeholder": "필터 청소\n씰 교체\n압력 테스트",
|
||||||
"checklist_help": "한 줄에 한 단계씩 입력하세요. 최대 100개.",
|
"checklist_help": "한 줄에 한 단계씩 입력하세요. 최대 100개.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "비워두면 모든 상태를 표시합니다.",
|
"card_filter_status_help": "비워두면 모든 상태를 표시합니다.",
|
||||||
"card_filter_objects": "객체로 필터",
|
"card_filter_objects": "객체로 필터",
|
||||||
"card_filter_objects_help": "비워두면 모든 객체를 표시합니다.",
|
"card_filter_objects_help": "비워두면 모든 객체를 표시합니다.",
|
||||||
|
"card_filter_areas": "구역으로 필터",
|
||||||
|
"card_filter_areas_help": "비워두면 모든 구역을 표시합니다.",
|
||||||
"card_filter_entities": "엔티티로 필터 (entity_ids)",
|
"card_filter_entities": "엔티티로 필터 (entity_ids)",
|
||||||
"card_filter_entities_help": "이 통합구성요소의 sensor / binary_sensor 엔티티를 선택하세요. 비워두면 전체.",
|
"card_filter_entities_help": "이 통합구성요소의 sensor / binary_sensor 엔티티를 선택하세요. 비워두면 전체.",
|
||||||
"card_loading_objects": "객체 불러오는 중…",
|
"card_loading_objects": "객체 불러오는 중…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "사이드바 패널 제목",
|
"settings_panel_title": "사이드바 패널 제목",
|
||||||
"settings_notifications": "알림",
|
"settings_notifications": "알림",
|
||||||
"settings_notify_service": "알림 서비스",
|
"settings_notify_service": "알림 서비스",
|
||||||
|
"settings_install_assist_sentences": "Assist 문장 설치",
|
||||||
|
"settings_install_assist_sentences_hint": "음성 문장을 설정에 복사하여 기존 Assist 에이전트가 인식하도록 합니다. 직접 수정한 파일은 절대 덮어쓰지 않습니다.",
|
||||||
"test_notification": "테스트 알림",
|
"test_notification": "테스트 알림",
|
||||||
"send_test": "테스트 보내기",
|
"send_test": "테스트 보내기",
|
||||||
"testing": "보내는 중…",
|
"testing": "보내는 중…",
|
||||||
"test_notification_success": "테스트 알림을 보냈습니다",
|
"test_notification_success": "테스트 알림을 보냈습니다",
|
||||||
"test_notification_failed": "테스트 알림 전송 실패",
|
"test_notification_failed": "테스트 알림 전송 실패",
|
||||||
|
"notify_per_person": "사용자별 전송",
|
||||||
|
"notify_no_own_device": "개인 기기 없음 — 가정 서비스 사용",
|
||||||
"settings_notify_due_soon": "기한 임박 시 알림",
|
"settings_notify_due_soon": "기한 임박 시 알림",
|
||||||
"settings_notify_overdue": "기한 초과 시 알림",
|
"settings_notify_overdue": "기한 초과 시 알림",
|
||||||
"settings_notify_triggered": "트리거 시 알림",
|
"settings_notify_triggered": "트리거 시 알림",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "사용자별",
|
"groupby_user": "사용자별",
|
||||||
"filter_label": "필터",
|
"filter_label": "필터",
|
||||||
"user_label": "사용자",
|
"user_label": "사용자",
|
||||||
|
"photo_label": "사진",
|
||||||
"sort_label": "정렬",
|
"sort_label": "정렬",
|
||||||
"group_by_label": "그룹화",
|
"group_by_label": "그룹화",
|
||||||
"state_value_help": "HA 상태 값을 사용하세요(보통 소문자, 예: \"on\"/\"off\"). 대소문자는 저장 시 정규화됩니다.",
|
"state_value_help": "HA 상태 값을 사용하세요(보통 소문자, 예: \"on\"/\"off\"). 대소문자는 저장 시 정규화됩니다.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "재고 조정",
|
"part_restock": "재고 조정",
|
||||||
"restock_quantity_label": "구매 수량",
|
"restock_quantity_label": "구매 수량",
|
||||||
"consumes_parts_label": "사용하는 부품",
|
"consumes_parts_label": "사용하는 부품",
|
||||||
|
"shared_parts_other_objects": "다른 객체의 부품",
|
||||||
|
"shared_parts_help": "여러 객체가 하나의 재고를 공유할 수 있습니다. 이 작업을 완료하면 소유 객체의 재고에서 차감됩니다.",
|
||||||
|
"shared_part_unknown": "알 수 없는 부품",
|
||||||
"parts_load_failed": "이 객체의 부품을 불러올 수 없습니다 — 부품 사용 옵션을 지금은 쓸 수 없습니다.",
|
"parts_load_failed": "이 객체의 부품을 불러올 수 없습니다 — 부품 사용 옵션을 지금은 쓸 수 없습니다.",
|
||||||
"adopt_problem_button": "문제 센서 가져오기",
|
"adopt_problem_button": "문제 센서 가져오기",
|
||||||
"adopt_problem_title": "문제 센서 가져오기",
|
"adopt_problem_title": "문제 센서 가져오기",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Utløserverdi",
|
"trigger_val": "Utløserverdi",
|
||||||
"complete_title": "Fullfør: ",
|
"complete_title": "Fullfør: ",
|
||||||
"checklist": "Sjekkliste",
|
"checklist": "Sjekkliste",
|
||||||
|
"require_on_completion": "Krev ved fullføring",
|
||||||
"checklist_steps_optional": "Sjekklistetrinn (valgfritt)",
|
"checklist_steps_optional": "Sjekklistetrinn (valgfritt)",
|
||||||
"checklist_placeholder": "Rengjør filter\nBytt pakning\nTest trykk",
|
"checklist_placeholder": "Rengjør filter\nBytt pakning\nTest trykk",
|
||||||
"checklist_help": "Ett trinn per linje. Maks 100 elementer.",
|
"checklist_help": "Ett trinn per linje. Maks 100 elementer.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Tom = vis alle statuser.",
|
"card_filter_status_help": "Tom = vis alle statuser.",
|
||||||
"card_filter_objects": "Filtrer etter objekter",
|
"card_filter_objects": "Filtrer etter objekter",
|
||||||
"card_filter_objects_help": "Tom = vis alle objekter.",
|
"card_filter_objects_help": "Tom = vis alle objekter.",
|
||||||
|
"card_filter_areas": "Filtrer etter områder",
|
||||||
|
"card_filter_areas_help": "Tom = vis alle områder.",
|
||||||
"card_filter_entities": "Filtrer etter entiteter (entity_ids)",
|
"card_filter_entities": "Filtrer etter entiteter (entity_ids)",
|
||||||
"card_filter_entities_help": "Velg sensor-/binary_sensor-entiteter fra denne integrasjonen. Tom = alle.",
|
"card_filter_entities_help": "Velg sensor-/binary_sensor-entiteter fra denne integrasjonen. Tom = alle.",
|
||||||
"card_loading_objects": "Laster objekter…",
|
"card_loading_objects": "Laster objekter…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Tittel på sidepanel",
|
"settings_panel_title": "Tittel på sidepanel",
|
||||||
"settings_notifications": "Varsler",
|
"settings_notifications": "Varsler",
|
||||||
"settings_notify_service": "Varslingstjeneste",
|
"settings_notify_service": "Varslingstjeneste",
|
||||||
|
"settings_install_assist_sentences": "Installer Assist-setninger",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopierer talesetningene til konfigurasjonen din slik at den klassiske Assist-agenten gjenkjenner dem. En fil du selv har endret, blir aldri overskrevet.",
|
||||||
"test_notification": "Testvarsel",
|
"test_notification": "Testvarsel",
|
||||||
"send_test": "Send test",
|
"send_test": "Send test",
|
||||||
"testing": "Sender…",
|
"testing": "Sender…",
|
||||||
"test_notification_success": "Testvarsel sendt",
|
"test_notification_success": "Testvarsel sendt",
|
||||||
"test_notification_failed": "Testvarsel mislyktes",
|
"test_notification_failed": "Testvarsel mislyktes",
|
||||||
|
"notify_per_person": "Levering per person",
|
||||||
|
"notify_no_own_device": "Ingen egen enhet — bruker husstandens tjeneste",
|
||||||
"settings_notify_due_soon": "Varsle når noe forfaller snart",
|
"settings_notify_due_soon": "Varsle når noe forfaller snart",
|
||||||
"settings_notify_overdue": "Varsle når noe er forfalt",
|
"settings_notify_overdue": "Varsle når noe er forfalt",
|
||||||
"settings_notify_triggered": "Varsle når noe utløses",
|
"settings_notify_triggered": "Varsle når noe utløses",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "Etter bruker",
|
"groupby_user": "Etter bruker",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Bruker",
|
"user_label": "Bruker",
|
||||||
|
"photo_label": "Bilde",
|
||||||
"sort_label": "Sorter",
|
"sort_label": "Sorter",
|
||||||
"group_by_label": "Grupper etter",
|
"group_by_label": "Grupper etter",
|
||||||
"state_value_help": "Bruk HA-tilstandsverdien (vanligvis små bokstaver, f.eks. \"on\"/\"off\"). Store/små bokstaver normaliseres ved lagring.",
|
"state_value_help": "Bruk HA-tilstandsverdien (vanligvis små bokstaver, f.eks. \"on\"/\"off\"). Store/små bokstaver normaliseres ved lagring.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Juster lager",
|
"part_restock": "Juster lager",
|
||||||
"restock_quantity_label": "Kjøpt mengde",
|
"restock_quantity_label": "Kjøpt mengde",
|
||||||
"consumes_parts_label": "Forbruker deler",
|
"consumes_parts_label": "Forbruker deler",
|
||||||
|
"shared_parts_other_objects": "Deler fra andre objekter",
|
||||||
|
"shared_parts_help": "Flere objekter kan dele samme lager. Når oppgaven fullføres, trekkes det fra det eiende objektet.",
|
||||||
|
"shared_part_unknown": "Ukjent del",
|
||||||
"parts_load_failed": "Kunne ikke laste objektets deler — forbruksvalgene er ikke tilgjengelige nå.",
|
"parts_load_failed": "Kunne ikke laste objektets deler — forbruksvalgene er ikke tilgjengelige nå.",
|
||||||
"settings_export_selection": "Begrens til valgte objekter (valgfritt)",
|
"settings_export_selection": "Begrens til valgte objekter (valgfritt)",
|
||||||
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Triggerwaarde",
|
"trigger_val": "Triggerwaarde",
|
||||||
"complete_title": "Voltooid: ",
|
"complete_title": "Voltooid: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Vereisen bij afronden",
|
||||||
"checklist_steps_optional": "Checklist-stappen (optioneel)",
|
"checklist_steps_optional": "Checklist-stappen (optioneel)",
|
||||||
"checklist_placeholder": "Filter schoonmaken\nPakking vervangen\nDruk testen",
|
"checklist_placeholder": "Filter schoonmaken\nPakking vervangen\nDruk testen",
|
||||||
"checklist_help": "Eén stap per regel. Max. 100 items.",
|
"checklist_help": "Eén stap per regel. Max. 100 items.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Leeg = alle statussen tonen.",
|
"card_filter_status_help": "Leeg = alle statussen tonen.",
|
||||||
"card_filter_objects": "Filteren op objecten",
|
"card_filter_objects": "Filteren op objecten",
|
||||||
"card_filter_objects_help": "Leeg = alle objecten tonen.",
|
"card_filter_objects_help": "Leeg = alle objecten tonen.",
|
||||||
|
"card_filter_areas": "Filteren op gebieden",
|
||||||
|
"card_filter_areas_help": "Leeg = alle gebieden tonen.",
|
||||||
"card_filter_entities": "Filteren op entiteiten (entity_ids)",
|
"card_filter_entities": "Filteren op entiteiten (entity_ids)",
|
||||||
"card_filter_entities_help": "Kies sensor/binary_sensor entiteiten van deze integratie. Leeg = alle.",
|
"card_filter_entities_help": "Kies sensor/binary_sensor entiteiten van deze integratie. Leeg = alle.",
|
||||||
"card_loading_objects": "Objecten laden…",
|
"card_loading_objects": "Objecten laden…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Titel zijbalkpaneel",
|
"settings_panel_title": "Titel zijbalkpaneel",
|
||||||
"settings_notifications": "Meldingen",
|
"settings_notifications": "Meldingen",
|
||||||
"settings_notify_service": "Meldingsservice",
|
"settings_notify_service": "Meldingsservice",
|
||||||
|
"settings_install_assist_sentences": "Assist-zinnen installeren",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopieert de spraakzinnen naar je configuratie zodat de klassieke Assist-agent ze herkent. Een bestand dat je zelf hebt bewerkt wordt nooit overschreven.",
|
||||||
"test_notification": "Testmelding",
|
"test_notification": "Testmelding",
|
||||||
"send_test": "Test versturen",
|
"send_test": "Test versturen",
|
||||||
"testing": "Verzenden…",
|
"testing": "Verzenden…",
|
||||||
"test_notification_success": "Testmelding verzonden",
|
"test_notification_success": "Testmelding verzonden",
|
||||||
"test_notification_failed": "Testmelding mislukt",
|
"test_notification_failed": "Testmelding mislukt",
|
||||||
|
"notify_per_person": "Bezorging per persoon",
|
||||||
|
"notify_no_own_device": "Geen eigen apparaat — gebruikt de huishoudelijke dienst",
|
||||||
"settings_notify_due_soon": "Melding bij bijna verlopen",
|
"settings_notify_due_soon": "Melding bij bijna verlopen",
|
||||||
"settings_notify_overdue": "Melding bij achterstallig",
|
"settings_notify_overdue": "Melding bij achterstallig",
|
||||||
"settings_notify_triggered": "Melding bij geactiveerd",
|
"settings_notify_triggered": "Melding bij geactiveerd",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Per gebruiker",
|
"groupby_user": "Per gebruiker",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Gebruiker",
|
"user_label": "Gebruiker",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sorteren",
|
"sort_label": "Sorteren",
|
||||||
"group_by_label": "Groeperen op",
|
"group_by_label": "Groeperen op",
|
||||||
"state_value_help": "Gebruik de HA-statuswaarde (meestal in kleine letters, bv. \"on\"/\"off\"). Hoofdletters worden bij opslaan genormaliseerd.",
|
"state_value_help": "Gebruik de HA-statuswaarde (meestal in kleine letters, bv. \"on\"/\"off\"). Hoofdletters worden bij opslaan genormaliseerd.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Voorraad aanpassen",
|
"part_restock": "Voorraad aanpassen",
|
||||||
"restock_quantity_label": "Gekochte hoeveelheid",
|
"restock_quantity_label": "Gekochte hoeveelheid",
|
||||||
"consumes_parts_label": "Verbruikt onderdelen",
|
"consumes_parts_label": "Verbruikt onderdelen",
|
||||||
|
"shared_parts_other_objects": "Onderdelen van andere objecten",
|
||||||
|
"shared_parts_help": "Meerdere objecten kunnen één voorraad delen. Bij afronden wordt van het eigenaarsobject afgeboekt.",
|
||||||
|
"shared_part_unknown": "Onbekend onderdeel",
|
||||||
"parts_load_failed": "Kon de onderdelen van dit object niet laden — de verbruiksopties zijn nu niet beschikbaar.",
|
"parts_load_failed": "Kon de onderdelen van dit object niet laden — de verbruiksopties zijn nu niet beschikbaar.",
|
||||||
"settings_export_selection": "Beperken tot geselecteerde objecten (optioneel)",
|
"settings_export_selection": "Beperken tot geselecteerde objecten (optioneel)",
|
||||||
"settings_docs_archive": "Documentenarchief (met bestanden)",
|
"settings_docs_archive": "Documentenarchief (met bestanden)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Wartość wyzwalacza",
|
"trigger_val": "Wartość wyzwalacza",
|
||||||
"complete_title": "Wykonaj: ",
|
"complete_title": "Wykonaj: ",
|
||||||
"checklist": "Lista kontrolna",
|
"checklist": "Lista kontrolna",
|
||||||
|
"require_on_completion": "Wymagaj przy zakończeniu",
|
||||||
"checklist_steps_optional": "Kroki listy kontrolnej (opcjonalne)",
|
"checklist_steps_optional": "Kroki listy kontrolnej (opcjonalne)",
|
||||||
"checklist_placeholder": "Wyczyść filtr\nWymień uszczelkę\nSprawdź ciśnienie",
|
"checklist_placeholder": "Wyczyść filtr\nWymień uszczelkę\nSprawdź ciśnienie",
|
||||||
"checklist_help": "Jeden krok na linię. Maks. 100 elementów.",
|
"checklist_help": "Jeden krok na linię. Maks. 100 elementów.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Puste = pokaż wszystkie statusy.",
|
"card_filter_status_help": "Puste = pokaż wszystkie statusy.",
|
||||||
"card_filter_objects": "Filtruj wg obiektów",
|
"card_filter_objects": "Filtruj wg obiektów",
|
||||||
"card_filter_objects_help": "Puste = pokaż wszystkie obiekty.",
|
"card_filter_objects_help": "Puste = pokaż wszystkie obiekty.",
|
||||||
|
"card_filter_areas": "Filtruj wg obszarów",
|
||||||
|
"card_filter_areas_help": "Puste = pokaż wszystkie obszary.",
|
||||||
"card_filter_entities": "Filtruj wg encji (entity_ids)",
|
"card_filter_entities": "Filtruj wg encji (entity_ids)",
|
||||||
"card_filter_entities_help": "Wybierz encje sensor / binary_sensor z tej integracji. Puste = wszystkie.",
|
"card_filter_entities_help": "Wybierz encje sensor / binary_sensor z tej integracji. Puste = wszystkie.",
|
||||||
"card_loading_objects": "Ładowanie obiektów…",
|
"card_loading_objects": "Ładowanie obiektów…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Tytuł panelu bocznego",
|
"settings_panel_title": "Tytuł panelu bocznego",
|
||||||
"settings_notifications": "Powiadomienia",
|
"settings_notifications": "Powiadomienia",
|
||||||
"settings_notify_service": "Usługa powiadomień",
|
"settings_notify_service": "Usługa powiadomień",
|
||||||
|
"settings_install_assist_sentences": "Zainstaluj zdania Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopiuje zdania głosowe do Twojej konfiguracji, aby klasyczny agent Assist je rozpoznawał. Plik zmieniony przez Ciebie nigdy nie zostanie nadpisany.",
|
||||||
"test_notification": "Powiadomienie testowe",
|
"test_notification": "Powiadomienie testowe",
|
||||||
"send_test": "Wyślij test",
|
"send_test": "Wyślij test",
|
||||||
"testing": "Wysyłanie…",
|
"testing": "Wysyłanie…",
|
||||||
"test_notification_success": "Powiadomienie testowe wysłane",
|
"test_notification_success": "Powiadomienie testowe wysłane",
|
||||||
"test_notification_failed": "Powiadomienie testowe nie powiodło się",
|
"test_notification_failed": "Powiadomienie testowe nie powiodło się",
|
||||||
|
"notify_per_person": "Dostarczanie dla każdej osoby",
|
||||||
|
"notify_no_own_device": "Brak własnego urządzenia — używa usługi domowej",
|
||||||
"settings_notify_due_soon": "Powiadom gdy wkrótce",
|
"settings_notify_due_soon": "Powiadom gdy wkrótce",
|
||||||
"settings_notify_overdue": "Powiadom gdy zaległe",
|
"settings_notify_overdue": "Powiadom gdy zaległe",
|
||||||
"settings_notify_triggered": "Powiadom gdy wyzwolone",
|
"settings_notify_triggered": "Powiadom gdy wyzwolone",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Wg użytkownika",
|
"groupby_user": "Wg użytkownika",
|
||||||
"filter_label": "Filtr",
|
"filter_label": "Filtr",
|
||||||
"user_label": "Użytkownik",
|
"user_label": "Użytkownik",
|
||||||
|
"photo_label": "Zdjęcie",
|
||||||
"sort_label": "Sortowanie",
|
"sort_label": "Sortowanie",
|
||||||
"group_by_label": "Grupuj wg",
|
"group_by_label": "Grupuj wg",
|
||||||
"state_value_help": "Użyj wartości stanu HA (zwykle małymi literami, np. \"on\"/\"off\"). Wielkość liter jest normalizowana przy zapisie.",
|
"state_value_help": "Użyj wartości stanu HA (zwykle małymi literami, np. \"on\"/\"off\"). Wielkość liter jest normalizowana przy zapisie.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Koryguj stan",
|
"part_restock": "Koryguj stan",
|
||||||
"restock_quantity_label": "Kupiona ilość",
|
"restock_quantity_label": "Kupiona ilość",
|
||||||
"consumes_parts_label": "Zużywa części",
|
"consumes_parts_label": "Zużywa części",
|
||||||
|
"shared_parts_other_objects": "Części z innych obiektów",
|
||||||
|
"shared_parts_help": "Kilka obiektów może korzystać z jednego zapasu. Wykonanie tego zadania odejmuje ze stanu obiektu będącego właścicielem.",
|
||||||
|
"shared_part_unknown": "Nieznana część",
|
||||||
"parts_load_failed": "Nie udało się wczytać części tego obiektu — opcje zużycia części są teraz niedostępne.",
|
"parts_load_failed": "Nie udało się wczytać części tego obiektu — opcje zużycia części są teraz niedostępne.",
|
||||||
"settings_export_selection": "Ogranicz do wybranych obiektów (opcjonalnie)",
|
"settings_export_selection": "Ogranicz do wybranych obiektów (opcjonalnie)",
|
||||||
"settings_docs_archive": "Archiwum dokumentów (z plikami)",
|
"settings_docs_archive": "Archiwum dokumentów (z plikami)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Valor do gatilho",
|
"trigger_val": "Valor do gatilho",
|
||||||
"complete_title": "Concluir: ",
|
"complete_title": "Concluir: ",
|
||||||
"checklist": "Checklist",
|
"checklist": "Checklist",
|
||||||
|
"require_on_completion": "Exigir ao concluir",
|
||||||
"checklist_steps_optional": "Etapas do checklist (opcional)",
|
"checklist_steps_optional": "Etapas do checklist (opcional)",
|
||||||
"checklist_placeholder": "Limpar o filtro\nTrocar a vedação\nTestar a pressão",
|
"checklist_placeholder": "Limpar o filtro\nTrocar a vedação\nTestar a pressão",
|
||||||
"checklist_help": "Uma etapa por linha. Máx. 100 itens.",
|
"checklist_help": "Uma etapa por linha. Máx. 100 itens.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Vazio = mostrar todos os status.",
|
"card_filter_status_help": "Vazio = mostrar todos os status.",
|
||||||
"card_filter_objects": "Filtrar por objetos",
|
"card_filter_objects": "Filtrar por objetos",
|
||||||
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
||||||
|
"card_filter_areas": "Filtrar por áreas",
|
||||||
|
"card_filter_areas_help": "Vazio = mostrar todas as áreas.",
|
||||||
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
||||||
"card_filter_entities_help": "Escolha entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
"card_filter_entities_help": "Escolha entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
||||||
"card_loading_objects": "Carregando objetos…",
|
"card_loading_objects": "Carregando objetos…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Título do painel na barra lateral",
|
"settings_panel_title": "Título do painel na barra lateral",
|
||||||
"settings_notifications": "Notificações",
|
"settings_notifications": "Notificações",
|
||||||
"settings_notify_service": "Serviço de notificação",
|
"settings_notify_service": "Serviço de notificação",
|
||||||
|
"settings_install_assist_sentences": "Instalar frases do Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia as frases de voz para a sua configuração para que o agente Assist clássico as reconheça. Um arquivo que você editou nunca é sobrescrito.",
|
||||||
"test_notification": "Notificação de teste",
|
"test_notification": "Notificação de teste",
|
||||||
"send_test": "Enviar teste",
|
"send_test": "Enviar teste",
|
||||||
"testing": "Enviando…",
|
"testing": "Enviando…",
|
||||||
"test_notification_success": "Notificação de teste enviada",
|
"test_notification_success": "Notificação de teste enviada",
|
||||||
"test_notification_failed": "Falha na notificação de teste",
|
"test_notification_failed": "Falha na notificação de teste",
|
||||||
|
"notify_per_person": "Entrega por pessoa",
|
||||||
|
"notify_no_own_device": "Sem dispositivo próprio — usa o serviço da casa",
|
||||||
"settings_notify_due_soon": "Notificar quando vencer em breve",
|
"settings_notify_due_soon": "Notificar quando vencer em breve",
|
||||||
"settings_notify_overdue": "Notificar quando atrasada",
|
"settings_notify_overdue": "Notificar quando atrasada",
|
||||||
"settings_notify_triggered": "Notificar quando acionada",
|
"settings_notify_triggered": "Notificar quando acionada",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "Por usuário",
|
"groupby_user": "Por usuário",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Usuário",
|
"user_label": "Usuário",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordenar",
|
"sort_label": "Ordenar",
|
||||||
"group_by_label": "Agrupar por",
|
"group_by_label": "Agrupar por",
|
||||||
"state_value_help": "Use o valor de estado do HA (geralmente minúsculo, ex.: \"on\"/\"off\"). Maiúsculas e minúsculas são normalizadas ao salvar.",
|
"state_value_help": "Use o valor de estado do HA (geralmente minúsculo, ex.: \"on\"/\"off\"). Maiúsculas e minúsculas são normalizadas ao salvar.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Ajustar estoque",
|
"part_restock": "Ajustar estoque",
|
||||||
"restock_quantity_label": "Quantidade comprada",
|
"restock_quantity_label": "Quantidade comprada",
|
||||||
"consumes_parts_label": "Consome peças",
|
"consumes_parts_label": "Consome peças",
|
||||||
|
"shared_parts_other_objects": "Peças de outros objetos",
|
||||||
|
"shared_parts_help": "Vários objetos podem compartilhar o mesmo estoque. Concluir esta tarefa desconta do objeto proprietário.",
|
||||||
|
"shared_part_unknown": "Peça desconhecida",
|
||||||
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis no momento.",
|
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis no momento.",
|
||||||
"adopt_problem_button": "Adotar sensores de problema",
|
"adopt_problem_button": "Adotar sensores de problema",
|
||||||
"adopt_problem_title": "Adotar sensores de problema",
|
"adopt_problem_title": "Adotar sensores de problema",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Valor do acionador",
|
"trigger_val": "Valor do acionador",
|
||||||
"complete_title": "Concluída: ",
|
"complete_title": "Concluída: ",
|
||||||
"checklist": "Lista de verificação",
|
"checklist": "Lista de verificação",
|
||||||
|
"require_on_completion": "Exigir ao concluir",
|
||||||
"checklist_steps_optional": "Passos da lista de verificação (opcional)",
|
"checklist_steps_optional": "Passos da lista de verificação (opcional)",
|
||||||
"checklist_placeholder": "Limpar filtro\nSubstituir vedação\nTestar pressão",
|
"checklist_placeholder": "Limpar filtro\nSubstituir vedação\nTestar pressão",
|
||||||
"checklist_help": "Um passo por linha. Máx. 100 itens.",
|
"checklist_help": "Um passo por linha. Máx. 100 itens.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Vazio = mostrar todos os estados.",
|
"card_filter_status_help": "Vazio = mostrar todos os estados.",
|
||||||
"card_filter_objects": "Filtrar por objetos",
|
"card_filter_objects": "Filtrar por objetos",
|
||||||
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
"card_filter_objects_help": "Vazio = mostrar todos os objetos.",
|
||||||
|
"card_filter_areas": "Filtrar por áreas",
|
||||||
|
"card_filter_areas_help": "Vazio = mostrar todas as áreas.",
|
||||||
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
"card_filter_entities": "Filtrar por entidades (entity_ids)",
|
||||||
"card_filter_entities_help": "Selecione entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
"card_filter_entities_help": "Selecione entidades sensor / binary_sensor desta integração. Vazio = todas.",
|
||||||
"card_loading_objects": "A carregar objetos…",
|
"card_loading_objects": "A carregar objetos…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Título do painel lateral",
|
"settings_panel_title": "Título do painel lateral",
|
||||||
"settings_notifications": "Notificações",
|
"settings_notifications": "Notificações",
|
||||||
"settings_notify_service": "Serviço de notificação",
|
"settings_notify_service": "Serviço de notificação",
|
||||||
|
"settings_install_assist_sentences": "Instalar frases do Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Copia as frases de voz para a sua configuração para que o agente Assist clássico as reconheça. Um ficheiro que editou nunca é substituído.",
|
||||||
"test_notification": "Notificação de teste",
|
"test_notification": "Notificação de teste",
|
||||||
"send_test": "Enviar teste",
|
"send_test": "Enviar teste",
|
||||||
"testing": "A enviar…",
|
"testing": "A enviar…",
|
||||||
"test_notification_success": "Notificação de teste enviada",
|
"test_notification_success": "Notificação de teste enviada",
|
||||||
"test_notification_failed": "Falha na notificação de teste",
|
"test_notification_failed": "Falha na notificação de teste",
|
||||||
|
"notify_per_person": "Entrega por pessoa",
|
||||||
|
"notify_no_own_device": "Sem dispositivo próprio — usa o serviço da casa",
|
||||||
"settings_notify_due_soon": "Notificar quando próxima",
|
"settings_notify_due_soon": "Notificar quando próxima",
|
||||||
"settings_notify_overdue": "Notificar quando atrasada",
|
"settings_notify_overdue": "Notificar quando atrasada",
|
||||||
"settings_notify_triggered": "Notificar quando acionada",
|
"settings_notify_triggered": "Notificar quando acionada",
|
||||||
@@ -483,6 +490,7 @@
|
|||||||
"sort_group": "Grupo",
|
"sort_group": "Grupo",
|
||||||
"filter_label": "Filtro",
|
"filter_label": "Filtro",
|
||||||
"user_label": "Utilizador",
|
"user_label": "Utilizador",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Ordenar",
|
"sort_label": "Ordenar",
|
||||||
"group_by_label": "Agrupar por",
|
"group_by_label": "Agrupar por",
|
||||||
"state_value_help": "Use o valor de estado HA (normalmente em minúsculas, p. ex. \"on\"/\"off\"). As maiúsculas são normalizadas ao guardar.",
|
"state_value_help": "Use o valor de estado HA (normalmente em minúsculas, p. ex. \"on\"/\"off\"). As maiúsculas são normalizadas ao guardar.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Ajustar estoque",
|
"part_restock": "Ajustar estoque",
|
||||||
"restock_quantity_label": "Quantidade comprada",
|
"restock_quantity_label": "Quantidade comprada",
|
||||||
"consumes_parts_label": "Consome peças",
|
"consumes_parts_label": "Consome peças",
|
||||||
|
"shared_parts_other_objects": "Peças de outros objetos",
|
||||||
|
"shared_parts_help": "Vários objetos podem partilhar o mesmo stock. Concluir esta tarefa desconta do objeto proprietário.",
|
||||||
|
"shared_part_unknown": "Peça desconhecida",
|
||||||
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis.",
|
"parts_load_failed": "Não foi possível carregar as peças deste objeto — as opções de consumo de peças estão indisponíveis.",
|
||||||
"settings_export_selection": "Limitar aos objetos selecionados (opcional)",
|
"settings_export_selection": "Limitar aos objetos selecionados (opcional)",
|
||||||
"settings_docs_archive": "Arquivo de documentos (com ficheiros)",
|
"settings_docs_archive": "Arquivo de documentos (com ficheiros)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Значение триггера",
|
"trigger_val": "Значение триггера",
|
||||||
"complete_title": "Выполнить: ",
|
"complete_title": "Выполнить: ",
|
||||||
"checklist": "Контрольный список",
|
"checklist": "Контрольный список",
|
||||||
|
"require_on_completion": "Требовать при завершении",
|
||||||
"checklist_steps_optional": "Шаги контрольного списка (необязательно)",
|
"checklist_steps_optional": "Шаги контрольного списка (необязательно)",
|
||||||
"checklist_placeholder": "Очистить фильтр\nЗаменить уплотнитель\nПроверить давление",
|
"checklist_placeholder": "Очистить фильтр\nЗаменить уплотнитель\nПроверить давление",
|
||||||
"checklist_help": "Один шаг на строку. Макс. 100 элементов.",
|
"checklist_help": "Один шаг на строку. Макс. 100 элементов.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Пусто = показать все статусы.",
|
"card_filter_status_help": "Пусто = показать все статусы.",
|
||||||
"card_filter_objects": "Фильтровать по объектам",
|
"card_filter_objects": "Фильтровать по объектам",
|
||||||
"card_filter_objects_help": "Пусто = показать все объекты.",
|
"card_filter_objects_help": "Пусто = показать все объекты.",
|
||||||
|
"card_filter_areas": "Фильтровать по зонам",
|
||||||
|
"card_filter_areas_help": "Пусто = показать все зоны.",
|
||||||
"card_filter_entities": "Фильтровать по сущностям (entity_ids)",
|
"card_filter_entities": "Фильтровать по сущностям (entity_ids)",
|
||||||
"card_filter_entities_help": "Выберите сущности sensor / binary_sensor из этой интеграции. Пусто = все.",
|
"card_filter_entities_help": "Выберите сущности sensor / binary_sensor из этой интеграции. Пусто = все.",
|
||||||
"card_loading_objects": "Загрузка объектов…",
|
"card_loading_objects": "Загрузка объектов…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Заголовок панели",
|
"settings_panel_title": "Заголовок панели",
|
||||||
"settings_notifications": "Уведомления",
|
"settings_notifications": "Уведомления",
|
||||||
"settings_notify_service": "Сервис уведомлений",
|
"settings_notify_service": "Сервис уведомлений",
|
||||||
|
"settings_install_assist_sentences": "Установить фразы Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Копирует голосовые фразы в вашу конфигурацию, чтобы классический агент Assist их распознавал. Файл, который вы изменили, никогда не перезаписывается.",
|
||||||
"test_notification": "Тестовое уведомление",
|
"test_notification": "Тестовое уведомление",
|
||||||
"send_test": "Отправить тест",
|
"send_test": "Отправить тест",
|
||||||
"testing": "Отправка…",
|
"testing": "Отправка…",
|
||||||
"test_notification_success": "Тестовое уведомление отправлено",
|
"test_notification_success": "Тестовое уведомление отправлено",
|
||||||
"test_notification_failed": "Не удалось отправить тестовое уведомление",
|
"test_notification_failed": "Не удалось отправить тестовое уведомление",
|
||||||
|
"notify_per_person": "Доставка по пользователям",
|
||||||
|
"notify_no_own_device": "Нет своего устройства — используется общий сервис",
|
||||||
"settings_notify_due_soon": "Уведомлять, когда срок скоро истекает",
|
"settings_notify_due_soon": "Уведомлять, когда срок скоро истекает",
|
||||||
"settings_notify_overdue": "Уведомлять при просрочке",
|
"settings_notify_overdue": "Уведомлять при просрочке",
|
||||||
"settings_notify_triggered": "Уведомлять при срабатывании",
|
"settings_notify_triggered": "Уведомлять при срабатывании",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "По пользователю",
|
"groupby_user": "По пользователю",
|
||||||
"filter_label": "Фильтр",
|
"filter_label": "Фильтр",
|
||||||
"user_label": "Пользователь",
|
"user_label": "Пользователь",
|
||||||
|
"photo_label": "Фото",
|
||||||
"sort_label": "Сортировка",
|
"sort_label": "Сортировка",
|
||||||
"group_by_label": "Группировать по",
|
"group_by_label": "Группировать по",
|
||||||
"state_value_help": "Используйте значение состояния HA (обычно в нижнем регистре, напр. \"on\"/\"off\"). Регистр нормализуется при сохранении.",
|
"state_value_help": "Используйте значение состояния HA (обычно в нижнем регистре, напр. \"on\"/\"off\"). Регистр нормализуется при сохранении.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Изменить запас",
|
"part_restock": "Изменить запас",
|
||||||
"restock_quantity_label": "Куплено, шт.",
|
"restock_quantity_label": "Куплено, шт.",
|
||||||
"consumes_parts_label": "Расходует детали",
|
"consumes_parts_label": "Расходует детали",
|
||||||
|
"shared_parts_other_objects": "Детали других объектов",
|
||||||
|
"shared_parts_help": "Несколько объектов могут использовать один запас. Выполнение этой задачи списывает детали у объекта-владельца.",
|
||||||
|
"shared_part_unknown": "Неизвестная деталь",
|
||||||
"parts_load_failed": "Не удалось загрузить запчасти этого объекта — параметры расхода запчастей сейчас недоступны.",
|
"parts_load_failed": "Не удалось загрузить запчасти этого объекта — параметры расхода запчастей сейчас недоступны.",
|
||||||
"settings_export_selection": "Ограничить выбранными объектами (необязательно)",
|
"settings_export_selection": "Ограничить выбранными объектами (необязательно)",
|
||||||
"settings_docs_archive": "Архив документов (с файлами)",
|
"settings_docs_archive": "Архив документов (с файлами)",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Utlösarvärde",
|
"trigger_val": "Utlösarvärde",
|
||||||
"complete_title": "Slutför: ",
|
"complete_title": "Slutför: ",
|
||||||
"checklist": "Checklista",
|
"checklist": "Checklista",
|
||||||
|
"require_on_completion": "Kräv vid slutförande",
|
||||||
"checklist_steps_optional": "Checkliststeg (valfritt)",
|
"checklist_steps_optional": "Checkliststeg (valfritt)",
|
||||||
"checklist_placeholder": "Rengör filter\nByt tätning\nTesta tryck",
|
"checklist_placeholder": "Rengör filter\nByt tätning\nTesta tryck",
|
||||||
"checklist_help": "Ett steg per rad. Max 100 objekt.",
|
"checklist_help": "Ett steg per rad. Max 100 objekt.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Tomt = visa alla statusar.",
|
"card_filter_status_help": "Tomt = visa alla statusar.",
|
||||||
"card_filter_objects": "Filtrera efter objekt",
|
"card_filter_objects": "Filtrera efter objekt",
|
||||||
"card_filter_objects_help": "Tomt = visa alla objekt.",
|
"card_filter_objects_help": "Tomt = visa alla objekt.",
|
||||||
|
"card_filter_areas": "Filtrera efter områden",
|
||||||
|
"card_filter_areas_help": "Tomt = visa alla områden.",
|
||||||
"card_filter_entities": "Filtrera efter entiteter (entity_ids)",
|
"card_filter_entities": "Filtrera efter entiteter (entity_ids)",
|
||||||
"card_filter_entities_help": "Välj sensor- / binary_sensor-entiteter från denna integration. Tomt = alla.",
|
"card_filter_entities_help": "Välj sensor- / binary_sensor-entiteter från denna integration. Tomt = alla.",
|
||||||
"card_loading_objects": "Laddar objekt…",
|
"card_loading_objects": "Laddar objekt…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Sidopanelens titel",
|
"settings_panel_title": "Sidopanelens titel",
|
||||||
"settings_notifications": "Notifikationer",
|
"settings_notifications": "Notifikationer",
|
||||||
"settings_notify_service": "Notifikationstjänst",
|
"settings_notify_service": "Notifikationstjänst",
|
||||||
|
"settings_install_assist_sentences": "Installera Assist-meningar",
|
||||||
|
"settings_install_assist_sentences_hint": "Kopierar rösmeningarna till din konfiguration så att den klassiska Assist-agenten känner igen dem. En fil du själv har ändrat skrivs aldrig över.",
|
||||||
"test_notification": "Testnotifikation",
|
"test_notification": "Testnotifikation",
|
||||||
"send_test": "Skicka test",
|
"send_test": "Skicka test",
|
||||||
"testing": "Skickar…",
|
"testing": "Skickar…",
|
||||||
"test_notification_success": "Testnotifikation skickad",
|
"test_notification_success": "Testnotifikation skickad",
|
||||||
"test_notification_failed": "Testnotifikation misslyckades",
|
"test_notification_failed": "Testnotifikation misslyckades",
|
||||||
|
"notify_per_person": "Leverans per person",
|
||||||
|
"notify_no_own_device": "Ingen egen enhet — använder hushållets tjänst",
|
||||||
"settings_notify_due_soon": "Notifiera när snart förfallande",
|
"settings_notify_due_soon": "Notifiera när snart förfallande",
|
||||||
"settings_notify_overdue": "Notifiera när försenad",
|
"settings_notify_overdue": "Notifiera när försenad",
|
||||||
"settings_notify_triggered": "Notifiera när utlöst",
|
"settings_notify_triggered": "Notifiera när utlöst",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "Per användare",
|
"groupby_user": "Per användare",
|
||||||
"filter_label": "Filter",
|
"filter_label": "Filter",
|
||||||
"user_label": "Användare",
|
"user_label": "Användare",
|
||||||
|
"photo_label": "Foto",
|
||||||
"sort_label": "Sortering",
|
"sort_label": "Sortering",
|
||||||
"group_by_label": "Gruppera efter",
|
"group_by_label": "Gruppera efter",
|
||||||
"state_value_help": "Använd HA-tillståndsvärdet (vanligtvis med små bokstäver, t.ex. \"on\"/\"off\"). Versaler normaliseras vid sparande.",
|
"state_value_help": "Använd HA-tillståndsvärdet (vanligtvis med små bokstäver, t.ex. \"on\"/\"off\"). Versaler normaliseras vid sparande.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Justera lager",
|
"part_restock": "Justera lager",
|
||||||
"restock_quantity_label": "Köpt antal",
|
"restock_quantity_label": "Köpt antal",
|
||||||
"consumes_parts_label": "Förbrukar delar",
|
"consumes_parts_label": "Förbrukar delar",
|
||||||
|
"shared_parts_other_objects": "Delar från andra objekt",
|
||||||
|
"shared_parts_help": "Flera objekt kan dela samma lager. När uppgiften slutförs dras det från det ägande objektet.",
|
||||||
|
"shared_part_unknown": "Okänd del",
|
||||||
"parts_load_failed": "Kunde inte läsa in objektets delar — förbrukningsalternativen är inte tillgängliga just nu.",
|
"parts_load_failed": "Kunde inte läsa in objektets delar — förbrukningsalternativen är inte tillgängliga just nu.",
|
||||||
"settings_export_selection": "Begränsa till valda objekt (valfritt)",
|
"settings_export_selection": "Begränsa till valda objekt (valfritt)",
|
||||||
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
"settings_docs_archive": "Dokumentarkiv (med filer)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "Tetikleme değeri",
|
"trigger_val": "Tetikleme değeri",
|
||||||
"complete_title": "Tamamla: ",
|
"complete_title": "Tamamla: ",
|
||||||
"checklist": "Kontrol listesi",
|
"checklist": "Kontrol listesi",
|
||||||
|
"require_on_completion": "Tamamlarken zorunlu tut",
|
||||||
"checklist_steps_optional": "Kontrol listesi adımları (isteğe bağlı)",
|
"checklist_steps_optional": "Kontrol listesi adımları (isteğe bağlı)",
|
||||||
"checklist_placeholder": "Filtreyi temizle\nContayı değiştir\nBasıncı test et",
|
"checklist_placeholder": "Filtreyi temizle\nContayı değiştir\nBasıncı test et",
|
||||||
"checklist_help": "Her satıra bir adım. En fazla 100 madde.",
|
"checklist_help": "Her satıra bir adım. En fazla 100 madde.",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "Boş = tüm durumları göster.",
|
"card_filter_status_help": "Boş = tüm durumları göster.",
|
||||||
"card_filter_objects": "Nesnelere göre filtrele",
|
"card_filter_objects": "Nesnelere göre filtrele",
|
||||||
"card_filter_objects_help": "Boş = tüm nesneleri göster.",
|
"card_filter_objects_help": "Boş = tüm nesneleri göster.",
|
||||||
|
"card_filter_areas": "Alanlara göre filtrele",
|
||||||
|
"card_filter_areas_help": "Boş = tüm alanları göster.",
|
||||||
"card_filter_entities": "Varlıklara göre filtrele (entity_id)",
|
"card_filter_entities": "Varlıklara göre filtrele (entity_id)",
|
||||||
"card_filter_entities_help": "Bu entegrasyonun sensor / binary_sensor varlıklarını seçin. Boş = tümü.",
|
"card_filter_entities_help": "Bu entegrasyonun sensor / binary_sensor varlıklarını seçin. Boş = tümü.",
|
||||||
"card_loading_objects": "Nesneler yükleniyor…",
|
"card_loading_objects": "Nesneler yükleniyor…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "Kenar çubuğu paneli başlığı",
|
"settings_panel_title": "Kenar çubuğu paneli başlığı",
|
||||||
"settings_notifications": "Bildirimler",
|
"settings_notifications": "Bildirimler",
|
||||||
"settings_notify_service": "Bildirim servisi",
|
"settings_notify_service": "Bildirim servisi",
|
||||||
|
"settings_install_assist_sentences": "Assist cümlelerini yükle",
|
||||||
|
"settings_install_assist_sentences_hint": "Sesli komut cümlelerini yapılandırmanıza kopyalar, böylece klasik Assist aracısı bunları tanır. Kendi düzenlediğiniz bir dosyanın üzerine asla yazılmaz.",
|
||||||
"test_notification": "Test bildirimi",
|
"test_notification": "Test bildirimi",
|
||||||
"send_test": "Test gönder",
|
"send_test": "Test gönder",
|
||||||
"testing": "Gönderiliyor…",
|
"testing": "Gönderiliyor…",
|
||||||
"test_notification_success": "Test bildirimi gönderildi",
|
"test_notification_success": "Test bildirimi gönderildi",
|
||||||
"test_notification_failed": "Test bildirimi başarısız oldu",
|
"test_notification_failed": "Test bildirimi başarısız oldu",
|
||||||
|
"notify_per_person": "Kişi bazında iletim",
|
||||||
|
"notify_no_own_device": "Kendi cihazı yok — ev servisini kullanır",
|
||||||
"settings_notify_due_soon": "Vade yaklaştığında bildir",
|
"settings_notify_due_soon": "Vade yaklaştığında bildir",
|
||||||
"settings_notify_overdue": "Geciktiğinde bildir",
|
"settings_notify_overdue": "Geciktiğinde bildir",
|
||||||
"settings_notify_triggered": "Tetiklendiğinde bildir",
|
"settings_notify_triggered": "Tetiklendiğinde bildir",
|
||||||
@@ -494,6 +501,7 @@
|
|||||||
"groupby_user": "Kullanıcıya göre",
|
"groupby_user": "Kullanıcıya göre",
|
||||||
"filter_label": "Filtre",
|
"filter_label": "Filtre",
|
||||||
"user_label": "Kullanıcı",
|
"user_label": "Kullanıcı",
|
||||||
|
"photo_label": "Fotoğraf",
|
||||||
"sort_label": "Sırala",
|
"sort_label": "Sırala",
|
||||||
"group_by_label": "Grupla",
|
"group_by_label": "Grupla",
|
||||||
"state_value_help": "HA durum değerini kullanın (genellikle küçük harf, örn. \"on\"/\"off\"). Büyük/küçük harf kaydederken normalleştirilir.",
|
"state_value_help": "HA durum değerini kullanın (genellikle küçük harf, örn. \"on\"/\"off\"). Büyük/küçük harf kaydederken normalleştirilir.",
|
||||||
@@ -728,6 +736,9 @@
|
|||||||
"part_restock": "Stoku ayarla",
|
"part_restock": "Stoku ayarla",
|
||||||
"restock_quantity_label": "Satın alınan miktar",
|
"restock_quantity_label": "Satın alınan miktar",
|
||||||
"consumes_parts_label": "Parça tüketir",
|
"consumes_parts_label": "Parça tüketir",
|
||||||
|
"shared_parts_other_objects": "Diğer nesnelerin parçaları",
|
||||||
|
"shared_parts_help": "Birden fazla nesne aynı stoğu paylaşabilir. Bu görev tamamlandığında stok, sahibi olan nesneden düşülür.",
|
||||||
|
"shared_part_unknown": "Bilinmeyen parça",
|
||||||
"parts_load_failed": "Bu nesnenin parçaları yüklenemedi — parça tüketimi seçenekleri şu anda kullanılamıyor.",
|
"parts_load_failed": "Bu nesnenin parçaları yüklenemedi — parça tüketimi seçenekleri şu anda kullanılamıyor.",
|
||||||
"adopt_problem_button": "Sorun sensörlerini devral",
|
"adopt_problem_button": "Sorun sensörlerini devral",
|
||||||
"adopt_problem_title": "Sorun sensörlerini devral",
|
"adopt_problem_title": "Sorun sensörlerini devral",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"trigger_val": "Значення тригера",
|
"trigger_val": "Значення тригера",
|
||||||
"complete_title": "Виконати: ",
|
"complete_title": "Виконати: ",
|
||||||
"checklist": "Чекліст",
|
"checklist": "Чекліст",
|
||||||
|
"require_on_completion": "Вимагати при завершенні",
|
||||||
"checklist_steps_optional": "Кроки чекліста (необов'язково)",
|
"checklist_steps_optional": "Кроки чекліста (необов'язково)",
|
||||||
"checklist_placeholder": "Очистити фільтр\nЗамінити ущільнювач\nПеревірити тиск",
|
"checklist_placeholder": "Очистити фільтр\nЗамінити ущільнювач\nПеревірити тиск",
|
||||||
"checklist_help": "Один крок на рядок. Макс. 100 елементів.",
|
"checklist_help": "Один крок на рядок. Макс. 100 елементів.",
|
||||||
@@ -362,6 +363,8 @@
|
|||||||
"card_filter_status_help": "Порожньо = показати всі статуси.",
|
"card_filter_status_help": "Порожньо = показати всі статуси.",
|
||||||
"card_filter_objects": "Фільтрувати за об'єктами",
|
"card_filter_objects": "Фільтрувати за об'єктами",
|
||||||
"card_filter_objects_help": "Порожньо = показати всі об'єкти.",
|
"card_filter_objects_help": "Порожньо = показати всі об'єкти.",
|
||||||
|
"card_filter_areas": "Фільтрувати за зонами",
|
||||||
|
"card_filter_areas_help": "Порожньо = показати всі зони.",
|
||||||
"card_filter_entities": "Фільтрувати за сутностями (entity_ids)",
|
"card_filter_entities": "Фільтрувати за сутностями (entity_ids)",
|
||||||
"card_filter_entities_help": "Виберіть сутності sensor / binary_sensor з цієї інтеграції. Порожньо = всі.",
|
"card_filter_entities_help": "Виберіть сутності sensor / binary_sensor з цієї інтеграції. Порожньо = всі.",
|
||||||
"card_loading_objects": "Завантаження об'єктів…",
|
"card_loading_objects": "Завантаження об'єктів…",
|
||||||
@@ -431,11 +434,15 @@
|
|||||||
"settings_panel_title": "Заголовок панелі",
|
"settings_panel_title": "Заголовок панелі",
|
||||||
"settings_notifications": "Сповіщення",
|
"settings_notifications": "Сповіщення",
|
||||||
"settings_notify_service": "Служба сповіщень",
|
"settings_notify_service": "Служба сповіщень",
|
||||||
|
"settings_install_assist_sentences": "Встановити фрази Assist",
|
||||||
|
"settings_install_assist_sentences_hint": "Копіює голосові фрази до вашої конфігурації, щоб класичний агент Assist їх розпізнавав. Файл, який ви редагували, ніколи не перезаписується.",
|
||||||
"test_notification": "Тестове сповіщення",
|
"test_notification": "Тестове сповіщення",
|
||||||
"send_test": "Надіслати тест",
|
"send_test": "Надіслати тест",
|
||||||
"testing": "Надсилання…",
|
"testing": "Надсилання…",
|
||||||
"test_notification_success": "Тестове сповіщення надіслано",
|
"test_notification_success": "Тестове сповіщення надіслано",
|
||||||
"test_notification_failed": "Не вдалося надіслати тестове сповіщення",
|
"test_notification_failed": "Не вдалося надіслати тестове сповіщення",
|
||||||
|
"notify_per_person": "Доставка за особами",
|
||||||
|
"notify_no_own_device": "Немає власного пристрою — використовується загальна служба",
|
||||||
"settings_notify_due_soon": "Сповіщати, коли термін наближається",
|
"settings_notify_due_soon": "Сповіщати, коли термін наближається",
|
||||||
"settings_notify_overdue": "Сповіщати про прострочення",
|
"settings_notify_overdue": "Сповіщати про прострочення",
|
||||||
"settings_notify_triggered": "Сповіщати про спрацювання",
|
"settings_notify_triggered": "Сповіщати про спрацювання",
|
||||||
@@ -487,6 +494,7 @@
|
|||||||
"groupby_user": "За користувачем",
|
"groupby_user": "За користувачем",
|
||||||
"filter_label": "Фільтр",
|
"filter_label": "Фільтр",
|
||||||
"user_label": "Користувач",
|
"user_label": "Користувач",
|
||||||
|
"photo_label": "Фото",
|
||||||
"sort_label": "Сортування",
|
"sort_label": "Сортування",
|
||||||
"group_by_label": "Групувати за",
|
"group_by_label": "Групувати за",
|
||||||
"state_value_help": "Використовуйте значення стану HA (зазвичай у нижньому регістрі, напр. \"on\"/\"off\"). Регістр нормалізується при збереженні.",
|
"state_value_help": "Використовуйте значення стану HA (зазвичай у нижньому регістрі, напр. \"on\"/\"off\"). Регістр нормалізується при збереженні.",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "Змінити запас",
|
"part_restock": "Змінити запас",
|
||||||
"restock_quantity_label": "Куплена кількість",
|
"restock_quantity_label": "Куплена кількість",
|
||||||
"consumes_parts_label": "Витрачає деталі",
|
"consumes_parts_label": "Витрачає деталі",
|
||||||
|
"shared_parts_other_objects": "Деталі інших об'єктів",
|
||||||
|
"shared_parts_help": "Кілька об'єктів можуть використовувати один запас. Виконання цього завдання списує деталі з об'єкта-власника.",
|
||||||
|
"shared_part_unknown": "Невідома деталь",
|
||||||
"parts_load_failed": "Не вдалося завантажити запчастини цього об'єкта — параметри витрати запчастин зараз недоступні.",
|
"parts_load_failed": "Не вдалося завантажити запчастини цього об'єкта — параметри витрати запчастин зараз недоступні.",
|
||||||
"settings_export_selection": "Обмежити вибраними об'єктами (необов'язково)",
|
"settings_export_selection": "Обмежити вибраними об'єктами (необов'язково)",
|
||||||
"settings_docs_archive": "Архів документів (з файлами)",
|
"settings_docs_archive": "Архів документів (з файлами)",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"trigger_val": "触发值",
|
"trigger_val": "触发值",
|
||||||
"complete_title": "完成: ",
|
"complete_title": "完成: ",
|
||||||
"checklist": "检查清单",
|
"checklist": "检查清单",
|
||||||
|
"require_on_completion": "完成时必填",
|
||||||
"checklist_steps_optional": "检查步骤 (可选)",
|
"checklist_steps_optional": "检查步骤 (可选)",
|
||||||
"checklist_placeholder": "清理过滤器\n更换密封圈\n测试压力",
|
"checklist_placeholder": "清理过滤器\n更换密封圈\n测试压力",
|
||||||
"checklist_help": "每行一个步骤。最多 100 项。",
|
"checklist_help": "每行一个步骤。最多 100 项。",
|
||||||
@@ -363,6 +364,8 @@
|
|||||||
"card_filter_status_help": "留空则显示所有状态。",
|
"card_filter_status_help": "留空则显示所有状态。",
|
||||||
"card_filter_objects": "按维护项过滤",
|
"card_filter_objects": "按维护项过滤",
|
||||||
"card_filter_objects_help": "留空则显示所有维护项。",
|
"card_filter_objects_help": "留空则显示所有维护项。",
|
||||||
|
"card_filter_areas": "按区域过滤",
|
||||||
|
"card_filter_areas_help": "留空则显示所有区域。",
|
||||||
"card_filter_entities": "按实体过滤 (entity_ids)",
|
"card_filter_entities": "按实体过滤 (entity_ids)",
|
||||||
"card_filter_entities_help": "选择该集成的传感器或二进制传感器实体。留空则显示全部。",
|
"card_filter_entities_help": "选择该集成的传感器或二进制传感器实体。留空则显示全部。",
|
||||||
"card_loading_objects": "正在加载维护项…",
|
"card_loading_objects": "正在加载维护项…",
|
||||||
@@ -432,11 +435,15 @@
|
|||||||
"settings_panel_title": "侧边栏面板标题",
|
"settings_panel_title": "侧边栏面板标题",
|
||||||
"settings_notifications": "通知",
|
"settings_notifications": "通知",
|
||||||
"settings_notify_service": "通知服务",
|
"settings_notify_service": "通知服务",
|
||||||
|
"settings_install_assist_sentences": "安装 Assist 语句",
|
||||||
|
"settings_install_assist_sentences_hint": "将语音语句复制到你的配置中,让传统 Assist 代理能够识别它们。你自己修改过的文件永远不会被覆盖。",
|
||||||
"test_notification": "测试通知",
|
"test_notification": "测试通知",
|
||||||
"send_test": "发送测试",
|
"send_test": "发送测试",
|
||||||
"testing": "正在发送…",
|
"testing": "正在发送…",
|
||||||
"test_notification_success": "测试通知已发送",
|
"test_notification_success": "测试通知已发送",
|
||||||
"test_notification_failed": "测试通知发送失败",
|
"test_notification_failed": "测试通知发送失败",
|
||||||
|
"notify_per_person": "按成员分别投递",
|
||||||
|
"notify_no_own_device": "无个人设备 — 使用家庭通知服务",
|
||||||
"settings_notify_due_soon": "到期前通知提醒",
|
"settings_notify_due_soon": "到期前通知提醒",
|
||||||
"settings_notify_overdue": "超期后通知提醒",
|
"settings_notify_overdue": "超期后通知提醒",
|
||||||
"settings_notify_triggered": "触发时通知提醒",
|
"settings_notify_triggered": "触发时通知提醒",
|
||||||
@@ -488,6 +495,7 @@
|
|||||||
"groupby_user": "按负责人",
|
"groupby_user": "按负责人",
|
||||||
"filter_label": "过滤器",
|
"filter_label": "过滤器",
|
||||||
"user_label": "用户",
|
"user_label": "用户",
|
||||||
|
"photo_label": "照片",
|
||||||
"sort_label": "排序",
|
"sort_label": "排序",
|
||||||
"group_by_label": "分组依据",
|
"group_by_label": "分组依据",
|
||||||
"state_value_help": "使用 HA 状态值(通常为小写,例如 \"on\"/\"off\")。保存时大小写会自动规范化。",
|
"state_value_help": "使用 HA 状态值(通常为小写,例如 \"on\"/\"off\")。保存时大小写会自动规范化。",
|
||||||
@@ -722,6 +730,9 @@
|
|||||||
"part_restock": "调整库存",
|
"part_restock": "调整库存",
|
||||||
"restock_quantity_label": "购买数量",
|
"restock_quantity_label": "购买数量",
|
||||||
"consumes_parts_label": "消耗配件",
|
"consumes_parts_label": "消耗配件",
|
||||||
|
"shared_parts_other_objects": "其他设备的配件",
|
||||||
|
"shared_parts_help": "多个设备可以共用同一批库存。完成此任务将从所属设备的库存中扣减。",
|
||||||
|
"shared_part_unknown": "未知配件",
|
||||||
"parts_load_failed": "无法加载此对象的配件 — 配件消耗选项暂时不可用。",
|
"parts_load_failed": "无法加载此对象的配件 — 配件消耗选项暂时不可用。",
|
||||||
"settings_export_selection": "仅限所选对象(可选)",
|
"settings_export_selection": "仅限所选对象(可选)",
|
||||||
"settings_docs_archive": "文档存档(含文件)",
|
"settings_docs_archive": "文档存档(含文件)",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
var rt=Object.defineProperty;var at=Object.getOwnPropertyDescriptor;var x=(a,e,t,o)=>{for(var r=o>1?void 0:o?at(e,t):e,n=a.length-1,s;n>=0;n--)(s=a[n])&&(r=(o?s(e,t,r):s(r))||r);return o&&r&&rt(e,t,r),r};var Z=globalThis,X=Z.ShadowRoot&&(Z.ShadyCSS===void 0||Z.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,ce=Symbol(),ke=new WeakMap,H=class{constructor(e,t,o){if(this._$cssResult$=!0,o!==ce)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(X&&e===void 0){let o=t!==void 0&&t.length===1;o&&(e=ke.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),o&&ke.set(t,e))}return e}toString(){return this.cssText}},Se=a=>new H(typeof a=="string"?a:a+"",void 0,ce),k=(a,...e)=>{let t=a.length===1?a[0]:e.reduce((o,r,n)=>o+(s=>{if(s._$cssResult$===!0)return s.cssText;if(typeof s=="number")return s;throw Error("Value passed to 'css' function must be a 'css' function result: "+s+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+a[n+1],a[0]);return new H(t,a,ce)},$e=(a,e)=>{if(X)a.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let o=document.createElement("style"),r=Z.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,a.appendChild(o)}},de=X?a=>a:a=>a instanceof CSSStyleSheet?(e=>{let t="";for(let o of e.cssRules)t+=o.cssText;return Se(t)})(a):a;var{is:nt,defineProperty:st,getOwnPropertyDescriptor:it,getOwnPropertyNames:lt,getOwnPropertySymbols:ct,getPrototypeOf:dt}=Object,ee=globalThis,Ae=ee.trustedTypes,pt=Ae?Ae.emptyScript:"",ut=ee.reactiveElementPolyfillSupport,q=(a,e)=>a,I={toAttribute(a,e){switch(e){case Boolean:a=a?pt:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,e){let t=a;switch(e){case Boolean:t=a!==null;break;case Number:t=a===null?null:Number(a);break;case Object:case Array:try{t=JSON.parse(a)}catch{t=null}}return t}},te=(a,e)=>!nt(a,e),Ce={attribute:!0,type:String,converter:I,reflect:!1,useDefault:!1,hasChanged:te};Symbol.metadata??=Symbol("metadata"),ee.litPropertyMetadata??=new WeakMap;var S=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let o=Symbol(),r=this.getPropertyDescriptor(e,o,t);r!==void 0&&st(this.prototype,e,r)}}static getPropertyDescriptor(e,t,o){let{get:r,set:n}=it(this.prototype,e)??{get(){return this[t]},set(s){this[t]=s}};return{get:r,set(s){let l=r?.call(this);n?.call(this,s),this.requestUpdate(e,l,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(q("elementProperties")))return;let e=dt(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(q("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(q("properties"))){let t=this.properties,o=[...lt(t),...ct(t)];for(let r of o)this.createProperty(r,t[r])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[o,r]of t)this.elementProperties.set(o,r)}this._$Eh=new Map;for(let[t,o]of this.elementProperties){let r=this._$Eu(t,o);r!==void 0&&this._$Eh.set(r,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let o=new Set(e.flat(1/0).reverse());for(let r of o)t.unshift(de(r))}else e!==void 0&&t.push(de(e));return t}static _$Eu(e,t){let o=t.attribute;return o===!1?void 0:typeof o=="string"?o:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let o of t.keys())this.hasOwnProperty(o)&&(e.set(o,this[o]),delete this[o]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return $e(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,o){this._$AK(e,o)}_$ET(e,t){let o=this.constructor.elementPropertiLine truncated
|
/*! maintenance_supporter frontend 2.44.1 */
|
||||||
|
var at=Object.defineProperty;var nt=Object.getOwnPropertyDescriptor;var x=(a,e,t,o)=>{for(var r=o>1?void 0:o?nt(e,t):e,n=a.length-1,s;n>=0;n--)(s=a[n])&&(r=(o?s(e,t,r):s(r))||r);return o&&r&&at(e,t,r),r};var Z=globalThis,X=Z.ShadowRoot&&(Z.ShadyCSS===void 0||Z.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,ce=Symbol(),ke=new WeakMap,H=class{constructor(e,t,o){if(this._$cssResult$=!0,o!==ce)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(X&&e===void 0){let o=t!==void 0&&t.length===1;o&&(e=ke.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),o&&ke.set(t,e))}return e}toString(){return this.cssText}},Se=a=>new H(typeof a=="string"?a:a+"",void 0,ce),k=(a,...e)=>{let t=a.length===1?a[0]:e.reduce((o,r,n)=>o+(s=>{if(s._$cssResult$===!0)return s.cssText;if(typeof s=="number")return s;throw Error("Value passed to 'css' function must be a 'css' function result: "+s+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+a[n+1],a[0]);return new H(t,a,ce)},$e=(a,e)=>{if(X)a.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let o=document.createElement("style"),r=Z.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,a.appendChild(o)}},de=X?a=>a:a=>a instanceof CSSStyleSheet?(e=>{let t="";for(let o of e.cssRules)t+=o.cssText;return Se(t)})(a):a;var{is:st,defineProperty:it,getOwnPropertyDescriptor:lt,getOwnPropertyNames:ct,getOwnPropertySymbols:dt,getPrototypeOf:pt}=Object,ee=globalThis,Ae=ee.trustedTypes,ut=Ae?Ae.emptyScript:"",_t=ee.reactiveElementPolyfillSupport,q=(a,e)=>a,I={toAttribute(a,e){switch(e){case Boolean:a=a?ut:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,e){let t=a;switch(e){case Boolean:t=a!==null;break;case Number:t=a===null?null:Number(a);break;case Object:case Array:try{t=JSON.parse(a)}catch{t=null}}return t}},te=(a,e)=>!st(a,e),Ce={attribute:!0,type:String,converter:I,reflect:!1,useDefault:!1,hasChanged:te};Symbol.metadata??=Symbol("metadata"),ee.litPropertyMetadata??=new WeakMap;var S=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let o=Symbol(),r=this.getPropertyDescriptor(e,o,t);r!==void 0&&it(this.prototype,e,r)}}static getPropertyDescriptor(e,t,o){let{get:r,set:n}=lt(this.prototype,e)??{get(){return this[t]},set(s){this[t]=s}};return{get:r,set(s){let l=r?.call(this);n?.call(this,s),this.requestUpdate(e,l,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(q("elementProperties")))return;let e=pt(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(q("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(q("properties"))){let t=this.properties,o=[...ct(t),...dt(t)];for(let r of o)this.createProperty(r,t[r])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[o,r]of t)this.elementProperties.set(o,r)}this._$Eh=new Map;for(let[t,o]of this.elementProperties){let r=this._$Eu(t,o);r!==void 0&&this._$Eh.set(r,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let o=new Set(e.flat(1/0).reverse());for(let r of o)t.unshift(de(r))}else e!==void 0&&t.push(de(e));return t}static _$Eu(e,t){let o=t.attribute;return o===!1?void 0:typeof o=="string"?o:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let o of t.keys())this.hasOwnProperty(o)&&(e.set(o,this[o]),delete this[o]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return $e(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,o){this._$AK(e,o)}_$ET(e,t){let o=this.constructor.elementPropertiLine truncated
|
||||||
\f\r]`,F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Te=/-->/g,De=/>/g,C=RegExp(`>|${pe}(?:([^\\s"'>=/]+)(${pe}*=${pe}*(?:[^
|
\f\r]`,F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Te=/-->/g,De=/>/g,C=RegExp(`>|${pe}(?:([^\\s"'>=/]+)(${pe}*=${pe}*(?:[^
|
||||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ne=/'/g,Re=/"/g,Oe=/^(?:script|style|textarea|title)$/i,ye=a=>(e,...t)=>({_$litType$:a,strings:e,values:t}),m=ye(1),Ot=ye(2),Mt=ye(3),T=Symbol.for("lit-noChange"),g=Symbol.for("lit-nothing"),Pe=new WeakMap,E=j.createTreeWalker(j,129);function Me(a,e){if(!be(a)||!a.hasOwnProperty("raw"))throw Error("invalid template strings array");return je!==void 0?je.createHTML(e):e}var gt=(a,e)=>{let t=a.length-1,o=[],r,n=e===2?"<svg>":e===3?"<math>":"",s=F;for(let l=0;l<t;l++){let c=a[l],p,u,d=-1,_=0;for(;_<c.length&&(s.lastIndex=_,u=s.exec(c),u!==null);)_=s.lastIndex,s===F?u[1]==="!--"?s=Te:u[1]!==void 0?s=De:u[2]!==void 0?(Oe.test(u[2])&&(r=RegExp("</"+u[2],"g")),s=C):u[3]!==void 0&&(s=C):s===C?u[0]===">"?(s=r??F,d=-1):u[1]===void 0?d=-2:(d=s.lastIndex-u[2].length,p=u[1],s=u[3]===void 0?C:u[3]==='"'?Re:Ne):s===Re||s===Ne?s=C:s===Te||s===De?s=F:(s=C,r=void 0);let h=s===C&&a[l+1].startsWith("/>")?" ":"";n+=s===F?c+_t:d>=0?(o.push(p),c.slice(0,d)+ze+c.slice(d)+A+h):c+A+(d===-2?l:h)}return[Me(a,n+(a[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),o]},Y=class a{constructor({strings:e,_$litType$:t},o){let r;this.parts=[];let n=0,s=0,l=e.length-1,c=this.parts,[p,u]=gt(e,t);if(this.el=a.createElement(p,o),E.currentNode=this.el.content,t===2||t===3){let d=this.el.content.firstChild;d.replaceWith(...d.childNodes)}for(;(r=E.nextNode())!==null&&c.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let d of r.getAttributeNames())if(d.endsWith(ze)){let _=u[s++],h=r.getAttribute(d).split(A),b=/([.?@])?(.*)/.exec(_);c.push({type:1,index:n,name:b[2],strings:h,ctor:b[1]==="."?_e:b[1]==="?"?he:b[1]==="@"?ge:L}),r.removeAttribute(d)}else d.startsWith(A)&&(c.push({type:6,index:n}),r.removeAttribute(d));if(Oe.test(r.tagName)){let d=r.textContent.split(A),_=d.length-1;if(_>0){r.textContent=oe?oe.emptyScript:"";for(let h=0;h<_;h++)r.append(d[h],B()),E.nextNode(),c.push({type:2,index:++n});r.append(d[_],B())}}}else if(r.nodeType===8)if(r.data===Le)c.push({type:2,index:n});else{let d=-1;for(;(d=r.data.indexOf(A,d+1))!==-1;)c.push({type:7,index:n}),d+=A.length-1}n++}}static createElement(e,t){let o=j.createElement("template");return o.innerHTML=e,o}};function z(a,e,t=a,o){if(e===T)return e;let r=o!==void 0?t._$Co?.[o]:t._$Cl,n=W(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),n===void 0?r=void 0:(r=new n(a),r._$AT(a,t,o)),o!==void 0?(t._$Co??=[])[o]=r:t._$Cl=r),r!==void 0&&(e=z(a,r._$AS(a,e.values),r,o)),e}var ue=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:o}=this._$AD,r=(e?.creationScope??j).importNode(t,!0);E.currentNode=r;let n=E.nextNode(),s=0,l=0,c=o[0];for(;c!==void 0;){if(s===c.index){let p;c.type===2?p=new G(n,n.nextSibling,this,e):c.type===1?p=new c.ctor(n,c.name,c.strings,this,e):c.type===6&&(p=new me(n,this,e)),this._$AV.push(p),c=o[++l]}s!==c?.index&&(n=E.nextNode(),s++)}return E.currentNode=j,r}p(e){let t=0;for(let o of this._$AV)o!==void 0&&(o.strings!==void 0?(o._$AI(e,o,t),t+=o.strings.length-2):o._$AI(e[t])),t++}},G=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,o,r){this.type=2,this._$AH=g,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=o,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=z(this,e,t),W(e)?e===g||e==null||e===""?(this._$AH!==g&&this._$AR(),this._$AH=g):e!==this._$AH&&e!==T&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):ht(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==g&&W(this._$AH)?this._$AA.nextSibling.data=e:this.T(j.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:o}=e,r=typeof o=="number"?this._$AC(e):(o.el===void 0&&(o.el=Y.createElement(Me(o.h,o.h[0]),this.options)),o);if(this._$AH?._$AD===r)this._$AH.p(t);else{let n=new ue(r,this),s=n.u(this.options);n.p(t),this.T(s),this._$AH=n}}_$AC(e){let t=Pe.get(e.strings);return t===void 0&&Pe.set(e.strings,t=new Y(e)),t}k(e){be(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,o,r=0;for(let n of e)r===t.length?t.push(o=new a(this.O(B()),this.O(B()),this,this.options)):o=t[r],o._$AI(n),r++;r<t.length&&(this._$AR(o&&o._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let o=Ee(e).nextSibling;Ee(e).remove(),e=o}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},L=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,o,r,n){this.type=1,this._$AH=g,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=n,o.length>2||o[0]!==""||o[1]!==""?(this._$AH=Array(o.length-1).fill(new String),this.strings=Line truncated
|
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ne=/'/g,Re=/"/g,Oe=/^(?:script|style|textarea|title)$/i,ye=a=>(e,...t)=>({_$litType$:a,strings:e,values:t}),f=ye(1),Mt=ye(2),Ut=ye(3),T=Symbol.for("lit-noChange"),g=Symbol.for("lit-nothing"),Pe=new WeakMap,j=E.createTreeWalker(E,129);function Me(a,e){if(!be(a)||!a.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ee!==void 0?Ee.createHTML(e):e}var mt=(a,e)=>{let t=a.length-1,o=[],r,n=e===2?"<svg>":e===3?"<math>":"",s=F;for(let l=0;l<t;l++){let c=a[l],p,u,d=-1,_=0;for(;_<c.length&&(s.lastIndex=_,u=s.exec(c),u!==null);)_=s.lastIndex,s===F?u[1]==="!--"?s=Te:u[1]!==void 0?s=De:u[2]!==void 0?(Oe.test(u[2])&&(r=RegExp("</"+u[2],"g")),s=C):u[3]!==void 0&&(s=C):s===C?u[0]===">"?(s=r??F,d=-1):u[1]===void 0?d=-2:(d=s.lastIndex-u[2].length,p=u[1],s=u[3]===void 0?C:u[3]==='"'?Re:Ne):s===Re||s===Ne?s=C:s===Te||s===De?s=F:(s=C,r=void 0);let h=s===C&&a[l+1].startsWith("/>")?" ":"";n+=s===F?c+ht:d>=0?(o.push(p),c.slice(0,d)+ze+c.slice(d)+A+h):c+A+(d===-2?l:h)}return[Me(a,n+(a[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),o]},Y=class a{constructor({strings:e,_$litType$:t},o){let r;this.parts=[];let n=0,s=0,l=e.length-1,c=this.parts,[p,u]=mt(e,t);if(this.el=a.createElement(p,o),j.currentNode=this.el.content,t===2||t===3){let d=this.el.content.firstChild;d.replaceWith(...d.childNodes)}for(;(r=j.nextNode())!==null&&c.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let d of r.getAttributeNames())if(d.endsWith(ze)){let _=u[s++],h=r.getAttribute(d).split(A),b=/([.?@])?(.*)/.exec(_);c.push({type:1,index:n,name:b[2],strings:h,ctor:b[1]==="."?_e:b[1]==="?"?he:b[1]==="@"?ge:L}),r.removeAttribute(d)}else d.startsWith(A)&&(c.push({type:6,index:n}),r.removeAttribute(d));if(Oe.test(r.tagName)){let d=r.textContent.split(A),_=d.length-1;if(_>0){r.textContent=oe?oe.emptyScript:"";for(let h=0;h<_;h++)r.append(d[h],B()),j.nextNode(),c.push({type:2,index:++n});r.append(d[_],B())}}}else if(r.nodeType===8)if(r.data===Le)c.push({type:2,index:n});else{let d=-1;for(;(d=r.data.indexOf(A,d+1))!==-1;)c.push({type:7,index:n}),d+=A.length-1}n++}}static createElement(e,t){let o=E.createElement("template");return o.innerHTML=e,o}};function z(a,e,t=a,o){if(e===T)return e;let r=o!==void 0?t._$Co?.[o]:t._$Cl,n=W(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),n===void 0?r=void 0:(r=new n(a),r._$AT(a,t,o)),o!==void 0?(t._$Co??=[])[o]=r:t._$Cl=r),r!==void 0&&(e=z(a,r._$AS(a,e.values),r,o)),e}var ue=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:o}=this._$AD,r=(e?.creationScope??E).importNode(t,!0);j.currentNode=r;let n=j.nextNode(),s=0,l=0,c=o[0];for(;c!==void 0;){if(s===c.index){let p;c.type===2?p=new G(n,n.nextSibling,this,e):c.type===1?p=new c.ctor(n,c.name,c.strings,this,e):c.type===6&&(p=new me(n,this,e)),this._$AV.push(p),c=o[++l]}s!==c?.index&&(n=j.nextNode(),s++)}return j.currentNode=E,r}p(e){let t=0;for(let o of this._$AV)o!==void 0&&(o.strings!==void 0?(o._$AI(e,o,t),t+=o.strings.length-2):o._$AI(e[t])),t++}},G=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,o,r){this.type=2,this._$AH=g,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=o,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=z(this,e,t),W(e)?e===g||e==null||e===""?(this._$AH!==g&&this._$AR(),this._$AH=g):e!==this._$AH&&e!==T&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):gt(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==g&&W(this._$AH)?this._$AA.nextSibling.data=e:this.T(E.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:o}=e,r=typeof o=="number"?this._$AC(e):(o.el===void 0&&(o.el=Y.createElement(Me(o.h,o.h[0]),this.options)),o);if(this._$AH?._$AD===r)this._$AH.p(t);else{let n=new ue(r,this),s=n.u(this.options);n.p(t),this.T(s),this._$AH=n}}_$AC(e){let t=Pe.get(e.strings);return t===void 0&&Pe.set(e.strings,t=new Y(e)),t}k(e){be(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,o,r=0;for(let n of e)r===t.length?t.push(o=new a(this.O(B()),this.O(B()),this,this.options)):o=t[r],o._$AI(n),r++;r<t.length&&(this._$AR(o&&o._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let o=je(e).nextSibling;je(e).remove(),e=o}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},L=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,o,r,n){this.type=1,this._$AH=g,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=n,o.length>2||o[0]!==""||o[1]!==""?(this._$AH=Array(o.length-1).fill(new String),this.strings=Line truncated
|
||||||
.cal-controls {
|
.cal-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
@@ -197,9 +198,9 @@ var rt=Object.defineProperty;var at=Object.getOwnPropertyDescriptor;var x=(a,e,t
|
|||||||
.cal-pill-day { font-size: 17px; }
|
.cal-pill-day { font-size: 17px; }
|
||||||
.cal-user-filter { margin-left: 0; width: 100%; }
|
.cal-user-filter { margin-left: 0; width: 100%; }
|
||||||
}
|
}
|
||||||
`;var Ye={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",runtime_hours:"Target runtime (hours)",target_value:"Target value",baseline:"Baseline",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_every:"every {n} {unit}",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter
|
`;var Ye={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",runtime_hours:"Target runtime (hours)",target_value:"Target value",baseline:"Baseline",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_every:"every {n} {unit}",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",require_on_completion:"Require on completion",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter
|
||||||
Replace seal
|
Replace seal
|
||||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
||||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||||
.field-input {
|
.field-input {
|
||||||
@@ -210,7 +211,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
font-family: inherit; width: 100%; box-sizing: border-box;
|
font-family: inherit; width: 100%; box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.field-input:focus { outline: none; border-color: var(--primary-color); }
|
.field-input:focus { outline: none; border-color: var(--primary-color); }
|
||||||
`,Xe=k`
|
`,et=k`
|
||||||
:host {
|
:host {
|
||||||
--maint-ok-color: var(--success-color, #4caf50);
|
--maint-ok-color: var(--success-color, #4caf50);
|
||||||
--maint-due-soon-color: var(--warning-color, #ff9800);
|
--maint-due-soon-color: var(--warning-color, #ff9800);
|
||||||
@@ -1375,24 +1376,24 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; }
|
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; }
|
||||||
.stat-value { font-size: 20px; }
|
.stat-value { font-size: 20px; }
|
||||||
}
|
}
|
||||||
`;var v=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._unsub=null;this._dataLoaded=!1;this._lastConnection=null}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){this._config={...t},t.past_days&&[30,90].includes(t.past_days)?this._pastDays=t.past_days:t.window_days&&[7,14,30,365].includes(t.window_days)&&(this._windowDays=t.window_days,this._pastDays=0),typeof t.user_filter=="string"&&(this._userFilter=t.user_filter),typeof t.object_filter=="string"&&(this._objectFilter=t.object_filter)}getCardSize(){return 6}get _lang(){return this.hass?.language||"en"}disconnectedCallback(){if(super.disconnectedCallback(),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){super.updated(t),t.has("hass")&&Ze(this.hass?.locale);let o=this.hass?.language;if(o&&!Qe(o)&&Je(o).then(()=>this.requestUpdate()),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,o]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=o}catch{}}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(o=>{let r=o;this._objects=r.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}render(){if(!this.hass)return g;let t=this._lang,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.title,s=null;this._userFilter&&(s=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let l=this._config.show_object_filter!==!1&&this._objects.length>1,c=null;if(this._objectFilter){let i=this._objectFilter.toLowerCase();c=this._objects.find(P=>P.entry_id===this._objectFilter||P.object.name.toLowerCase()===i)?.entry_id??null}let p=c?this._objects.filter(i=>i.entry_id===c):this._objects,u=new Date;u.setHours(0,0,0,0);let d=this._pastDays>0,_=d?Be(p,u,this._pastDays,s):Fe(p,u,this._windowDays,s),h=K(u),b=this._windowDays===365||d,y=b?_.filter(i=>i.events.length>0):_,N=i=>{let R=`cal-status-${i.status}`,P=i.projected?"cal-event-projected":"",se=i.status==="overdue"&&i.days_until_due!=null?` (${Math.abs(i.days_until_due)}d ${f("overdue",t).toLowerCase()})`:"",M=i.projected&&i.interval_days?m`<span class="cal-event-recur">${i.interval_unit&&i.interval_unit!=="days"?`${i.interval_days} ${f("unit_"+i.interval_unit,t)}`:f("cal_every_n_days",t).replace("{n}",String(i.interval_days))}</span>`:g,U=i.schedule_type==="sensor_based",ie=U?m`<ha-icon class="cal-event-icon cal-source-sensor"
|
`;var v=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._unsub=null;this._dataLoaded=!1;this._lastConnection=null}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){this._config={...t},t.past_days&&[30,90].includes(t.past_days)?this._pastDays=t.past_days:t.window_days&&[7,14,30,365].includes(t.window_days)&&(this._windowDays=t.window_days,this._pastDays=0),typeof t.user_filter=="string"&&(this._userFilter=t.user_filter),typeof t.object_filter=="string"&&(this._objectFilter=t.object_filter)}getCardSize(){return 6}get _lang(){return this.hass?.language||"en"}disconnectedCallback(){if(super.disconnectedCallback(),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){super.updated(t),t.has("hass")&&Ze(this.hass?.locale);let o=this.hass?.language;if(o&&!Qe(o)&&Je(o).then(()=>this.requestUpdate()),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,o]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=o}catch{}}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(o=>{let r=o;this._objects=r.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}render(){if(!this.hass)return g;let t=this._lang,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.title,s=null;this._userFilter&&(s=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let l=this._config.show_object_filter!==!1&&this._objects.length>1,c=null;if(this._objectFilter){let i=this._objectFilter.toLowerCase();c=this._objects.find(P=>P.entry_id===this._objectFilter||P.object.name.toLowerCase()===i)?.entry_id??null}let p=c?this._objects.filter(i=>i.entry_id===c):this._objects,u=new Date;u.setHours(0,0,0,0);let d=this._pastDays>0,_=d?Be(p,u,this._pastDays,s):Fe(p,u,this._windowDays,s),h=K(u),b=this._windowDays===365||d,y=b?_.filter(i=>i.events.length>0):_,N=i=>{let R=`cal-status-${i.status}`,P=i.projected?"cal-event-projected":"",se=i.status==="overdue"&&i.days_until_due!=null?` (${Xe(i.days_until_due,t)})`:"",M=i.projected&&i.interval_days?f`<span class="cal-event-recur">${i.interval_unit&&i.interval_unit!=="days"?`${i.interval_days} ${m("unit_"+i.interval_unit,t)}`:m("cal_every_n_days",t).replace("{n}",String(i.interval_days))}</span>`:g,U=i.schedule_type==="sensor_based",ie=U?f`<ha-icon class="cal-event-icon cal-source-sensor"
|
||||||
title="${f("cal_source_sensor",t)}" icon="mdi:trending-up"></ha-icon>`:m`<ha-icon class="cal-event-icon cal-source-time"
|
title="${m("cal_source_sensor",t)}" icon="mdi:trending-up"></ha-icon>`:f`<ha-icon class="cal-event-icon cal-source-time"
|
||||||
title="${i.adaptive_enabled?f("cal_source_time_adaptive",t):f("cal_source_time",t)}"
|
title="${i.adaptive_enabled?m("cal_source_time_adaptive",t):m("cal_source_time",t)}"
|
||||||
icon="${i.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,le=U&&i.prediction_confidence&&i.status!=="triggered"&&!i.projected?m`<span class="cal-event-prediction cal-conf-${i.prediction_confidence}">
|
icon="${i.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,le=U&&i.prediction_confidence&&i.status!=="triggered"&&!i.projected?f`<span class="cal-event-prediction cal-conf-${i.prediction_confidence}">
|
||||||
${f("cal_predicted",t)} · ${f(`cal_confidence_${i.prediction_confidence}`,t)}
|
${m("cal_predicted",t)} · ${m(`cal_confidence_${i.prediction_confidence}`,t)}
|
||||||
</span>`:g,tt=this._stats?.budget?.currency_symbol||Ve,ot=i.history_type?f(i.history_type,t):f(i.status,t);return m`
|
</span>`:g,ot=this._stats?.budget?.currency_symbol||Ve,rt=i.history_type?m(i.history_type,t):m(i.status,t);return f`
|
||||||
<div class="cal-event ${P}"
|
<div class="cal-event ${P}"
|
||||||
@click=${()=>this._onEventClick(i)}>
|
@click=${()=>this._onEventClick(i)}>
|
||||||
${ie}
|
${ie}
|
||||||
<span class="cal-status-pill ${R}">${ot}</span>
|
<span class="cal-status-pill ${R}">${rt}</span>
|
||||||
<div class="cal-event-body">
|
<div class="cal-event-body">
|
||||||
<div class="cal-event-title">${i.object_name} · ${i.task_name}${se}</div>
|
<div class="cal-event-title">${i.object_name} · ${i.task_name}${se}</div>
|
||||||
${le}
|
${le}
|
||||||
${M}
|
${M}
|
||||||
</div>
|
</div>
|
||||||
${i.avg_cost!=null&&i.avg_cost>0?m`<span class="cal-event-cost">${i.avg_cost.toFixed(0)} ${tt}</span>`:g}
|
${i.avg_cost!=null&&i.avg_cost>0?f`<span class="cal-event-cost">${i.avg_cost.toFixed(0)} ${ot}</span>`:g}
|
||||||
</div>
|
</div>
|
||||||
`},J=i=>{let[R,P,se]=i.date.split("-").map(Number),M=new Date(R,P-1,se),U=i.date===h,ie=M.toLocaleDateString(t,{weekday:"short"}),le=M.toLocaleDateString(t,{month:"long"});return m`
|
`},J=i=>{let[R,P,se]=i.date.split("-").map(Number),M=new Date(R,P-1,se),U=i.date===h,ie=M.toLocaleDateString(t,{weekday:"short"}),le=M.toLocaleDateString(t,{month:"long"});return f`
|
||||||
<div class="cal-day-row">
|
<div class="cal-day-row">
|
||||||
<div class="cal-day-pill ${U?"cal-today":""}">
|
<div class="cal-day-pill ${U?"cal-today":""}">
|
||||||
<span class="cal-pill-weekday">${ie}</span>
|
<span class="cal-pill-weekday">${ie}</span>
|
||||||
@@ -1401,18 +1402,18 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
<div class="cal-day-content">
|
<div class="cal-day-content">
|
||||||
<div class="cal-day-header">
|
<div class="cal-day-header">
|
||||||
<span class="cal-day-month">${le}</span>
|
<span class="cal-day-month">${le}</span>
|
||||||
${U?m`<span class="cal-day-today-badge">${f("today",t)}</span>`:g}
|
${U?f`<span class="cal-day-today-badge">${m("today",t)}</span>`:g}
|
||||||
</div>
|
</div>
|
||||||
${i.events.length===0?m`<div class="cal-empty">${f("cal_no_events",t)}</div>`:i.events.map(N)}
|
${i.events.length===0?f`<div class="cal-empty">${m("cal_no_events",t)}</div>`:i.events.map(N)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`};return m`
|
`};return f`
|
||||||
<ha-card .header=${n}>
|
<ha-card .header=${n}>
|
||||||
${o||r?m`
|
${o||r?f`
|
||||||
<div class="cal-controls">
|
<div class="cal-controls">
|
||||||
${o?m`
|
${o?f`
|
||||||
<div class="cal-window-chips cal-past-chips" title="${f("cal_past_windows",t)||"Past windows"}">
|
<div class="cal-window-chips cal-past-chips" title="${m("cal_past_windows",t)||"Past windows"}">
|
||||||
${[30,90].map(i=>m`
|
${[30,90].map(i=>f`
|
||||||
<button class="cal-window-chip cal-past-chip ${this._pastDays===i?"active":""}"
|
<button class="cal-window-chip cal-past-chip ${this._pastDays===i?"active":""}"
|
||||||
@click=${()=>{this._pastDays=i}}>
|
@click=${()=>{this._pastDays=i}}>
|
||||||
−${i}d
|
−${i}d
|
||||||
@@ -1420,8 +1421,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
<span class="cal-chip-separator" aria-hidden="true">●</span>
|
<span class="cal-chip-separator" aria-hidden="true">●</span>
|
||||||
<div class="cal-window-chips" title="${f("cal_forward_windows",t)||"Forward windows"}">
|
<div class="cal-window-chips" title="${m("cal_forward_windows",t)||"Forward windows"}">
|
||||||
${[7,14,30,365].map(i=>m`
|
${[7,14,30,365].map(i=>f`
|
||||||
<button class="cal-window-chip ${this._pastDays===0&&this._windowDays===i?"active":""}"
|
<button class="cal-window-chip ${this._pastDays===0&&this._windowDays===i?"active":""}"
|
||||||
@click=${()=>{this._windowDays=i,this._pastDays=0}}>
|
@click=${()=>{this._windowDays=i,this._pastDays=0}}>
|
||||||
${i===365?"+1y":`+${i}d`}
|
${i===365?"+1y":`+${i}d`}
|
||||||
@@ -1429,32 +1430,32 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
`:g}
|
`:g}
|
||||||
${r?m`
|
${r?f`
|
||||||
<select class="cal-user-filter"
|
<select class="cal-user-filter"
|
||||||
.value=${this._userFilter}
|
.value=${this._userFilter}
|
||||||
@change=${i=>{this._userFilter=i.target.value}}>
|
@change=${i=>{this._userFilter=i.target.value}}>
|
||||||
<option value="">${f("all_users",t)}</option>
|
<option value="">${m("all_users",t)}</option>
|
||||||
<option value="current_user">${f("my_tasks",t)}</option>
|
<option value="current_user">${m("my_tasks",t)}</option>
|
||||||
</select>
|
</select>
|
||||||
`:g}
|
`:g}
|
||||||
${l?m`
|
${l?f`
|
||||||
<select class="cal-user-filter"
|
<select class="cal-user-filter"
|
||||||
.value=${c??""}
|
.value=${c??""}
|
||||||
@change=${i=>{this._objectFilter=i.target.value}}>
|
@change=${i=>{this._objectFilter=i.target.value}}>
|
||||||
<option value="">${f("all_objects",t)}</option>
|
<option value="">${m("all_objects",t)}</option>
|
||||||
${[...this._objects].sort((i,R)=>i.object.name.localeCompare(R.object.name)).map(i=>m`<option value=${i.entry_id} ?selected=${i.entry_id===c}>${i.object.name}</option>`)}
|
${[...this._objects].sort((i,R)=>i.object.name.localeCompare(R.object.name)).map(i=>f`<option value=${i.entry_id} ?selected=${i.entry_id===c}>${i.object.name}</option>`)}
|
||||||
</select>
|
</select>
|
||||||
`:g}
|
`:g}
|
||||||
</div>
|
</div>
|
||||||
`:g}
|
`:g}
|
||||||
<div class="cal-rolling">
|
<div class="cal-rolling">
|
||||||
${y.length===0&&b?m`<div class="cal-empty">${f("cal_no_events",t)}</div>`:y.map(J)}
|
${y.length===0&&b?f`<div class="cal-empty">${m("cal_no_events",t)}</div>`:y.map(J)}
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`}};v.styles=[Xe,We,k`
|
`}};v.styles=[et,We,k`
|
||||||
:host { display: block; }
|
:host { display: block; }
|
||||||
ha-card { padding: 0; overflow: hidden; }
|
ha-card { padding: 0; overflow: hidden; }
|
||||||
`],x([V({attribute:!1})],v.prototype,"hass",2),x([w()],v.prototype,"_config",2),x([w()],v.prototype,"_objects",2),x([w()],v.prototype,"_stats",2),x([w()],v.prototype,"_windowDays",2),x([w()],v.prototype,"_pastDays",2),x([w()],v.prototype,"_userFilter",2),x([w()],v.prototype,"_objectFilter",2),x([w()],v.prototype,"_unsub",2);var Tt=[{value:7,label:"Week (7 days)"},{value:14,label:"Fortnight (14 days)"},{value:30,label:"Month (30 days, default)"},{value:365,label:"Year (365 days, empty days collapsed)"}],O=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}setConfig(t){this._config={...t}}_valueChanged(t,o){let r={...this._config,[t]:o};t==="show_window_chips"&&o===!0&&delete r.show_window_chips,t==="show_user_filter"&&o===!0&&delete r.show_user_filter,t==="show_object_filter"&&o===!0&&delete r.show_object_filter,t==="title"&&(!o||typeof o=="string"&&o.trim()==="")&&delete r.title,t==="user_filter"&&o===""&&delete r.user_filter,this._config=r,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:r},bubbles:!0,composed:!0}))}render(){let t=this._config.window_days??30,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.user_filter??"",s=this._config.title??"";return m`
|
`],x([V({attribute:!1})],v.prototype,"hass",2),x([w()],v.prototype,"_config",2),x([w()],v.prototype,"_objects",2),x([w()],v.prototype,"_stats",2),x([w()],v.prototype,"_windowDays",2),x([w()],v.prototype,"_pastDays",2),x([w()],v.prototype,"_userFilter",2),x([w()],v.prototype,"_objectFilter",2),x([w()],v.prototype,"_unsub",2);var Dt=[{value:7,label:"Week (7 days)"},{value:14,label:"Fortnight (14 days)"},{value:30,label:"Month (30 days, default)"},{value:365,label:"Year (365 days, empty days collapsed)"}],O=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}setConfig(t){this._config={...t}}_valueChanged(t,o){let r={...this._config,[t]:o};t==="show_window_chips"&&o===!0&&delete r.show_window_chips,t==="show_user_filter"&&o===!0&&delete r.show_user_filter,t==="show_object_filter"&&o===!0&&delete r.show_object_filter,t==="title"&&(!o||typeof o=="string"&&o.trim()==="")&&delete r.title,t==="user_filter"&&o===""&&delete r.user_filter,this._config=r,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:r},bubbles:!0,composed:!0}))}render(){let t=this._config.window_days??30,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.user_filter??"",s=this._config.title??"";return f`
|
||||||
<div class="editor">
|
<div class="editor">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="title">Title (optional)</label>
|
<label for="title">Title (optional)</label>
|
||||||
@@ -1471,7 +1472,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
id="window"
|
id="window"
|
||||||
@change=${l=>this._valueChanged("window_days",Number(l.target.value))}
|
@change=${l=>this._valueChanged("window_days",Number(l.target.value))}
|
||||||
>
|
>
|
||||||
${Tt.map(l=>m`<option value="${l.value}" ?selected=${l.value===t}>${l.label}</option>`)}
|
${Dt.map(l=>f`<option value="${l.value}" ?selected=${l.value===t}>${l.label}</option>`)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="row toggle">
|
<div class="row toggle">
|
||||||
@@ -1545,7 +1546,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--secondary-text-color, #666);
|
color: var(--secondary-text-color, #666);
|
||||||
}
|
}
|
||||||
`,x([V({attribute:!1})],O.prototype,"hass",2),x([w()],O.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",v);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",O);var ne=window;ne.customCards=ne.customCards||[];var et="maintenance-supporter-calendar-card",Dt=ne.customCards.some(a=>a.type===et);Dt||ne.customCards.push({type:et,name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});export{v as MaintenanceCalendarCard};
|
`,x([V({attribute:!1})],O.prototype,"hass",2),x([w()],O.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",v);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",O);var ne=window;ne.customCards=ne.customCards||[];var tt="maintenance-supporter-calendar-card",Nt=ne.customCards.some(a=>a.type===tt);Nt||ne.customCards.push({type:tt,name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});export{v as MaintenanceCalendarCard};
|
||||||
/*! Bundled license information:
|
/*! Bundled license information:
|
||||||
|
|
||||||
@lit/reactive-element/css-tag.js:
|
@lit/reactive-element/css-tag.js:
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.44.1 */
|
||||||
var d="maintenance-supporter",C=`ll-strategy-dashboard-${d}`,L="hui-maintenance-supporter-strategy-editor",D="/maintenance_supporter_strategy/maintenance-dashboard-strategy.js",m=null;function k(){return m||(m=import(D)),m}async function N(){let r=await k();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await k(),document.createElement(L)}static async generate(c,h){return(await N()).generate(c,h)}};function M(){try{customElements.define(C,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===d&&r.strategyType==="dashboard")||w.customStrategies.push({type:d,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,h=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${d}`;function E(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let l of Array.from(i))t.push(l)}return null}function S(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function R(){try{let t=E("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=S(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function _(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let l=e.pop();if(i++,!l)continue;let u=l;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&h.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let b=l.children;if(b)for(let s of Array.from(b))e.push(s)}return n?!0:o?!1:a&&t<3&&R()}let A="/maintenance_supporter_strategy_shim.js",y=0,v=0;function T(){let a=Date.now();a-v<5e3||y>=3||(v=a,y+=1,import(`${A}?heal=${a}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function f(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}_()?T():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",f):f(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||f()})}catch{}})();
|
var d="maintenance-supporter",C=`ll-strategy-dashboard-${d}`,L="hui-maintenance-supporter-strategy-editor",D="/maintenance_supporter_strategy/maintenance-dashboard-strategy.js",m=null;function k(){return m||(m=import(D)),m}async function N(){let r=await k();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await k(),document.createElement(L)}static async generate(c,h){return(await N()).generate(c,h)}};function M(){try{customElements.define(C,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===d&&r.strategyType==="dashboard")||w.customStrategies.push({type:d,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,h=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${d}`;function E(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let l of Array.from(i))t.push(l)}return null}function S(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function R(){try{let t=E("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=S(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function _(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let l=e.pop();if(i++,!l)continue;let u=l;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&h.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let b=l.children;if(b)for(let s of Array.from(b))e.push(s)}return n?!0:o?!1:a&&t<3&&R()}let A="/maintenance_supporter_strategy_shim.js",y=0,v=0;function T(){let a=Date.now();a-v<5e3||y>=3||(v=a,y+=1,import(`${A}?heal=${a}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function f(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}_()?T():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",f):f(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||f()})}catch{}})();
|
||||||
+34
-34
@@ -1,56 +1,56 @@
|
|||||||
import{a as f}from"./chunk-Q7DQUCT7.js";import{a as h,b as o,d as b,e as m,f as g,g as n,h as _,i as a,k as v,s as p}from"./chunk-X7OW5OLQ.js";import{a as i}from"./chunk-PEGRBZWY.js";var s=class extends m{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return this.hass?.language||"en"}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),v(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"});this._status=t,this._localMonthly=t.monthly_budget?String(t.monthly_budget):"",this._localYearly=t.yearly_budget?String(t.yearly_budget):"",this._dirty=!1}catch(t){this._error=p(t,this._lang)}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=parseFloat(this._localMonthly),e=parseFloat(this._localYearly),r={};!isNaN(t)&&t>=0&&(r.budget_monthly=t),!isNaN(e)&&e>=0&&(r.budget_yearly=e),await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/global/update",settings:r}),await this._load()}catch(t){this._error=p(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,e=this._status;if(!e)return o`<ha-card><div class="loading">${a("loading",t)||"Loading\u2026"}</div></ha-card>`;let r=e.currency_symbol||_,l=e.monthly_budget?Math.min(100,(e.monthly_spent||0)/e.monthly_budget*100):0,d=e.yearly_budget?Math.min(100,(e.yearly_spent||0)/e.yearly_budget*100):0,u=l>=100?"danger":l>=80?"warning":"ok",y=d>=100?"danger":d>=80?"warning":"ok";return o`
|
/*! maintenance_supporter frontend 2.44.1 */
|
||||||
|
import{a as v}from"./chunk-TF44IC56.js";import{a as u,b as o,d as h,e as b,f as y,g as l,h as g,i as r,k as m,t as p}from"./chunk-RLJYCMAK.js";import{a as n}from"./chunk-KRBXISES.js";var x=80,s=class extends b{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return this.hass?.language||"en"}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"});this._status=t,this._localMonthly=t.monthly_budget?String(t.monthly_budget):"",this._localYearly=t.yearly_budget?String(t.yearly_budget):"",this._dirty=!1}catch(t){this._error=p(t,this._lang)}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=parseFloat(this._localMonthly),a=parseFloat(this._localYearly),i={};!isNaN(t)&&t>=0&&(i.budget_monthly=t),!isNaN(a)&&a>=0&&(i.budget_yearly=a),await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/global/update",settings:i}),await this._load()}catch(t){this._error=p(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,a=this._status;if(!a)return o`<ha-card><div class="loading">${r("loading",t)||"Loading\u2026"}</div></ha-card>`;let i=a.currency_symbol||g,_=a.alert_threshold_pct??x,f=[{label:r("budget_monthly",t)||"Monthly",spent:a.monthly_spent||0,budget:a.monthly_budget||0},{label:r("budget_yearly",t)||"Yearly",spent:a.yearly_spent||0,budget:a.yearly_budget||0}];return o`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span class="emoji">💰</span>
|
<span class="emoji">💰</span>
|
||||||
<span>${this._config.title||a("settings_budget",t)||"Budget"}</span>
|
<span>${this._config.title||r("settings_budget",t)||"Budget"}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="currency">${r}</span>
|
<span class="currency">${i}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this._error?o`<div class="error">${this._error}</div>`:b}
|
${this._error?o`<div class="error">${this._error}</div>`:h}
|
||||||
|
|
||||||
<div class="track">
|
${f.map(e=>{if(!(e.budget>0))return o`
|
||||||
<div class="track-label-row">
|
<div class="track spent-only">
|
||||||
<label>${a("budget_monthly",t)||"Monthly"}</label>
|
<div class="track-label-row">
|
||||||
<span class="track-numbers ${u}">
|
<label>${e.label}</label>
|
||||||
${(e.monthly_spent||0).toFixed(0)} / ${(e.monthly_budget||0).toFixed(0)} ${r}
|
<span class="track-numbers ok">${e.spent.toFixed(0)} ${i}</span>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bar"><div class="bar-fill ${u}" style="width:${l}%"></div></div>
|
`;let d=Math.min(100,Math.max(0,e.spent/e.budget*100)),c=d>=100?"danger":d>=_?"warning":"ok";return o`
|
||||||
</div>
|
<div class="track">
|
||||||
|
<div class="track-label-row">
|
||||||
<div class="track">
|
<label>${e.label}</label>
|
||||||
<div class="track-label-row">
|
<span class="track-numbers ${c}">
|
||||||
<label>${a("budget_yearly",t)||"Yearly"}</label>
|
${e.spent.toFixed(0)} / ${e.budget.toFixed(0)} ${i}
|
||||||
<span class="track-numbers ${y}">
|
</span>
|
||||||
${(e.yearly_spent||0).toFixed(0)} / ${(e.yearly_budget||0).toFixed(0)} ${r}
|
</div>
|
||||||
</span>
|
<div class="bar"><div class="bar-fill ${c}" style="width:${d}%"></div></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bar"><div class="bar-fill ${y}" style="width:${d}%"></div></div>
|
`})}
|
||||||
</div>
|
|
||||||
|
|
||||||
${this._isAdmin?o`
|
${this._isAdmin?o`
|
||||||
<div class="inputs-row">
|
<div class="inputs-row">
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<label>${a("budget_monthly_set",t)||"Set monthly"}</label>
|
<label>${r("budget_monthly_set",t)||"Set monthly"}</label>
|
||||||
<div class="input-wrap">
|
<div class="input-wrap">
|
||||||
<input type="number" min="0" step="1"
|
<input type="number" min="0" step="1"
|
||||||
.value=${this._localMonthly}
|
.value=${this._localMonthly}
|
||||||
?disabled=${this._busy}
|
?disabled=${this._busy}
|
||||||
@input=${c=>{this._localMonthly=c.target.value,this._dirty=!0}} />
|
@input=${e=>{this._localMonthly=e.target.value,this._dirty=!0}} />
|
||||||
<span class="input-suffix">${r}</span>
|
<span class="input-suffix">${i}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<label>${a("budget_yearly_set",t)||"Set yearly"}</label>
|
<label>${r("budget_yearly_set",t)||"Set yearly"}</label>
|
||||||
<div class="input-wrap">
|
<div class="input-wrap">
|
||||||
<input type="number" min="0" step="1"
|
<input type="number" min="0" step="1"
|
||||||
.value=${this._localYearly}
|
.value=${this._localYearly}
|
||||||
?disabled=${this._busy}
|
?disabled=${this._busy}
|
||||||
@input=${c=>{this._localYearly=c.target.value,this._dirty=!0}} />
|
@input=${e=>{this._localYearly=e.target.value,this._dirty=!0}} />
|
||||||
<span class="input-suffix">${r}</span>
|
<span class="input-suffix">${i}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,20 +59,20 @@ import{a as f}from"./chunk-Q7DQUCT7.js";import{a as h,b as o,d as b,e as m,f as
|
|||||||
@click=${this._save}
|
@click=${this._save}
|
||||||
?disabled=${this._busy||!this._dirty}>
|
?disabled=${this._busy||!this._dirty}>
|
||||||
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
|
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
|
||||||
${this._dirty?a("save",t)||"Save":a("saved",t)||"Saved"}
|
${this._dirty?r("save",t)||"Save":r("saved",t)||"Saved"}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn link" @click=${this._onDeepLink}>
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
${a("budget_advanced",t)||"Currency, alerts\u2026"}
|
${r("budget_advanced",t)||"Currency, alerts\u2026"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`:o`
|
`:o`
|
||||||
<button class="btn link" @click=${this._onDeepLink}>
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
${a("budget_open_panel",t)||"Open in panel"}
|
${r("budget_open_panel",t)||"Open in panel"}
|
||||||
</button>
|
</button>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`}};s.styles=[f,h`
|
`}};s.styles=[v,u`
|
||||||
.currency {
|
.currency {
|
||||||
font-size: 14px; font-weight: 600;
|
font-size: 14px; font-weight: 600;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
@@ -122,4 +122,4 @@ import{a as f}from"./chunk-Q7DQUCT7.js";import{a as h,b as o,d as b,e as m,f as
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.actions { display: flex; gap: 8px; align-items: center; }
|
.actions { display: flex; gap: 8px; align-items: center; }
|
||||||
`],i([g({attribute:!1})],s.prototype,"hass",2),i([n()],s.prototype,"_config",2),i([n()],s.prototype,"_status",2),i([n()],s.prototype,"_busy",2),i([n()],s.prototype,"_error",2),i([n()],s.prototype,"_localMonthly",2),i([n()],s.prototype,"_localYearly",2),i([n()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);window.customCards=window.customCards||[];window.customCards.push({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{s as MaintenanceBudgetSectionCard};
|
`],n([y({attribute:!1})],s.prototype,"hass",2),n([l()],s.prototype,"_config",2),n([l()],s.prototype,"_status",2),n([l()],s.prototype,"_busy",2),n([l()],s.prototype,"_error",2),n([l()],s.prototype,"_localMonthly",2),n([l()],s.prototype,"_localYearly",2),n([l()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);window.customCards=window.customCards||[];window.customCards.push({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{s as MaintenanceBudgetSectionCard};
|
||||||
+1
@@ -1 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.44.1 */
|
||||||
var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var t=(a,r,c,o)=>{for(var e=o>1?void 0:o?l(r,c):r,i=a.length-1,d;i>=0;i--)(d=a[i])&&(e=(o?d(r,c,e):d(e))||e);return o&&e&&s(r,c,e),e};var m={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},v={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"};export{t as a,m as b,v as c};
|
var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var t=(a,r,c,o)=>{for(var e=o>1?void 0:o?l(r,c):r,i=a.length-1,d;i>=0;i--)(d=a[i])&&(e=(o?d(r,c,e):d(e))||e);return o&&e&&s(r,c,e),e};var m={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},v={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"};export{t as a,m as b,v as c};
|
||||||
+5
-4
@@ -1,8 +1,9 @@
|
|||||||
var L=globalThis,M=L.ShadowRoot&&(L.ShadyCSS===void 0||L.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,W=Symbol(),ae=new WeakMap,$=class{constructor(e,t,r){if(this._$cssResult$=!0,r!==W)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(M&&e===void 0){let r=t!==void 0&&t.length===1;r&&(e=ae.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),r&&ae.set(t,e))}return e}toString(){return this.cssText}},ne=o=>new $(typeof o=="string"?o:o+"",void 0,W),U=(o,...e)=>{let t=o.length===1?o[0]:e.reduce((r,a,n)=>r+(i=>{if(i._$cssResult$===!0)return i.cssText;if(typeof i=="number")return i;throw Error("Value passed to 'css' function must be a 'css' function result: "+i+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(a)+o[n+1],o[0]);return new $(t,o,W)},ie=(o,e)=>{if(M)o.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let r=document.createElement("style"),a=L.litNonce;a!==void 0&&r.setAttribute("nonce",a),r.textContent=t.cssText,o.appendChild(r)}},G=M?o=>o:o=>o instanceof CSSStyleSheet?(e=>{let t="";for(let r of e.cssRules)t+=r.cssText;return ne(t)})(o):o;var{is:Te,defineProperty:Ne,getOwnPropertyDescriptor:je,getOwnPropertyNames:Pe,getOwnPropertySymbols:Re,getPrototypeOf:ze}=Object,q=globalThis,se=q.trustedTypes,Oe=se?se.emptyScript:"",De=q.reactiveElementPolyfillSupport,E=(o,e)=>o,C={toAttribute(o,e){switch(e){case Boolean:o=o?Oe:null;break;case Object:case Array:o=o==null?o:JSON.stringify(o)}return o},fromAttribute(o,e){let t=o;switch(e){case Boolean:t=o!==null;break;case Number:t=o===null?null:Number(o);break;case Object:case Array:try{t=JSON.parse(o)}catch{t=null}}return t}},H=(o,e)=>!Te(o,e),le={attribute:!0,type:String,converter:C,reflect:!1,useDefault:!1,hasChanged:H};Symbol.metadata??=Symbol("metadata"),q.litPropertyMetadata??=new WeakMap;var g=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=le){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let r=Symbol(),a=this.getPropertyDescriptor(e,r,t);a!==void 0&&Ne(this.prototype,e,a)}}static getPropertyDescriptor(e,t,r){let{get:a,set:n}=je(this.prototype,e)??{get(){return this[t]},set(i){this[t]=i}};return{get:a,set(i){let l=a?.call(this);n?.call(this,i),this.requestUpdate(e,l,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??le}static _$Ei(){if(this.hasOwnProperty(E("elementProperties")))return;let e=ze(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(E("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(E("properties"))){let t=this.properties,r=[...Pe(t),...Re(t)];for(let a of r)this.createProperty(a,t[a])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[r,a]of t)this.elementProperties.set(r,a)}this._$Eh=new Map;for(let[t,r]of this.elementProperties){let a=this._$Eu(t,r);a!==void 0&&this._$Eh.set(a,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let r=new Set(e.flat(1/0).reverse());for(let a of r)t.unshift(G(a))}else e!==void 0&&t.push(G(e));return t}static _$Eu(e,t){let r=t.attribute;return r===!1?void 0:typeof r=="string"?r:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let r of t.keys())this.hasOwnProperty(r)&&(e.set(r,this[r]),delete this[r]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return ie(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,r){this._$AK(e,r)}_$ET(e,t){let r=this.constructor.elementProperties.get(e),a=this.constructor._$Eu(e,r);if(a!==void 0&&r.reflect===!0){let n=(r.converter?.toAttribute!==void 0?r.converter:C).toAttribute(t,r.type);this._$Em=e,n==null?this.removeAttribute(a):this.setAttribute(a,n),thLine truncated
|
/*! maintenance_supporter frontend 2.44.1 */
|
||||||
|
var L=globalThis,M=L.ShadowRoot&&(L.ShadyCSS===void 0||L.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,W=Symbol(),ae=new WeakMap,$=class{constructor(e,t,r){if(this._$cssResult$=!0,r!==W)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(M&&e===void 0){let r=t!==void 0&&t.length===1;r&&(e=ae.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),r&&ae.set(t,e))}return e}toString(){return this.cssText}},ne=o=>new $(typeof o=="string"?o:o+"",void 0,W),U=(o,...e)=>{let t=o.length===1?o[0]:e.reduce((r,a,n)=>r+(i=>{if(i._$cssResult$===!0)return i.cssText;if(typeof i=="number")return i;throw Error("Value passed to 'css' function must be a 'css' function result: "+i+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(a)+o[n+1],o[0]);return new $(t,o,W)},ie=(o,e)=>{if(M)o.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let r=document.createElement("style"),a=L.litNonce;a!==void 0&&r.setAttribute("nonce",a),r.textContent=t.cssText,o.appendChild(r)}},G=M?o=>o:o=>o instanceof CSSStyleSheet?(e=>{let t="";for(let r of e.cssRules)t+=r.cssText;return ne(t)})(o):o;var{is:Te,defineProperty:je,getOwnPropertyDescriptor:Ne,getOwnPropertyNames:Pe,getOwnPropertySymbols:Re,getPrototypeOf:ze}=Object,q=globalThis,se=q.trustedTypes,Oe=se?se.emptyScript:"",De=q.reactiveElementPolyfillSupport,E=(o,e)=>o,C={toAttribute(o,e){switch(e){case Boolean:o=o?Oe:null;break;case Object:case Array:o=o==null?o:JSON.stringify(o)}return o},fromAttribute(o,e){let t=o;switch(e){case Boolean:t=o!==null;break;case Number:t=o===null?null:Number(o);break;case Object:case Array:try{t=JSON.parse(o)}catch{t=null}}return t}},H=(o,e)=>!Te(o,e),le={attribute:!0,type:String,converter:C,reflect:!1,useDefault:!1,hasChanged:H};Symbol.metadata??=Symbol("metadata"),q.litPropertyMetadata??=new WeakMap;var g=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=le){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let r=Symbol(),a=this.getPropertyDescriptor(e,r,t);a!==void 0&&je(this.prototype,e,a)}}static getPropertyDescriptor(e,t,r){let{get:a,set:n}=Ne(this.prototype,e)??{get(){return this[t]},set(i){this[t]=i}};return{get:a,set(i){let l=a?.call(this);n?.call(this,i),this.requestUpdate(e,l,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??le}static _$Ei(){if(this.hasOwnProperty(E("elementProperties")))return;let e=ze(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(E("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(E("properties"))){let t=this.properties,r=[...Pe(t),...Re(t)];for(let a of r)this.createProperty(a,t[a])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[r,a]of t)this.elementProperties.set(r,a)}this._$Eh=new Map;for(let[t,r]of this.elementProperties){let a=this._$Eu(t,r);a!==void 0&&this._$Eh.set(a,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let r=new Set(e.flat(1/0).reverse());for(let a of r)t.unshift(G(a))}else e!==void 0&&t.push(G(e));return t}static _$Eu(e,t){let r=t.attribute;return r===!1?void 0:typeof r=="string"?r:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let r of t.keys())this.hasOwnProperty(r)&&(e.set(r,this[r]),delete this[r]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return ie(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,r){this._$AK(e,r)}_$ET(e,t){let r=this.constructor.elementProperties.get(e),a=this.constructor._$Eu(e,r);if(a!==void 0&&r.reflect===!0){let n=(r.converter?.toAttribute!==void 0?r.converter:C).toAttribute(t,r.type);this._$Em=e,n==null?this.removeAttribute(a):this.setAttribute(a,n),thLine truncated
|
||||||
\f\r]`,T=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,pe=/-->/g,_e=/>/g,b=RegExp(`>|${V}(?:([^\\s"'>=/]+)(${V}*=${V}*(?:[^
|
\f\r]`,T=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,pe=/-->/g,_e=/>/g,b=RegExp(`>|${V}(?:([^\\s"'>=/]+)(${V}*=${V}*(?:[^
|
||||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),ue=/'/g,he=/"/g,be=/^(?:script|style|textarea|title)$/i,te=o=>(e,...t)=>({_$litType$:o,strings:e,values:t}),ot=te(1),rt=te(2),at=te(3),x=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),ge=new WeakMap,y=v.createTreeWalker(v,129);function ye(o,e){if(!ee(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return de!==void 0?de.createHTML(e):e}var Ue=(o,e)=>{let t=o.length-1,r=[],a,n=e===2?"<svg>":e===3?"<math>":"",i=T;for(let l=0;l<t;l++){let s=o[l],d,_,c=-1,h=0;for(;h<s.length&&(i.lastIndex=h,_=i.exec(s),_!==null);)h=i.lastIndex,i===T?_[1]==="!--"?i=pe:_[1]!==void 0?i=_e:_[2]!==void 0?(be.test(_[2])&&(a=RegExp("</"+_[2],"g")),i=b):_[3]!==void 0&&(i=b):i===b?_[0]===">"?(i=a??T,c=-1):_[1]===void 0?c=-2:(c=i.lastIndex-_[2].length,d=_[1],i=_[3]===void 0?b:_[3]==='"'?he:ue):i===he||i===ue?i=b:i===pe||i===_e?i=T:(i=b,a=void 0);let m=i===b&&o[l+1].startsWith("/>")?" ":"";n+=i===T?s+Le:c>=0?(r.push(d),s.slice(0,c)+me+s.slice(c)+f+m):s+f+(c===-2?l:m)}return[ye(o,n+(o[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},P=class o{constructor({strings:e,_$litType$:t},r){let a;this.parts=[];let n=0,i=0,l=e.length-1,s=this.parts,[d,_]=Ue(e,t);if(this.el=o.createElement(d,r),y.currentNode=this.el.content,t===2||t===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(a=y.nextNode())!==null&&s.length<l;){if(a.nodeType===1){if(a.hasAttributes())for(let c of a.getAttributeNames())if(c.endsWith(me)){let h=_[i++],m=a.getAttribute(c).split(f),D=/([.?@])?(.*)/.exec(h);s.push({type:1,index:n,name:D[2],strings:m,ctor:D[1]==="."?K:D[1]==="?"?Y:D[1]==="@"?J:S}),a.removeAttribute(c)}else c.startsWith(f)&&(s.push({type:6,index:n}),a.removeAttribute(c));if(be.test(a.tagName)){let c=a.textContent.split(f),h=c.length-1;if(h>0){a.textContent=I?I.emptyScript:"";for(let m=0;m<h;m++)a.append(c[m],N()),y.nextNode(),s.push({type:2,index:++n});a.append(c[h],N())}}}else if(a.nodeType===8)if(a.data===fe)s.push({type:2,index:n});else{let c=-1;for(;(c=a.data.indexOf(f,c+1))!==-1;)s.push({type:7,index:n}),c+=f.length-1}n++}}static createElement(e,t){let r=v.createElement("template");return r.innerHTML=e,r}};function k(o,e,t=o,r){if(e===x)return e;let a=r!==void 0?t._$Co?.[r]:t._$Cl,n=j(e)?void 0:e._$litDirective$;return a?.constructor!==n&&(a?._$AO?.(!1),n===void 0?a=void 0:(a=new n(o),a._$AT(o,t,r)),r!==void 0?(t._$Co??=[])[r]=a:t._$Cl=a),a!==void 0&&(e=k(o,a._$AS(o,e.values),a,r)),e}var Q=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,a=(e?.creationScope??v).importNode(t,!0);y.currentNode=a;let n=y.nextNode(),i=0,l=0,s=r[0];for(;s!==void 0;){if(i===s.index){let d;s.type===2?d=new R(n,n.nextSibling,this,e):s.type===1?d=new s.ctor(n,s.name,s.strings,this,e):s.type===6&&(d=new Z(n,this,e)),this._$AV.push(d),s=r[++l]}i!==s?.index&&(n=y.nextNode(),i++)}return y.currentNode=v,a}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},R=class o{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,a){this.type=2,this._$AH=p,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=a,this._$Cv=a?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=k(this,e,t),j(e)?e===p||e==null||e===""?(this._$AH!==p&&this._$AR(),this._$AH=p):e!==this._$AH&&e!==x&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Me(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==p&&j(this._$AH)?this._$AA.nextSibling.data=e:this.T(v.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,a=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=P.createElement(ye(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===a)this._$AH.p(t);else{let n=new Q(a,this),i=n.u(this.options);n.p(t),this.T(i),this._$AH=n}}_$AC(e){let t=ge.get(e.strings);return t===void 0&&ge.set(e.strings,t=new P(e)),t}k(e){ee(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,a=0;for(let n of e)a===t.length?t.push(r=new o(this.O(N()),this.O(N()),this,this.options)):r=t[a],r._$AI(n),a++;a<t.length&&(this._$AR(r&&r._$AB.nextSibling,a),t.length=a)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=ce(e).nextSibling;ce(e).remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},S=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,a,n){this.type=1,this._$AH=p,this._$AN=void 0,this.element=e,this.name=t,this._$AM=a,this.options=n,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):thisLine truncated
|
\f\r"'\`<>=]|("|')|))|$)`,"g"),ue=/'/g,he=/"/g,be=/^(?:script|style|textarea|title)$/i,te=o=>(e,...t)=>({_$litType$:o,strings:e,values:t}),ot=te(1),rt=te(2),at=te(3),x=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),ge=new WeakMap,y=v.createTreeWalker(v,129);function ye(o,e){if(!ee(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return de!==void 0?de.createHTML(e):e}var Ue=(o,e)=>{let t=o.length-1,r=[],a,n=e===2?"<svg>":e===3?"<math>":"",i=T;for(let l=0;l<t;l++){let s=o[l],d,_,c=-1,h=0;for(;h<s.length&&(i.lastIndex=h,_=i.exec(s),_!==null);)h=i.lastIndex,i===T?_[1]==="!--"?i=pe:_[1]!==void 0?i=_e:_[2]!==void 0?(be.test(_[2])&&(a=RegExp("</"+_[2],"g")),i=b):_[3]!==void 0&&(i=b):i===b?_[0]===">"?(i=a??T,c=-1):_[1]===void 0?c=-2:(c=i.lastIndex-_[2].length,d=_[1],i=_[3]===void 0?b:_[3]==='"'?he:ue):i===he||i===ue?i=b:i===pe||i===_e?i=T:(i=b,a=void 0);let m=i===b&&o[l+1].startsWith("/>")?" ":"";n+=i===T?s+Le:c>=0?(r.push(d),s.slice(0,c)+me+s.slice(c)+f+m):s+f+(c===-2?l:m)}return[ye(o,n+(o[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},P=class o{constructor({strings:e,_$litType$:t},r){let a;this.parts=[];let n=0,i=0,l=e.length-1,s=this.parts,[d,_]=Ue(e,t);if(this.el=o.createElement(d,r),y.currentNode=this.el.content,t===2||t===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(a=y.nextNode())!==null&&s.length<l;){if(a.nodeType===1){if(a.hasAttributes())for(let c of a.getAttributeNames())if(c.endsWith(me)){let h=_[i++],m=a.getAttribute(c).split(f),D=/([.?@])?(.*)/.exec(h);s.push({type:1,index:n,name:D[2],strings:m,ctor:D[1]==="."?K:D[1]==="?"?Y:D[1]==="@"?J:S}),a.removeAttribute(c)}else c.startsWith(f)&&(s.push({type:6,index:n}),a.removeAttribute(c));if(be.test(a.tagName)){let c=a.textContent.split(f),h=c.length-1;if(h>0){a.textContent=I?I.emptyScript:"";for(let m=0;m<h;m++)a.append(c[m],j()),y.nextNode(),s.push({type:2,index:++n});a.append(c[h],j())}}}else if(a.nodeType===8)if(a.data===fe)s.push({type:2,index:n});else{let c=-1;for(;(c=a.data.indexOf(f,c+1))!==-1;)s.push({type:7,index:n}),c+=f.length-1}n++}}static createElement(e,t){let r=v.createElement("template");return r.innerHTML=e,r}};function k(o,e,t=o,r){if(e===x)return e;let a=r!==void 0?t._$Co?.[r]:t._$Cl,n=N(e)?void 0:e._$litDirective$;return a?.constructor!==n&&(a?._$AO?.(!1),n===void 0?a=void 0:(a=new n(o),a._$AT(o,t,r)),r!==void 0?(t._$Co??=[])[r]=a:t._$Cl=a),a!==void 0&&(e=k(o,a._$AS(o,e.values),a,r)),e}var Q=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,a=(e?.creationScope??v).importNode(t,!0);y.currentNode=a;let n=y.nextNode(),i=0,l=0,s=r[0];for(;s!==void 0;){if(i===s.index){let d;s.type===2?d=new R(n,n.nextSibling,this,e):s.type===1?d=new s.ctor(n,s.name,s.strings,this,e):s.type===6&&(d=new Z(n,this,e)),this._$AV.push(d),s=r[++l]}i!==s?.index&&(n=y.nextNode(),i++)}return y.currentNode=v,a}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},R=class o{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,a){this.type=2,this._$AH=p,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=a,this._$Cv=a?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=k(this,e,t),N(e)?e===p||e==null||e===""?(this._$AH!==p&&this._$AR(),this._$AH=p):e!==this._$AH&&e!==x&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Me(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==p&&N(this._$AH)?this._$AA.nextSibling.data=e:this.T(v.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,a=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=P.createElement(ye(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===a)this._$AH.p(t);else{let n=new Q(a,this),i=n.u(this.options);n.p(t),this.T(i),this._$AH=n}}_$AC(e){let t=ge.get(e.strings);return t===void 0&&ge.set(e.strings,t=new P(e)),t}k(e){ee(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,a=0;for(let n of e)a===t.length?t.push(r=new o(this.O(j()),this.O(j()),this,this.options)):r=t[a],r._$AI(n),a++;a<t.length&&(this._$AR(r&&r._$AB.nextSibling,a),t.length=a)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=ce(e).nextSibling;ce(e).remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},S=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,a,n){this.type=1,this._$AH=p,this._$AN=void 0,this.element=e,this.name=t,this._$AM=a,this.options=n,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):thisLine truncated
|
||||||
Replace seal
|
Replace seal
|
||||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
||||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||||
.field-input {
|
.field-input {
|
||||||
@@ -1178,7 +1179,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; }
|
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; }
|
||||||
.stat-value { font-size: 20px; }
|
.stat-value { font-size: 20px; }
|
||||||
}
|
}
|
||||||
`;var Ke={name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",group_name:"name",group_description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_for_minutes:"trigger_for_minutes"};function Ye(o,e){let t=Ke[o];if(!t)return o;let r=u(t,e);return r&&r!==t?r:o}function Je(o){let t=o.match(/data\['([^']+)'\]/)?.[1],r;return(r=o.match(/length of value must be at most (\d+)/))?{field:t,rule:"too_long",param:r[1]}:(r=o.match(/length of value must be at least (\d+)/))?{field:t,rule:"too_short",param:r[1]}:(r=o.match(/value must be at most (\S+)/))?{field:t,rule:"value_too_high",param:r[1]}:(r=o.match(/value must be at least (\S+)/))?{field:t,rule:"value_too_low",param:r[1]}:/required key not provided/.test(o)?{field:t,rule:"required"}:(r=o.match(/expected (\w+)/))?{field:t,rule:"wrong_type",param:r[1]}:/value must be one of/.test(o)?{field:t,rule:"invalid_choice"}:/not a valid value/.test(o)?{field:t,rule:"invalid_value"}:{field:t,rule:"unknown"}}function so(o,e,t){if(t=t??u("action_error",e),typeof o=="string")return o;if(typeof o!="object"||o===null)return t;let r=o,a=r.message||r.error?.message||"";if(!a)return t;let n=Je(a),i=n.field?Ye(n.field,e):"",l=s=>u(s,e).replace("{field}",i).replace("{n}",n.param??"");switch(n.rule){case"too_long":return l("err_too_long");case"too_short":return l("err_too_short");case"value_too_high":return l("err_value_too_high");case"value_too_low":return l("err_value_too_low");case"required":return l("err_required");case"wrong_type":return l("err_wrong_type").replace("{type}",n.param??"");case"invalid_choice":return l("err_invalid_choice");case"invalid_value":return l("err_invalid_value");default:return a||t}}export{U as a,ot as b,rt as c,p as d,A as e,xe as f,vt as g,Yt as h,u as i,Jt as j,Zt as k,ke as l,Xt as m,Ae as n,eo as o,to as p,oo as q,ro as r,so as s};
|
`;var Ke={name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",group_name:"name",group_description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_for_minutes:"trigger_for_minutes"};function Ye(o,e){let t=Ke[o];if(!t)return o;let r=u(t,e);return r&&r!==t?r:o}function Je(o){let t=o.match(/data\['([^']+)'\]/)?.[1],r;return(r=o.match(/length of value must be at most (\d+)/))?{field:t,rule:"too_long",param:r[1]}:(r=o.match(/length of value must be at least (\d+)/))?{field:t,rule:"too_short",param:r[1]}:(r=o.match(/value must be at most (\S+)/))?{field:t,rule:"value_too_high",param:r[1]}:(r=o.match(/value must be at least (\S+)/))?{field:t,rule:"value_too_low",param:r[1]}:/required key not provided/.test(o)?{field:t,rule:"required"}:(r=o.match(/expected (\w+)/))?{field:t,rule:"wrong_type",param:r[1]}:/value must be one of/.test(o)?{field:t,rule:"invalid_choice"}:/not a valid value/.test(o)?{field:t,rule:"invalid_value"}:{field:t,rule:"unknown"}}function so(o,e,t){if(t=t??u("action_error",e),typeof o=="string")return o;if(typeof o!="object"||o===null)return t;let r=o,a=r.message||r.error?.message||"";if(!a)return t;let n=Je(a),i=n.field?Ye(n.field,e):"",l=s=>u(s,e).replace("{field}",i).replace("{n}",n.param??"");switch(n.rule){case"too_long":return l("err_too_long");case"too_short":return l("err_too_short");case"value_too_high":return l("err_value_too_high");case"value_too_low":return l("err_value_too_low");case"required":return l("err_required");case"wrong_type":return l("err_wrong_type").replace("{type}",n.param??"");case"invalid_choice":return l("err_invalid_choice");case"invalid_value":return l("err_invalid_value");default:return a||t}}export{U as a,ot as b,rt as c,p as d,A as e,xe as f,vt as g,Yt as h,u as i,Jt as j,Zt as k,ke as l,Xt as m,Se as n,Ae as o,eo as p,to as q,oo as r,ro as s,so as t};
|
||||||
/*! Bundled license information:
|
/*! Bundled license information:
|
||||||
|
|
||||||
@lit/reactive-element/css-tag.js:
|
@lit/reactive-element/css-tag.js:
|
||||||
Loaded 100 of 217 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user