- )}
+ {/* Live regions must stay mounted so screen readers can observe
+ text changes; conditional mounting would hide the update. */}
+
+
{t('git.conflicts.banner')}
diff --git a/apps/desktop/src/api/builtin.l10n.ts b/apps/desktop/src/api/builtin.l10n.ts
index faa1b10a..c5f2d3a6 100644
--- a/apps/desktop/src/api/builtin.l10n.ts
+++ b/apps/desktop/src/api/builtin.l10n.ts
@@ -258,6 +258,7 @@ export function registerBuiltinTranslations() {
'ai.status.badge.ready': 'Ready',
'ai.status.badge.busy': 'Busy',
'ai.disclaimer': 'Trixty AI can make mistakes. Check important info.',
+ 'ai.chat_log_label': 'AI chat transcript',
'terminal.error_connect': 'Error connecting to terminal: ',
'editor.empty_desc': 'Select a file from the explorer to begin',
@@ -635,6 +636,7 @@ export function registerBuiltinTranslations() {
'ai.status.badge.ready': 'Listo',
'ai.status.badge.busy': 'Ocupado',
'ai.disclaimer': 'Trixty AI puede cometer errores. Verifica info importante.',
+ 'ai.chat_log_label': 'Transcripción del chat de IA',
'terminal.error_connect': 'Error al conectar con la terminal: ',
'editor.empty_desc': 'Selecciona un archivo del explorador para comenzar',
diff --git a/apps/desktop/src/components/UpdaterDialog.tsx b/apps/desktop/src/components/UpdaterDialog.tsx
index 06061f63..88030dfe 100644
--- a/apps/desktop/src/components/UpdaterDialog.tsx
+++ b/apps/desktop/src/components/UpdaterDialog.tsx
@@ -112,8 +112,34 @@ const UpdaterDialog: React.FC = () => {
}
};
+ // Build the string AT should announce for the current phase. Progress
+ // percentage is intentionally omitted because `updater-progress` fires
+ // on every chunk and would flood screen readers if it lived inside a
+ // live region.
+ const getAnnouncement = (): string => {
+ switch (state.phase) {
+ case "checking": return t('updater.checking');
+ case "up-to-date": return `${getDialogTitle()}. ${t('updater.uptodate')}`;
+ case "available": return `${getDialogTitle()}. ${t('updater.new_version')} ${state.version}`;
+ case "downloading": return t('updater.downloading');
+ case "ready": return `${getDialogTitle()}. ${t('updater.relaunching')}`;
+ case "error": return `${getDialogTitle()}. ${state.message}`;
+ default: return getDialogTitle();
+ }
+ };
+
return (
+ {/* Dedicated live region so only the phase text is announced — not
+ the whole toast with buttons, and not every frame of the
+ `updater-progress` stream. Role escalates to `alert` on error. */}
+
+ {getAnnouncement()}
+
{/* Header */}