@@ -23,14 +23,15 @@ var BattleNarrator = (function() {
2323 enabled = true ;
2424 }
2525
26- // Create narrator live region
26+ // Create narrator live region. Keep it as one persistent status region:
27+ // mobile screen readers announce text replacement more reliably than
28+ // appended children inside role=log.
2729 if ( ! narratorEl ) {
2830 narratorEl = document . createElement ( 'div' ) ;
2931 narratorEl . id = 'battle-narrator' ;
30- narratorEl . setAttribute ( 'role' , 'log ' ) ;
32+ narratorEl . setAttribute ( 'role' , 'status ' ) ;
3133 narratorEl . setAttribute ( 'aria-live' , 'polite' ) ;
32- narratorEl . setAttribute ( 'aria-atomic' , 'false' ) ;
33- narratorEl . setAttribute ( 'aria-relevant' , 'additions' ) ;
34+ narratorEl . setAttribute ( 'aria-atomic' , 'true' ) ;
3435 narratorEl . className = 'sr-only' ;
3536 narratorEl . setAttribute ( 'aria-label' , Helpers . t ( 'narrator_label' ) ) ;
3637 document . body . appendChild ( narratorEl ) ;
@@ -66,17 +67,32 @@ var BattleNarrator = (function() {
6667 if ( ! enabled || ! message ) return ;
6768 if ( ! narratorEl ) init ( ) ;
6869
69- narratorEl . setAttribute ( 'aria-live' , priority || 'polite' ) ;
70+ var mode = priority || 'polite' ;
71+ narratorEl . setAttribute ( 'aria-live' , mode ) ;
72+ narratorEl . setAttribute ( 'role' , mode === 'assertive' ? 'alert' : 'status' ) ;
7073
71- // Append new message as paragraph
72- var p = document . createElement ( 'p' ) ;
73- p . textContent = message ;
74- narratorEl . appendChild ( p ) ;
74+ // Force a DOM text change so TalkBack/VoiceOver do not ignore repeated
75+ // announcements after navigation or re-render.
76+ narratorEl . textContent = '' ;
77+ setTimeout ( function ( ) {
78+ if ( narratorEl ) narratorEl . textContent = message ;
79+ } , 25 ) ;
7580
76- // Keep only last 10 messages
77- while ( narratorEl . children . length > 10 ) {
78- narratorEl . removeChild ( narratorEl . firstChild ) ;
79- }
81+ _speak ( message ) ;
82+ }
83+
84+ function _speak ( message ) {
85+ if ( ! message || typeof window === 'undefined' || ! window . speechSynthesis || ! window . SpeechSynthesisUtterance ) return ;
86+ try {
87+ var utterance = new SpeechSynthesisUtterance ( message ) ;
88+ var lang = ( Helpers . getCurrentLang && Helpers . getCurrentLang ( ) === 'en' ) ? 'en-US' : 'ru-RU' ;
89+ utterance . lang = lang ;
90+ utterance . rate = 1 ;
91+ utterance . pitch = 1 ;
92+ utterance . volume = 1 ;
93+ window . speechSynthesis . cancel ( ) ;
94+ window . speechSynthesis . speak ( utterance ) ;
95+ } catch ( e ) { }
8096 }
8197
8298 /**
0 commit comments