From 7b0e51147927082f98626552603306f1f02e8a18 Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Mon, 11 May 2026 11:57:11 +0200 Subject: [PATCH] a11y: localized aria-label on the 3 filter/search inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three filter / search inputs in the always-visible UI surface (VOD filter, sidebar streamer-list filter, Archive search) had only placeholder text as their accessible-name source. Placeholder text is unreliable as a screen-reader name — some implementations announce it, some skip it, and it disappears as soon as the user types so a re-focus during typing leaves the input unannounced. Added three locale keys (DE+EN): - vods.filterAria — "VOD-Titel filtern" / "Filter VOD titles" - static.archiveSearchAria — "Archiv durchsuchen" / "Search archive" - static.streamerListFilterAria — "Streamer-Liste filtern" / "Filter streamer list" Wired through renderer-texts via the existing setAriaLabel helper (added in 4.6.91), so each input now has a proper aria-label that survives the placeholder vanishing and reads cleanly in screen-reader navigation. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/renderer-locale-de.ts | 3 +++ src/renderer-locale-en.ts | 3 +++ src/renderer-texts.ts | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/renderer-locale-de.ts b/src/renderer-locale-de.ts index 77d3748..7c0783c 100644 --- a/src/renderer-locale-de.ts +++ b/src/renderer-locale-de.ts @@ -139,6 +139,7 @@ const UI_TEXT_DE = { archiveNoMatches: 'Keine Treffer.', archiveNoRoot: 'Download-Ordner nicht gefunden. Setze zuerst einen Download-Pfad in den Einstellungen.', archiveSearchPlaceholder: 'Suche...', + archiveSearchAria: 'Archiv durchsuchen', archiveOpen: 'Oeffnen', archiveShowInFolder: 'Ordner', archiveViewChat: 'Chat', @@ -177,6 +178,7 @@ const UI_TEXT_DE = { downloadPathNotWritable: 'Download-Ordner ist nicht beschreibbar. Waehle einen anderen Ordner oder pruefe die Schreibrechte.', streamerSectionTitle: 'Streamer', streamerListFilterPlaceholder: 'Filtern...', + streamerListFilterAria: 'Streamer-Liste filtern', streamerAddAriaLabel: 'Streamer hinzufuegen', streamerBulkRemoveTitle: 'Alle entfernen (oder gefilterte)', streamerBulkRemoveAll: 'Alle {count} Streamer aus der Liste entfernen?', @@ -378,6 +380,7 @@ const UI_TEXT_DE = { addQueue: '+ Warteschlange', trimButton: 'VOD zuschneiden', filterPlaceholder: 'Nach Titel filtern... (Strg+F)', + filterAria: 'VOD-Titel filtern', filterClearTitle: 'Filter loeschen (Esc)', filterNoMatchTitle: 'Keine Treffer', filterNoMatchText: 'Keine VODs entsprechen dem aktuellen Filter.', diff --git a/src/renderer-locale-en.ts b/src/renderer-locale-en.ts index a4326c1..7ba575f 100644 --- a/src/renderer-locale-en.ts +++ b/src/renderer-locale-en.ts @@ -140,6 +140,7 @@ const UI_TEXT_EN = { archiveNoMatches: 'No matches.', archiveNoRoot: 'Download folder not found. Set a download path in Settings first.', archiveSearchPlaceholder: 'Search...', + archiveSearchAria: 'Search archive', archiveOpen: 'Open', archiveShowInFolder: 'Folder', archiveViewChat: 'Chat', @@ -177,6 +178,7 @@ const UI_TEXT_EN = { downloadPathNotWritable: 'Download folder is not writable. Pick another folder or grant write permission.', streamerSectionTitle: 'Streamer', streamerListFilterPlaceholder: 'Filter...', + streamerListFilterAria: 'Filter streamer list', streamerAddAriaLabel: 'Add streamer', streamerBulkRemoveTitle: 'Remove all (or filtered)', streamerBulkRemoveAll: 'Remove all {count} streamers from the list?', @@ -378,6 +380,7 @@ const UI_TEXT_EN = { addQueue: '+ Queue', trimButton: 'Trim VOD', filterPlaceholder: 'Filter by title... (Ctrl+F)', + filterAria: 'Filter VOD titles', filterClearTitle: 'Clear filter (Esc)', filterNoMatchTitle: 'No matches', filterNoMatchText: 'No VODs match the current filter.', diff --git a/src/renderer-texts.ts b/src/renderer-texts.ts index f3dac42..700fcf0 100644 --- a/src/renderer-texts.ts +++ b/src/renderer-texts.ts @@ -67,6 +67,7 @@ function applyLanguageToStaticUI(): void { setText('btnArchiveSearch', UI_TEXT.static.archiveSearchBtn); const archiveQueryInput = document.getElementById('archiveSearchQuery') as HTMLInputElement | null; if (archiveQueryInput) archiveQueryInput.placeholder = UI_TEXT.static.archiveSearchPlaceholder; + setAriaLabel('archiveSearchQuery', UI_TEXT.static.archiveSearchAria); const archiveTypeSelect = document.getElementById('archiveSearchType') as HTMLSelectElement | null; if (archiveTypeSelect) { const opts = archiveTypeSelect.options; @@ -185,6 +186,7 @@ function applyLanguageToStaticUI(): void { setText('streamlinkQualityAudio', UI_TEXT.static.streamlinkQualityAudio); setText('streamerSectionTitleText', UI_TEXT.static.streamerSectionTitle); setPlaceholder('streamerListFilter', UI_TEXT.static.streamerListFilterPlaceholder); + setAriaLabel('streamerListFilter', UI_TEXT.static.streamerListFilterAria); setTitle('btnStreamerBulkRemove', UI_TEXT.static.streamerBulkRemoveTitle); setAriaLabel('btnStreamerBulkRemove', UI_TEXT.static.streamerBulkRemoveTitle); setAriaLabel('btnAddStreamer', UI_TEXT.static.streamerAddAriaLabel); @@ -294,6 +296,7 @@ function applyLanguageToStaticUI(): void { setText('updateChangelogEmpty', UI_TEXT.updates.noChangelog); setPlaceholder('newStreamer', UI_TEXT.static.streamerPlaceholder); setPlaceholder('vodFilterInput', UI_TEXT.vods.filterPlaceholder); + setAriaLabel('vodFilterInput', UI_TEXT.vods.filterAria); setTitle('vodFilterClearBtn', UI_TEXT.vods.filterClearTitle); setAriaLabel('vodFilterClearBtn', UI_TEXT.vods.filterClearTitle); setPlaceholder('chatViewerFilter', UI_TEXT.queue.chatViewerFilterPlaceholder);