From a4c0fabbd602c60b0696321d7701a7cb31e4f571 Mon Sep 17 00:00:00 2001 From: Jeffrey Johnson Date: Thu, 18 Jun 2026 18:16:06 -0700 Subject: [PATCH 01/10] fix(a11y): i18n strings and hide decorative icons in ai-action-confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire useTranslations("aiActionConfirmation") and migrate every user-facing string (action labels, descriptions, and Deny/Allow/Working…/Done/Denied buttons + status) to t(). Mark all decorative ActionIcon glyphs and the done/denied status icons aria-hidden="true" so screen readers announce the real button/status text instead of icon noise. Adds the aiActionConfirmation namespace to all 14 locale files with genuine translations. WCAG 2.2 AA 4.1.2 Name, Role, Value Refs #1202 --- web/messages/de.json | 51 ++++++++ web/messages/en.json | 51 ++++++++ web/messages/es.json | 51 ++++++++ web/messages/fr.json | 51 ++++++++ web/messages/it.json | 51 ++++++++ web/messages/ja.json | 51 ++++++++ web/messages/ko.json | 51 ++++++++ web/messages/nl.json | 51 ++++++++ web/messages/pl.json | 51 ++++++++ web/messages/pt.json | 51 ++++++++ web/messages/ru.json | 51 ++++++++ web/messages/sv.json | 51 ++++++++ web/messages/tr.json | 51 ++++++++ web/messages/zh.json | 51 ++++++++ web/src/components/ai-action-confirmation.tsx | 114 +++++++++--------- 15 files changed, 774 insertions(+), 54 deletions(-) diff --git a/web/messages/de.json b/web/messages/de.json index f4460007b..b59dcd040 100644 --- a/web/messages/de.json +++ b/web/messages/de.json @@ -1002,6 +1002,57 @@ "rotation": "Drehung" } }, + "aiActionConfirmation": { + "deny": "Ablehnen", + "allow": "Zulassen", + "working": "Wird ausgeführt…", + "done": "Fertig", + "denied": "Abgelehnt", + "noChanges": "keine Änderungen", + "noValues": "keine Werte", + "noChangesSpecified": "Keine Änderungen angegeben.", + "openEnd": "offen", + "label": { + "installPlugin": "Plugin installieren: {id}", + "updatePluginConfig": "Plugin konfigurieren: {id}", + "updatePlugin": "Plugin aktualisieren: {id}", + "enablePlugin": "Plugin aktivieren: {id}", + "disablePlugin": "Plugin deaktivieren: {id}", + "uninstallPlugin": "Plugin deinstallieren: {id}", + "updateSetting": "Einstellung ändern: {category}", + "createCollection": "Sammlung erstellen: \"{name}\"", + "updateCollection": "Sammlung aktualisieren", + "createSchedule": "Zeitplan erstellen", + "updateSchedule": "Zeitplan aktualisieren", + "deleteSchedule": "Zeitplan löschen", + "triggerSystemUpdate": "Systemaktualisierung" + }, + "description": { + "installPlugin": "Installiert \"{id}\" aus der offiziellen Registry.", + "installPluginEnable": "Installiert \"{id}\" aus der offiziellen Registry und aktiviert es.", + "updatePluginConfig": "Aktualisiert die Konfiguration von \"{id}\": {keys}.", + "updatePlugin": "Lädt die neueste Registry-Version von \"{id}\" herunter und installiert sie.", + "enablePlugin": "Aktiviert \"{id}\", damit es Daten für deine Boards bereitstellen kann.", + "disablePlugin": "Deaktiviert \"{id}\", ohne es zu entfernen. Es kann später wieder aktiviert werden.", + "uninstallPlugin": "Entfernt \"{id}\" dauerhaft. Dies kann nicht rückgängig gemacht werden.", + "updateSetting": "Setzt {values} in den {category}-Einstellungen.", + "createCollection": "Erstellt eine Sammlung mit {count, plural, one {# Seite} other {# Seiten}}, die alle {interval}s wechselt.", + "createSchedule": "Zeigt Seite \"{page}\" von {time} an {days}-Tagen.", + "deleteSchedule": "Entfernt den Zeitplan \"{id}\" dauerhaft. Dies kann nicht rückgängig gemacht werden.", + "triggerSystemUpdate": "Lädt die neueste FiestaBoard-Aktualisierung herunter und installiert sie. Das System startet kurz neu." + }, + "change": { + "rename": "umbenennen in \"{name}\"", + "setPages": "{count, plural, one {# Seite} other {# Seiten}} festlegen", + "interval": "Intervall → {interval}s", + "page": "Seite → {page}", + "start": "Start → {start}", + "end": "Ende → {end}", + "days": "Tage → {days}", + "enable": "aktivieren", + "disable": "deaktivieren" + } + }, "plainTextEditor": { "placeholder": "Vorlagentext eingeben...", "lineCount": "{current} / {total} Zeilen", diff --git a/web/messages/en.json b/web/messages/en.json index 8d1112bb2..4cdbf6fb0 100644 --- a/web/messages/en.json +++ b/web/messages/en.json @@ -959,6 +959,57 @@ "rotation": "Rotation" } }, + "aiActionConfirmation": { + "deny": "Deny", + "allow": "Allow", + "working": "Working…", + "done": "Done", + "denied": "Denied", + "noChanges": "no changes", + "noValues": "no values", + "noChangesSpecified": "No changes specified.", + "openEnd": "open", + "label": { + "installPlugin": "Install plugin: {id}", + "updatePluginConfig": "Configure plugin: {id}", + "updatePlugin": "Update plugin: {id}", + "enablePlugin": "Enable plugin: {id}", + "disablePlugin": "Disable plugin: {id}", + "uninstallPlugin": "Uninstall plugin: {id}", + "updateSetting": "Change setting: {category}", + "createCollection": "Create collection: \"{name}\"", + "updateCollection": "Update collection", + "createSchedule": "Create schedule", + "updateSchedule": "Update schedule", + "deleteSchedule": "Delete schedule", + "triggerSystemUpdate": "System update" + }, + "description": { + "installPlugin": "Installs \"{id}\" from the official registry.", + "installPluginEnable": "Installs \"{id}\" from the official registry and enables it.", + "updatePluginConfig": "Updates configuration for \"{id}\": {keys}.", + "updatePlugin": "Downloads and installs the latest registry version of \"{id}\".", + "enablePlugin": "Enables \"{id}\" so it can provide data to your boards.", + "disablePlugin": "Disables \"{id}\" without removing it. It can be re-enabled later.", + "uninstallPlugin": "Permanently removes \"{id}\". This cannot be undone.", + "updateSetting": "Sets {values} in {category} settings.", + "createCollection": "Creates a collection with {count, plural, one {# page} other {# pages}}, rotating every {interval}s.", + "createSchedule": "Shows page \"{page}\" from {time} on {days} days.", + "deleteSchedule": "Permanently removes schedule \"{id}\". This cannot be undone.", + "triggerSystemUpdate": "Downloads and installs the latest FiestaBoard update. The system will restart briefly." + }, + "change": { + "rename": "rename to \"{name}\"", + "setPages": "set {count, plural, one {# page} other {# pages}}", + "interval": "interval → {interval}s", + "page": "page → {page}", + "start": "start → {start}", + "end": "end → {end}", + "days": "days → {days}", + "enable": "enable", + "disable": "disable" + } + }, "plainTextEditor": { "placeholder": "Type your template text...", "lineCount": "{current} / {total} lines", diff --git a/web/messages/es.json b/web/messages/es.json index 642680444..b9ba26eac 100644 --- a/web/messages/es.json +++ b/web/messages/es.json @@ -1002,6 +1002,57 @@ "rotation": "Rotación" } }, + "aiActionConfirmation": { + "deny": "Denegar", + "allow": "Permitir", + "working": "Trabajando…", + "done": "Hecho", + "denied": "Denegado", + "noChanges": "sin cambios", + "noValues": "sin valores", + "noChangesSpecified": "No se especificaron cambios.", + "openEnd": "abierto", + "label": { + "installPlugin": "Instalar complemento: {id}", + "updatePluginConfig": "Configurar complemento: {id}", + "updatePlugin": "Actualizar complemento: {id}", + "enablePlugin": "Activar complemento: {id}", + "disablePlugin": "Desactivar complemento: {id}", + "uninstallPlugin": "Desinstalar complemento: {id}", + "updateSetting": "Cambiar ajuste: {category}", + "createCollection": "Crear colección: \"{name}\"", + "updateCollection": "Actualizar colección", + "createSchedule": "Crear programación", + "updateSchedule": "Actualizar programación", + "deleteSchedule": "Eliminar programación", + "triggerSystemUpdate": "Actualización del sistema" + }, + "description": { + "installPlugin": "Instala \"{id}\" desde el registro oficial.", + "installPluginEnable": "Instala \"{id}\" desde el registro oficial y lo activa.", + "updatePluginConfig": "Actualiza la configuración de \"{id}\": {keys}.", + "updatePlugin": "Descarga e instala la última versión del registro de \"{id}\".", + "enablePlugin": "Activa \"{id}\" para que pueda proporcionar datos a tus tableros.", + "disablePlugin": "Desactiva \"{id}\" sin eliminarlo. Se puede volver a activar más tarde.", + "uninstallPlugin": "Elimina \"{id}\" de forma permanente. Esto no se puede deshacer.", + "updateSetting": "Establece {values} en los ajustes de {category}.", + "createCollection": "Crea una colección con {count, plural, one {# página} other {# páginas}}, rotando cada {interval}s.", + "createSchedule": "Muestra la página \"{page}\" de {time} los días {days}.", + "deleteSchedule": "Elimina permanentemente la programación \"{id}\". Esto no se puede deshacer.", + "triggerSystemUpdate": "Descarga e instala la última actualización de FiestaBoard. El sistema se reiniciará brevemente." + }, + "change": { + "rename": "renombrar a \"{name}\"", + "setPages": "establecer {count, plural, one {# página} other {# páginas}}", + "interval": "intervalo → {interval}s", + "page": "página → {page}", + "start": "inicio → {start}", + "end": "fin → {end}", + "days": "días → {days}", + "enable": "activar", + "disable": "desactivar" + } + }, "plainTextEditor": { "placeholder": "Escribe el texto de tu plantilla...", "lineCount": "{current} / {total} líneas", diff --git a/web/messages/fr.json b/web/messages/fr.json index 7a4333cba..8097474db 100644 --- a/web/messages/fr.json +++ b/web/messages/fr.json @@ -1002,6 +1002,57 @@ "rotation": "Rotation" } }, + "aiActionConfirmation": { + "deny": "Refuser", + "allow": "Autoriser", + "working": "En cours…", + "done": "Terminé", + "denied": "Refusé", + "noChanges": "aucun changement", + "noValues": "aucune valeur", + "noChangesSpecified": "Aucun changement spécifié.", + "openEnd": "ouvert", + "label": { + "installPlugin": "Installer le module : {id}", + "updatePluginConfig": "Configurer le module : {id}", + "updatePlugin": "Mettre à jour le module : {id}", + "enablePlugin": "Activer le module : {id}", + "disablePlugin": "Désactiver le module : {id}", + "uninstallPlugin": "Désinstaller le module : {id}", + "updateSetting": "Modifier le paramètre : {category}", + "createCollection": "Créer une collection : \"{name}\"", + "updateCollection": "Mettre à jour la collection", + "createSchedule": "Créer une programmation", + "updateSchedule": "Mettre à jour la programmation", + "deleteSchedule": "Supprimer la programmation", + "triggerSystemUpdate": "Mise à jour du système" + }, + "description": { + "installPlugin": "Installe \"{id}\" depuis le registre officiel.", + "installPluginEnable": "Installe \"{id}\" depuis le registre officiel et l'active.", + "updatePluginConfig": "Met à jour la configuration de \"{id}\" : {keys}.", + "updatePlugin": "Télécharge et installe la dernière version du registre de \"{id}\".", + "enablePlugin": "Active \"{id}\" pour qu'il puisse fournir des données à vos tableaux.", + "disablePlugin": "Désactive \"{id}\" sans le supprimer. Il peut être réactivé plus tard.", + "uninstallPlugin": "Supprime définitivement \"{id}\". Cette action est irréversible.", + "updateSetting": "Définit {values} dans les paramètres {category}.", + "createCollection": "Crée une collection avec {count, plural, one {# page} other {# pages}}, en alternant toutes les {interval}s.", + "createSchedule": "Affiche la page \"{page}\" de {time} les jours {days}.", + "deleteSchedule": "Supprime définitivement la programmation \"{id}\". Cette action est irréversible.", + "triggerSystemUpdate": "Télécharge et installe la dernière mise à jour de FiestaBoard. Le système redémarrera brièvement." + }, + "change": { + "rename": "renommer en \"{name}\"", + "setPages": "définir {count, plural, one {# page} other {# pages}}", + "interval": "intervalle → {interval}s", + "page": "page → {page}", + "start": "début → {start}", + "end": "fin → {end}", + "days": "jours → {days}", + "enable": "activer", + "disable": "désactiver" + } + }, "plainTextEditor": { "placeholder": "Tapez votre texte de modèle...", "lineCount": "{current} / {total} lignes", diff --git a/web/messages/it.json b/web/messages/it.json index 7f0406044..107c337f1 100644 --- a/web/messages/it.json +++ b/web/messages/it.json @@ -1002,6 +1002,57 @@ "rotation": "Rotazione" } }, + "aiActionConfirmation": { + "deny": "Nega", + "allow": "Consenti", + "working": "In corso…", + "done": "Fatto", + "denied": "Negato", + "noChanges": "nessuna modifica", + "noValues": "nessun valore", + "noChangesSpecified": "Nessuna modifica specificata.", + "openEnd": "aperto", + "label": { + "installPlugin": "Installa plugin: {id}", + "updatePluginConfig": "Configura plugin: {id}", + "updatePlugin": "Aggiorna plugin: {id}", + "enablePlugin": "Abilita plugin: {id}", + "disablePlugin": "Disabilita plugin: {id}", + "uninstallPlugin": "Disinstalla plugin: {id}", + "updateSetting": "Cambia impostazione: {category}", + "createCollection": "Crea collezione: \"{name}\"", + "updateCollection": "Aggiorna collezione", + "createSchedule": "Crea pianificazione", + "updateSchedule": "Aggiorna pianificazione", + "deleteSchedule": "Elimina pianificazione", + "triggerSystemUpdate": "Aggiornamento di sistema" + }, + "description": { + "installPlugin": "Installa \"{id}\" dal registro ufficiale.", + "installPluginEnable": "Installa \"{id}\" dal registro ufficiale e lo abilita.", + "updatePluginConfig": "Aggiorna la configurazione di \"{id}\": {keys}.", + "updatePlugin": "Scarica e installa l'ultima versione del registro di \"{id}\".", + "enablePlugin": "Abilita \"{id}\" affinché possa fornire dati alle tue board.", + "disablePlugin": "Disabilita \"{id}\" senza rimuoverlo. Può essere riabilitato in seguito.", + "uninstallPlugin": "Rimuove definitivamente \"{id}\". Questa azione non può essere annullata.", + "updateSetting": "Imposta {values} nelle impostazioni {category}.", + "createCollection": "Crea una collezione con {count, plural, one {# pagina} other {# pagine}}, alternando ogni {interval}s.", + "createSchedule": "Mostra la pagina \"{page}\" dalle {time} nei giorni {days}.", + "deleteSchedule": "Rimuove definitivamente la pianificazione \"{id}\". Questa azione non può essere annullata.", + "triggerSystemUpdate": "Scarica e installa l'ultimo aggiornamento di FiestaBoard. Il sistema si riavvierà brevemente." + }, + "change": { + "rename": "rinomina in \"{name}\"", + "setPages": "imposta {count, plural, one {# pagina} other {# pagine}}", + "interval": "intervallo → {interval}s", + "page": "pagina → {page}", + "start": "inizio → {start}", + "end": "fine → {end}", + "days": "giorni → {days}", + "enable": "abilita", + "disable": "disabilita" + } + }, "plainTextEditor": { "placeholder": "Scrivi il testo del template...", "lineCount": "{current} / {total} righe", diff --git a/web/messages/ja.json b/web/messages/ja.json index aca64a8d4..aa1ff80bb 100644 --- a/web/messages/ja.json +++ b/web/messages/ja.json @@ -1002,6 +1002,57 @@ "rotation": "ローテーション" } }, + "aiActionConfirmation": { + "deny": "拒否", + "allow": "許可", + "working": "実行中…", + "done": "完了", + "denied": "拒否しました", + "noChanges": "変更なし", + "noValues": "値なし", + "noChangesSpecified": "変更が指定されていません。", + "openEnd": "未指定", + "label": { + "installPlugin": "プラグインをインストール: {id}", + "updatePluginConfig": "プラグインを設定: {id}", + "updatePlugin": "プラグインを更新: {id}", + "enablePlugin": "プラグインを有効化: {id}", + "disablePlugin": "プラグインを無効化: {id}", + "uninstallPlugin": "プラグインをアンインストール: {id}", + "updateSetting": "設定を変更: {category}", + "createCollection": "コレクションを作成: \"{name}\"", + "updateCollection": "コレクションを更新", + "createSchedule": "スケジュールを作成", + "updateSchedule": "スケジュールを更新", + "deleteSchedule": "スケジュールを削除", + "triggerSystemUpdate": "システム更新" + }, + "description": { + "installPlugin": "公式レジストリから「{id}」をインストールします。", + "installPluginEnable": "公式レジストリから「{id}」をインストールして有効化します。", + "updatePluginConfig": "「{id}」の設定を更新します: {keys}。", + "updatePlugin": "「{id}」の最新のレジストリ版をダウンロードしてインストールします。", + "enablePlugin": "「{id}」を有効にして、ボードにデータを提供できるようにします。", + "disablePlugin": "「{id}」を削除せずに無効化します。後で再び有効化できます。", + "uninstallPlugin": "「{id}」を完全に削除します。この操作は元に戻せません。", + "updateSetting": "{category} 設定に {values} を設定します。", + "createCollection": "{count, plural, other {# ページ}}のコレクションを作成し、{interval}秒ごとに切り替えます。", + "createSchedule": "「{page}」ページを {days} の日に {time} に表示します。", + "deleteSchedule": "スケジュール「{id}」を完全に削除します。この操作は元に戻せません。", + "triggerSystemUpdate": "最新の FiestaBoard アップデートをダウンロードしてインストールします。システムは短時間再起動します。" + }, + "change": { + "rename": "「{name}」に名前を変更", + "setPages": "{count, plural, other {# ページ}}を設定", + "interval": "間隔 → {interval}秒", + "page": "ページ → {page}", + "start": "開始 → {start}", + "end": "終了 → {end}", + "days": "曜日 → {days}", + "enable": "有効化", + "disable": "無効化" + } + }, "plainTextEditor": { "placeholder": "テンプレートテキストを入力...", "lineCount": "{current} / {total} 行", diff --git a/web/messages/ko.json b/web/messages/ko.json index 606105476..724e30773 100644 --- a/web/messages/ko.json +++ b/web/messages/ko.json @@ -1002,6 +1002,57 @@ "rotation": "회전" } }, + "aiActionConfirmation": { + "deny": "거부", + "allow": "허용", + "working": "처리 중…", + "done": "완료", + "denied": "거부됨", + "noChanges": "변경 없음", + "noValues": "값 없음", + "noChangesSpecified": "지정된 변경 사항이 없습니다.", + "openEnd": "미지정", + "label": { + "installPlugin": "플러그인 설치: {id}", + "updatePluginConfig": "플러그인 구성: {id}", + "updatePlugin": "플러그인 업데이트: {id}", + "enablePlugin": "플러그인 활성화: {id}", + "disablePlugin": "플러그인 비활성화: {id}", + "uninstallPlugin": "플러그인 제거: {id}", + "updateSetting": "설정 변경: {category}", + "createCollection": "컬렉션 만들기: \"{name}\"", + "updateCollection": "컬렉션 업데이트", + "createSchedule": "일정 만들기", + "updateSchedule": "일정 업데이트", + "deleteSchedule": "일정 삭제", + "triggerSystemUpdate": "시스템 업데이트" + }, + "description": { + "installPlugin": "공식 레지스트리에서 \"{id}\"을(를) 설치합니다.", + "installPluginEnable": "공식 레지스트리에서 \"{id}\"을(를) 설치하고 활성화합니다.", + "updatePluginConfig": "\"{id}\"의 구성을 업데이트합니다: {keys}.", + "updatePlugin": "\"{id}\"의 최신 레지스트리 버전을 다운로드하여 설치합니다.", + "enablePlugin": "\"{id}\"을(를) 활성화하여 보드에 데이터를 제공할 수 있도록 합니다.", + "disablePlugin": "\"{id}\"을(를) 제거하지 않고 비활성화합니다. 나중에 다시 활성화할 수 있습니다.", + "uninstallPlugin": "\"{id}\"을(를) 영구적으로 제거합니다. 이 작업은 취소할 수 없습니다.", + "updateSetting": "{category} 설정에서 {values}을(를) 설정합니다.", + "createCollection": "{count, plural, other {# 페이지}}로 컬렉션을 만들고 {interval}초마다 전환합니다.", + "createSchedule": "\"{page}\" 페이지를 {days} 요일에 {time}에 표시합니다.", + "deleteSchedule": "일정 \"{id}\"을(를) 영구적으로 제거합니다. 이 작업은 취소할 수 없습니다.", + "triggerSystemUpdate": "최신 FiestaBoard 업데이트를 다운로드하여 설치합니다. 시스템이 잠시 다시 시작됩니다." + }, + "change": { + "rename": "\"{name}\"(으)로 이름 변경", + "setPages": "{count, plural, other {# 페이지}} 설정", + "interval": "간격 → {interval}초", + "page": "페이지 → {page}", + "start": "시작 → {start}", + "end": "종료 → {end}", + "days": "요일 → {days}", + "enable": "활성화", + "disable": "비활성화" + } + }, "plainTextEditor": { "placeholder": "템플릿 텍스트를 입력하세요...", "lineCount": "{current} / {total} 줄", diff --git a/web/messages/nl.json b/web/messages/nl.json index 0fecd1dcc..03345ed60 100644 --- a/web/messages/nl.json +++ b/web/messages/nl.json @@ -1002,6 +1002,57 @@ "rotation": "Rotatie" } }, + "aiActionConfirmation": { + "deny": "Weigeren", + "allow": "Toestaan", + "working": "Bezig…", + "done": "Klaar", + "denied": "Geweigerd", + "noChanges": "geen wijzigingen", + "noValues": "geen waarden", + "noChangesSpecified": "Geen wijzigingen opgegeven.", + "openEnd": "open", + "label": { + "installPlugin": "Plug-in installeren: {id}", + "updatePluginConfig": "Plug-in configureren: {id}", + "updatePlugin": "Plug-in bijwerken: {id}", + "enablePlugin": "Plug-in inschakelen: {id}", + "disablePlugin": "Plug-in uitschakelen: {id}", + "uninstallPlugin": "Plug-in verwijderen: {id}", + "updateSetting": "Instelling wijzigen: {category}", + "createCollection": "Collectie maken: \"{name}\"", + "updateCollection": "Collectie bijwerken", + "createSchedule": "Planning maken", + "updateSchedule": "Planning bijwerken", + "deleteSchedule": "Planning verwijderen", + "triggerSystemUpdate": "Systeemupdate" + }, + "description": { + "installPlugin": "Installeert \"{id}\" uit het officiële register.", + "installPluginEnable": "Installeert \"{id}\" uit het officiële register en schakelt het in.", + "updatePluginConfig": "Werkt de configuratie van \"{id}\" bij: {keys}.", + "updatePlugin": "Downloadt en installeert de nieuwste registerversie van \"{id}\".", + "enablePlugin": "Schakelt \"{id}\" in zodat het gegevens aan je borden kan leveren.", + "disablePlugin": "Schakelt \"{id}\" uit zonder het te verwijderen. Het kan later opnieuw worden ingeschakeld.", + "uninstallPlugin": "Verwijdert \"{id}\" definitief. Dit kan niet ongedaan worden gemaakt.", + "updateSetting": "Stelt {values} in bij de instellingen voor {category}.", + "createCollection": "Maakt een collectie met {count, plural, one {# pagina} other {# pagina's}}, die elke {interval}s wisselt.", + "createSchedule": "Toont pagina \"{page}\" vanaf {time} op {days}-dagen.", + "deleteSchedule": "Verwijdert planning \"{id}\" definitief. Dit kan niet ongedaan worden gemaakt.", + "triggerSystemUpdate": "Downloadt en installeert de nieuwste FiestaBoard-update. Het systeem start kort opnieuw op." + }, + "change": { + "rename": "hernoemen naar \"{name}\"", + "setPages": "{count, plural, one {# pagina} other {# pagina's}} instellen", + "interval": "interval → {interval}s", + "page": "pagina → {page}", + "start": "begin → {start}", + "end": "einde → {end}", + "days": "dagen → {days}", + "enable": "inschakelen", + "disable": "uitschakelen" + } + }, "plainTextEditor": { "placeholder": "Typ je sjabloontekst...", "lineCount": "{current} / {total} regels", diff --git a/web/messages/pl.json b/web/messages/pl.json index 4bd6f6bda..3ecbc9f79 100644 --- a/web/messages/pl.json +++ b/web/messages/pl.json @@ -1002,6 +1002,57 @@ "rotation": "Rotacja" } }, + "aiActionConfirmation": { + "deny": "Odmów", + "allow": "Zezwól", + "working": "Trwa…", + "done": "Gotowe", + "denied": "Odmówiono", + "noChanges": "brak zmian", + "noValues": "brak wartości", + "noChangesSpecified": "Nie określono zmian.", + "openEnd": "otwarte", + "label": { + "installPlugin": "Zainstaluj wtyczkę: {id}", + "updatePluginConfig": "Skonfiguruj wtyczkę: {id}", + "updatePlugin": "Zaktualizuj wtyczkę: {id}", + "enablePlugin": "Włącz wtyczkę: {id}", + "disablePlugin": "Wyłącz wtyczkę: {id}", + "uninstallPlugin": "Odinstaluj wtyczkę: {id}", + "updateSetting": "Zmień ustawienie: {category}", + "createCollection": "Utwórz kolekcję: \"{name}\"", + "updateCollection": "Zaktualizuj kolekcję", + "createSchedule": "Utwórz harmonogram", + "updateSchedule": "Zaktualizuj harmonogram", + "deleteSchedule": "Usuń harmonogram", + "triggerSystemUpdate": "Aktualizacja systemu" + }, + "description": { + "installPlugin": "Instaluje \"{id}\" z oficjalnego rejestru.", + "installPluginEnable": "Instaluje \"{id}\" z oficjalnego rejestru i włącza ją.", + "updatePluginConfig": "Aktualizuje konfigurację \"{id}\": {keys}.", + "updatePlugin": "Pobiera i instaluje najnowszą wersję \"{id}\" z rejestru.", + "enablePlugin": "Włącza \"{id}\", aby mogła dostarczać dane do Twoich tablic.", + "disablePlugin": "Wyłącza \"{id}\" bez usuwania. Można ją później ponownie włączyć.", + "uninstallPlugin": "Trwale usuwa \"{id}\". Tej operacji nie można cofnąć.", + "updateSetting": "Ustawia {values} w ustawieniach {category}.", + "createCollection": "Tworzy kolekcję z {count, plural, one {# stroną} other {# stronami}}, zmieniając co {interval}s.", + "createSchedule": "Pokazuje stronę \"{page}\" od {time} w dni {days}.", + "deleteSchedule": "Trwale usuwa harmonogram \"{id}\". Tej operacji nie można cofnąć.", + "triggerSystemUpdate": "Pobiera i instaluje najnowszą aktualizację FiestaBoard. System na chwilę uruchomi się ponownie." + }, + "change": { + "rename": "zmień nazwę na \"{name}\"", + "setPages": "ustaw {count, plural, one {# stronę} other {# stron}}", + "interval": "interwał → {interval}s", + "page": "strona → {page}", + "start": "początek → {start}", + "end": "koniec → {end}", + "days": "dni → {days}", + "enable": "włącz", + "disable": "wyłącz" + } + }, "plainTextEditor": { "placeholder": "Wpisz tekst szablonu...", "lineCount": "{current} / {total} linii", diff --git a/web/messages/pt.json b/web/messages/pt.json index 29754bcfb..4bd8556d0 100644 --- a/web/messages/pt.json +++ b/web/messages/pt.json @@ -1002,6 +1002,57 @@ "rotation": "Rotação" } }, + "aiActionConfirmation": { + "deny": "Negar", + "allow": "Permitir", + "working": "A processar…", + "done": "Concluído", + "denied": "Negado", + "noChanges": "sem alterações", + "noValues": "sem valores", + "noChangesSpecified": "Nenhuma alteração especificada.", + "openEnd": "aberto", + "label": { + "installPlugin": "Instalar plugin: {id}", + "updatePluginConfig": "Configurar plugin: {id}", + "updatePlugin": "Atualizar plugin: {id}", + "enablePlugin": "Ativar plugin: {id}", + "disablePlugin": "Desativar plugin: {id}", + "uninstallPlugin": "Desinstalar plugin: {id}", + "updateSetting": "Alterar definição: {category}", + "createCollection": "Criar coleção: \"{name}\"", + "updateCollection": "Atualizar coleção", + "createSchedule": "Criar agendamento", + "updateSchedule": "Atualizar agendamento", + "deleteSchedule": "Eliminar agendamento", + "triggerSystemUpdate": "Atualização do sistema" + }, + "description": { + "installPlugin": "Instala \"{id}\" a partir do registo oficial.", + "installPluginEnable": "Instala \"{id}\" a partir do registo oficial e ativa-o.", + "updatePluginConfig": "Atualiza a configuração de \"{id}\": {keys}.", + "updatePlugin": "Transfere e instala a versão mais recente do registo de \"{id}\".", + "enablePlugin": "Ativa \"{id}\" para que possa fornecer dados aos teus quadros.", + "disablePlugin": "Desativa \"{id}\" sem o remover. Pode ser reativado mais tarde.", + "uninstallPlugin": "Remove permanentemente \"{id}\". Esta ação não pode ser anulada.", + "updateSetting": "Define {values} nas definições de {category}.", + "createCollection": "Cria uma coleção com {count, plural, one {# página} other {# páginas}}, alternando a cada {interval}s.", + "createSchedule": "Mostra a página \"{page}\" das {time} nos dias {days}.", + "deleteSchedule": "Remove permanentemente o agendamento \"{id}\". Esta ação não pode ser anulada.", + "triggerSystemUpdate": "Transfere e instala a atualização mais recente do FiestaBoard. O sistema reiniciará brevemente." + }, + "change": { + "rename": "renomear para \"{name}\"", + "setPages": "definir {count, plural, one {# página} other {# páginas}}", + "interval": "intervalo → {interval}s", + "page": "página → {page}", + "start": "início → {start}", + "end": "fim → {end}", + "days": "dias → {days}", + "enable": "ativar", + "disable": "desativar" + } + }, "plainTextEditor": { "placeholder": "Digite o texto do seu template...", "lineCount": "{current} / {total} linhas", diff --git a/web/messages/ru.json b/web/messages/ru.json index 807e21ef4..85fb652db 100644 --- a/web/messages/ru.json +++ b/web/messages/ru.json @@ -1002,6 +1002,57 @@ "rotation": "Ротация" } }, + "aiActionConfirmation": { + "deny": "Отклонить", + "allow": "Разрешить", + "working": "Выполняется…", + "done": "Готово", + "denied": "Отклонено", + "noChanges": "без изменений", + "noValues": "без значений", + "noChangesSpecified": "Изменения не указаны.", + "openEnd": "открыто", + "label": { + "installPlugin": "Установить плагин: {id}", + "updatePluginConfig": "Настроить плагин: {id}", + "updatePlugin": "Обновить плагин: {id}", + "enablePlugin": "Включить плагин: {id}", + "disablePlugin": "Отключить плагин: {id}", + "uninstallPlugin": "Удалить плагин: {id}", + "updateSetting": "Изменить настройку: {category}", + "createCollection": "Создать коллекцию: \"{name}\"", + "updateCollection": "Обновить коллекцию", + "createSchedule": "Создать расписание", + "updateSchedule": "Обновить расписание", + "deleteSchedule": "Удалить расписание", + "triggerSystemUpdate": "Обновление системы" + }, + "description": { + "installPlugin": "Устанавливает \"{id}\" из официального реестра.", + "installPluginEnable": "Устанавливает \"{id}\" из официального реестра и включает его.", + "updatePluginConfig": "Обновляет конфигурацию \"{id}\": {keys}.", + "updatePlugin": "Загружает и устанавливает последнюю версию \"{id}\" из реестра.", + "enablePlugin": "Включает \"{id}\", чтобы он мог предоставлять данные для ваших досок.", + "disablePlugin": "Отключает \"{id}\" без удаления. Его можно снова включить позже.", + "uninstallPlugin": "Безвозвратно удаляет \"{id}\". Это действие нельзя отменить.", + "updateSetting": "Устанавливает {values} в настройках {category}.", + "createCollection": "Создаёт коллекцию из {count, plural, one {# страницы} other {# страниц}}, чередуя каждые {interval}с.", + "createSchedule": "Показывает страницу \"{page}\" с {time} по дням: {days}.", + "deleteSchedule": "Безвозвратно удаляет расписание \"{id}\". Это действие нельзя отменить.", + "triggerSystemUpdate": "Загружает и устанавливает последнее обновление FiestaBoard. Система ненадолго перезапустится." + }, + "change": { + "rename": "переименовать в \"{name}\"", + "setPages": "задать {count, plural, one {# страницу} other {# страниц}}", + "interval": "интервал → {interval}с", + "page": "страница → {page}", + "start": "начало → {start}", + "end": "конец → {end}", + "days": "дни → {days}", + "enable": "включить", + "disable": "отключить" + } + }, "plainTextEditor": { "placeholder": "Введите текст шаблона...", "lineCount": "{current} / {total} строк", diff --git a/web/messages/sv.json b/web/messages/sv.json index d658c9f9f..49257877d 100644 --- a/web/messages/sv.json +++ b/web/messages/sv.json @@ -1002,6 +1002,57 @@ "rotation": "Rotation" } }, + "aiActionConfirmation": { + "deny": "Neka", + "allow": "Tillåt", + "working": "Arbetar…", + "done": "Klar", + "denied": "Nekad", + "noChanges": "inga ändringar", + "noValues": "inga värden", + "noChangesSpecified": "Inga ändringar angivna.", + "openEnd": "öppet", + "label": { + "installPlugin": "Installera plugin: {id}", + "updatePluginConfig": "Konfigurera plugin: {id}", + "updatePlugin": "Uppdatera plugin: {id}", + "enablePlugin": "Aktivera plugin: {id}", + "disablePlugin": "Inaktivera plugin: {id}", + "uninstallPlugin": "Avinstallera plugin: {id}", + "updateSetting": "Ändra inställning: {category}", + "createCollection": "Skapa samling: \"{name}\"", + "updateCollection": "Uppdatera samling", + "createSchedule": "Skapa schema", + "updateSchedule": "Uppdatera schema", + "deleteSchedule": "Ta bort schema", + "triggerSystemUpdate": "Systemuppdatering" + }, + "description": { + "installPlugin": "Installerar \"{id}\" från det officiella registret.", + "installPluginEnable": "Installerar \"{id}\" från det officiella registret och aktiverar det.", + "updatePluginConfig": "Uppdaterar konfigurationen för \"{id}\": {keys}.", + "updatePlugin": "Laddar ner och installerar den senaste registerversionen av \"{id}\".", + "enablePlugin": "Aktiverar \"{id}\" så att det kan leverera data till dina tavlor.", + "disablePlugin": "Inaktiverar \"{id}\" utan att ta bort det. Det kan aktiveras igen senare.", + "uninstallPlugin": "Tar bort \"{id}\" permanent. Detta kan inte ångras.", + "updateSetting": "Ställer in {values} i inställningarna för {category}.", + "createCollection": "Skapar en samling med {count, plural, one {# sida} other {# sidor}}, som växlar var {interval}:e sekund.", + "createSchedule": "Visar sidan \"{page}\" från {time} på {days}-dagar.", + "deleteSchedule": "Tar bort schemat \"{id}\" permanent. Detta kan inte ångras.", + "triggerSystemUpdate": "Laddar ner och installerar den senaste FiestaBoard-uppdateringen. Systemet startar om en kort stund." + }, + "change": { + "rename": "byt namn till \"{name}\"", + "setPages": "ange {count, plural, one {# sida} other {# sidor}}", + "interval": "intervall → {interval}s", + "page": "sida → {page}", + "start": "start → {start}", + "end": "slut → {end}", + "days": "dagar → {days}", + "enable": "aktivera", + "disable": "inaktivera" + } + }, "plainTextEditor": { "placeholder": "Skriv din malltext...", "lineCount": "{current} / {total} rader", diff --git a/web/messages/tr.json b/web/messages/tr.json index fc115ed68..f2eeae376 100644 --- a/web/messages/tr.json +++ b/web/messages/tr.json @@ -1002,6 +1002,57 @@ "rotation": "Rotasyon" } }, + "aiActionConfirmation": { + "deny": "Reddet", + "allow": "İzin ver", + "working": "Çalışıyor…", + "done": "Tamam", + "denied": "Reddedildi", + "noChanges": "değişiklik yok", + "noValues": "değer yok", + "noChangesSpecified": "Değişiklik belirtilmedi.", + "openEnd": "açık", + "label": { + "installPlugin": "Eklenti yükle: {id}", + "updatePluginConfig": "Eklentiyi yapılandır: {id}", + "updatePlugin": "Eklentiyi güncelle: {id}", + "enablePlugin": "Eklentiyi etkinleştir: {id}", + "disablePlugin": "Eklentiyi devre dışı bırak: {id}", + "uninstallPlugin": "Eklentiyi kaldır: {id}", + "updateSetting": "Ayarı değiştir: {category}", + "createCollection": "Koleksiyon oluştur: \"{name}\"", + "updateCollection": "Koleksiyonu güncelle", + "createSchedule": "Zamanlama oluştur", + "updateSchedule": "Zamanlamayı güncelle", + "deleteSchedule": "Zamanlamayı sil", + "triggerSystemUpdate": "Sistem güncellemesi" + }, + "description": { + "installPlugin": "\"{id}\" eklentisini resmi kayıttan yükler.", + "installPluginEnable": "\"{id}\" eklentisini resmi kayıttan yükler ve etkinleştirir.", + "updatePluginConfig": "\"{id}\" yapılandırmasını günceller: {keys}.", + "updatePlugin": "\"{id}\" eklentisinin en son kayıt sürümünü indirir ve yükler.", + "enablePlugin": "\"{id}\" eklentisini panolarınıza veri sağlayabilmesi için etkinleştirir.", + "disablePlugin": "\"{id}\" eklentisini kaldırmadan devre dışı bırakır. Daha sonra tekrar etkinleştirilebilir.", + "uninstallPlugin": "\"{id}\" eklentisini kalıcı olarak kaldırır. Bu işlem geri alınamaz.", + "updateSetting": "{category} ayarlarında {values} değerini ayarlar.", + "createCollection": "{count, plural, one {# sayfa} other {# sayfa}} içeren bir koleksiyon oluşturur, her {interval}s'de bir döner.", + "createSchedule": "\"{page}\" sayfasını {days} günlerinde {time} arasında gösterir.", + "deleteSchedule": "\"{id}\" zamanlamasını kalıcı olarak kaldırır. Bu işlem geri alınamaz.", + "triggerSystemUpdate": "En son FiestaBoard güncellemesini indirir ve yükler. Sistem kısa süreliğine yeniden başlar." + }, + "change": { + "rename": "\"{name}\" olarak yeniden adlandır", + "setPages": "{count, plural, one {# sayfa} other {# sayfa}} ayarla", + "interval": "aralık → {interval}s", + "page": "sayfa → {page}", + "start": "başlangıç → {start}", + "end": "bitiş → {end}", + "days": "günler → {days}", + "enable": "etkinleştir", + "disable": "devre dışı bırak" + } + }, "plainTextEditor": { "placeholder": "Şablon metninizi yazın...", "lineCount": "{current} / {total} satır", diff --git a/web/messages/zh.json b/web/messages/zh.json index 5b6ed2fc9..dbe3a603a 100644 --- a/web/messages/zh.json +++ b/web/messages/zh.json @@ -1002,6 +1002,57 @@ "rotation": "轮换" } }, + "aiActionConfirmation": { + "deny": "拒绝", + "allow": "允许", + "working": "处理中…", + "done": "完成", + "denied": "已拒绝", + "noChanges": "无更改", + "noValues": "无值", + "noChangesSpecified": "未指定更改。", + "openEnd": "未设定", + "label": { + "installPlugin": "安装插件:{id}", + "updatePluginConfig": "配置插件:{id}", + "updatePlugin": "更新插件:{id}", + "enablePlugin": "启用插件:{id}", + "disablePlugin": "禁用插件:{id}", + "uninstallPlugin": "卸载插件:{id}", + "updateSetting": "更改设置:{category}", + "createCollection": "创建合集:\"{name}\"", + "updateCollection": "更新合集", + "createSchedule": "创建日程", + "updateSchedule": "更新日程", + "deleteSchedule": "删除日程", + "triggerSystemUpdate": "系统更新" + }, + "description": { + "installPlugin": "从官方注册表安装“{id}”。", + "installPluginEnable": "从官方注册表安装“{id}”并启用它。", + "updatePluginConfig": "更新“{id}”的配置:{keys}。", + "updatePlugin": "下载并安装“{id}”的最新注册表版本。", + "enablePlugin": "启用“{id}”,使其能够向你的看板提供数据。", + "disablePlugin": "禁用“{id}”但不移除它。稍后可重新启用。", + "uninstallPlugin": "永久移除“{id}”。此操作无法撤销。", + "updateSetting": "在 {category} 设置中设置 {values}。", + "createCollection": "创建一个包含 {count, plural, other {# 个页面}} 的合集,每 {interval} 秒轮换一次。", + "createSchedule": "在 {days} 的 {time} 显示页面“{page}”。", + "deleteSchedule": "永久移除日程“{id}”。此操作无法撤销。", + "triggerSystemUpdate": "下载并安装最新的 FiestaBoard 更新。系统将短暂重启。" + }, + "change": { + "rename": "重命名为“{name}”", + "setPages": "设置 {count, plural, other {# 个页面}}", + "interval": "间隔 → {interval}秒", + "page": "页面 → {page}", + "start": "开始 → {start}", + "end": "结束 → {end}", + "days": "日期 → {days}", + "enable": "启用", + "disable": "禁用" + } + }, "plainTextEditor": { "placeholder": "输入您的模板文本...", "lineCount": "{current} / {total} 行", diff --git a/web/src/components/ai-action-confirmation.tsx b/web/src/components/ai-action-confirmation.tsx index cb4a40a42..3f65a6944 100644 --- a/web/src/components/ai-action-confirmation.tsx +++ b/web/src/components/ai-action-confirmation.tsx @@ -17,6 +17,7 @@ import { useEffect, useRef, useState } from "react"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; +import { useTranslations } from "@/i18n/translations"; import type { CreateCollectionArgs, CreateScheduleArgs, @@ -49,102 +50,106 @@ interface AiActionConfirmationProps { autoAllow?: boolean; } -function actionLabel(call: AiActionConfirmationProps["call"]): string { +type TranslateFn = (key: string, params?: Record) => string; + +function actionLabel(call: AiActionConfirmationProps["call"], t: TranslateFn): string { switch (call.op) { case "install_plugin": - return `Install plugin: ${(call.args as InstallPluginArgs).plugin_id}`; + return t("label.installPlugin", { id: (call.args as InstallPluginArgs).plugin_id }); case "update_plugin_config": - return `Configure plugin: ${(call.args as UpdatePluginConfigArgs).plugin_id}`; + return t("label.updatePluginConfig", { id: (call.args as UpdatePluginConfigArgs).plugin_id }); case "update_plugin": - return `Update plugin: ${(call.args as UpdatePluginArgs).plugin_id}`; + return t("label.updatePlugin", { id: (call.args as UpdatePluginArgs).plugin_id }); case "enable_plugin": - return `Enable plugin: ${(call.args as EnablePluginArgs).plugin_id}`; + return t("label.enablePlugin", { id: (call.args as EnablePluginArgs).plugin_id }); case "disable_plugin": - return `Disable plugin: ${(call.args as DisablePluginArgs).plugin_id}`; + return t("label.disablePlugin", { id: (call.args as DisablePluginArgs).plugin_id }); case "uninstall_plugin": - return `Uninstall plugin: ${(call.args as UninstallPluginArgs).plugin_id}`; + return t("label.uninstallPlugin", { id: (call.args as UninstallPluginArgs).plugin_id }); case "update_setting": - return `Change setting: ${(call.args as UpdateSettingArgs).category}`; + return t("label.updateSetting", { category: (call.args as UpdateSettingArgs).category }); case "create_collection": - return `Create collection: "${(call.args as CreateCollectionArgs).name}"`; + return t("label.createCollection", { name: (call.args as CreateCollectionArgs).name }); case "update_collection": - return `Update collection`; + return t("label.updateCollection"); case "create_schedule": - return `Create schedule`; + return t("label.createSchedule"); case "update_schedule": - return `Update schedule`; + return t("label.updateSchedule"); case "delete_schedule": - return `Delete schedule`; + return t("label.deleteSchedule"); case "trigger_system_update": - return `System update`; + return t("label.triggerSystemUpdate"); } } -function actionDescription(call: AiActionConfirmationProps["call"]): string { +function actionDescription(call: AiActionConfirmationProps["call"], t: TranslateFn): string { switch (call.op) { case "install_plugin": { const a = call.args as InstallPluginArgs; - return `Installs "${a.plugin_id}" from the official registry${a.auto_enable !== false ? " and enables it" : ""}.`; + return a.auto_enable !== false + ? t("description.installPluginEnable", { id: a.plugin_id }) + : t("description.installPlugin", { id: a.plugin_id }); } case "update_plugin_config": { const a = call.args as UpdatePluginConfigArgs; const keys = Object.keys(a.config).join(", "); - return `Updates configuration for "${a.plugin_id}": ${keys || "no changes"}.`; + return t("description.updatePluginConfig", { id: a.plugin_id, keys: keys || t("noChanges") }); } case "update_plugin": { const a = call.args as UpdatePluginArgs; - return `Downloads and installs the latest registry version of "${a.plugin_id}".`; + return t("description.updatePlugin", { id: a.plugin_id }); } case "enable_plugin": { const a = call.args as EnablePluginArgs; - return `Enables "${a.plugin_id}" so it can provide data to your boards.`; + return t("description.enablePlugin", { id: a.plugin_id }); } case "disable_plugin": { const a = call.args as DisablePluginArgs; - return `Disables "${a.plugin_id}" without removing it. It can be re-enabled later.`; + return t("description.disablePlugin", { id: a.plugin_id }); } case "uninstall_plugin": { const a = call.args as UninstallPluginArgs; - return `Permanently removes "${a.plugin_id}". This cannot be undone.`; + return t("description.uninstallPlugin", { id: a.plugin_id }); } case "update_setting": { const a = call.args as UpdateSettingArgs; const entries = Object.entries(a.values) .map(([k, v]) => `${k}: ${JSON.stringify(v)}`) .join(", "); - return `Sets ${entries || "no values"} in ${a.category} settings.`; + return t("description.updateSetting", { values: entries || t("noValues"), category: a.category }); } case "create_collection": { const a = call.args as CreateCollectionArgs; - return `Creates a collection with ${a.page_ids.length} page(s), rotating every ${a.interval_seconds}s.`; + return t("description.createCollection", { count: a.page_ids.length, interval: a.interval_seconds }); } case "update_collection": { const a = call.args as UpdateCollectionArgs; const changes: string[] = []; - if (a.name != null) changes.push(`rename to "${a.name}"`); - if (a.page_ids != null) changes.push(`set ${a.page_ids.length} page(s)`); - if (a.interval_seconds != null) changes.push(`interval → ${a.interval_seconds}s`); - return changes.length ? changes.join(", ") + "." : "No changes specified."; + if (a.name != null) changes.push(t("change.rename", { name: a.name })); + if (a.page_ids != null) changes.push(t("change.setPages", { count: a.page_ids.length })); + if (a.interval_seconds != null) changes.push(t("change.interval", { interval: a.interval_seconds })); + return changes.length ? changes.join(", ") + "." : t("noChangesSpecified"); } case "create_schedule": { const a = call.args as CreateScheduleArgs; const time = `${a.start_time}${a.end_time ? `–${a.end_time}` : "+"}`; - return `Shows page "${a.page_id}" from ${time} on ${a.day_pattern} days.`; + return t("description.createSchedule", { page: a.page_id, time, days: a.day_pattern }); } case "update_schedule": { const a = call.args as UpdateScheduleArgs; const changes: string[] = []; - if (a.page_id != null) changes.push(`page → ${a.page_id}`); - if (a.start_time != null) changes.push(`start → ${a.start_time}`); - if (a.end_time !== undefined) changes.push(`end → ${a.end_time ?? "open"}`); - if (a.day_pattern != null) changes.push(`days → ${a.day_pattern}`); - if (a.enabled != null) changes.push(a.enabled ? "enable" : "disable"); - return changes.length ? changes.join(", ") + "." : "No changes specified."; + if (a.page_id != null) changes.push(t("change.page", { page: a.page_id })); + if (a.start_time != null) changes.push(t("change.start", { start: a.start_time })); + if (a.end_time !== undefined) changes.push(t("change.end", { end: a.end_time ?? t("openEnd") })); + if (a.day_pattern != null) changes.push(t("change.days", { days: a.day_pattern })); + if (a.enabled != null) changes.push(a.enabled ? t("change.enable") : t("change.disable")); + return changes.length ? changes.join(", ") + "." : t("noChangesSpecified"); } case "delete_schedule": - return `Permanently removes schedule "${(call.args as DeleteScheduleArgs).schedule_id}". This cannot be undone.`; + return t("description.deleteSchedule", { id: (call.args as DeleteScheduleArgs).schedule_id }); case "trigger_system_update": - return "Downloads and installs the latest FiestaBoard update. The system will restart briefly."; + return t("description.triggerSystemUpdate"); } } @@ -152,32 +157,33 @@ function ActionIcon({ op }: { op: ConfirmableOp }) { const cls = "h-4 w-4 shrink-0 text-muted-foreground"; switch (op) { case "install_plugin": - return ; + return