feat: add screen reader announcements, improve translation fallback, and fix voice recognition restart

This commit is contained in:
sinanisler
2026-06-15 21:48:04 +03:00
parent d41ed0c8d7
commit a5c23f1773
+61 -1
View File
@@ -1133,7 +1133,20 @@ function setLanguage(lang) {
}
function getTranslation(key) {
return TRANSLATIONS[currentLanguage][key] || TRANSLATIONS['en'][key] || key;
// Check current language translations first
if (TRANSLATIONS[currentLanguage] && TRANSLATIONS[currentLanguage][key]) {
return TRANSLATIONS[currentLanguage][key];
}
// Fallback to user-configured lang overrides
if (WIDGET_CONFIG.lang && WIDGET_CONFIG.lang[key]) {
return WIDGET_CONFIG.lang[key];
}
// Fallback to English translations
if (TRANSLATIONS['en'] && TRANSLATIONS['en'][key]) {
return TRANSLATIONS['en'][key];
}
// Last resort: return the key itself
return key;
}
// Initialize language from localStorage or detect from browser
@@ -2211,6 +2224,19 @@ const widgetStyles = `
word-spacing: 2px !important;
text-align: left;
}
/* Screen-reader-only utility for live announcements */
.snn-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
`;
// Page accessibility styles (will go in main document - these affect the page, NOT the widget)
@@ -2470,6 +2496,14 @@ function createShadowContainer() {
styleElement.textContent = widgetStyles;
shadowRoot.appendChild(styleElement);
// Create aria-live region for screen reader announcements
const liveRegion = document.createElement('div');
liveRegion.id = 'snn-live-region';
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.setAttribute('aria-atomic', 'true');
liveRegion.classList.add('snn-sr-only');
shadowRoot.appendChild(liveRegion);
return shadowRoot;
}
@@ -2477,6 +2511,19 @@ function createShadowContainer() {
// CORE UTILITY FUNCTIONS
// ===========================================
// Announce a change to screen reader users via the live region
function announceChange(message) {
if (!shadowRoot) return;
const liveRegion = shadowRoot.getElementById('snn-live-region');
if (!liveRegion) return;
// Clear then set to ensure announcement even for repeated messages
liveRegion.textContent = '';
// Use requestAnimationFrame to ensure DOM update before setting new text
requestAnimationFrame(() => {
liveRegion.textContent = message;
});
}
// Cache for DOM elements to improve performance
const domCache = {
get body() {
@@ -2800,6 +2847,9 @@ function resetAccessibilitySettings() {
const steps = button.querySelectorAll('.snn-option-step');
steps.forEach(step => step.classList.remove('active'));
});
// Announce reset to screen reader users
announceChange(getTranslation('resetAllSettings'));
}
// Create toggle buttons for accessibility options
@@ -2877,6 +2927,9 @@ function createToggleButton(
targetElement.classList.remove(className);
}
}
// Announce change to screen reader users
announceChange(buttonText);
}
return button;
@@ -2916,6 +2969,7 @@ function createActionButton(buttonText, actionFunction, iconSVG, optionsConfig =
const result = actionFunction();
if (result) {
updateActionButtonStatus(button, optionId, optionsConfig);
announceChange(buttonText + ': ' + result);
}
});
@@ -2925,6 +2979,7 @@ function createActionButton(buttonText, actionFunction, iconSVG, optionsConfig =
const result = actionFunction();
if (result) {
updateActionButtonStatus(button, optionId, optionsConfig);
announceChange(buttonText + ': ' + result);
}
}
});
@@ -3383,6 +3438,11 @@ const voiceControl = {
}
try {
// Abort any existing recognition instance before creating a new one
if (voiceControl.recognition) {
try { voiceControl.recognition.abort(); } catch (e) { /* ignore */ }
voiceControl.recognition = null;
}
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
voiceControl.recognition = new SpeechRecognition();
voiceControl.recognition.interimResults = false;