@@ -142,6 +142,10 @@ export default class AbstractTTSEngine {
142142 // MS Edge fires voices changed randomly very often
143143 this . events . off ( 'voiceschanged' , this . updateBestVoice ) ;
144144 this . voice = this . getVoices ( ) . find ( voice => voice . voiceURI === voiceURI ) ;
145+ // if the current book has a language set, store the selected voice with the book language as a suffix
146+ if ( this . opts . bookLanguage ) {
147+ localStorage . setItem ( `BRtts-voice-${ this . opts . bookLanguage } ` , this . voice . voiceURI ) ;
148+ }
145149 if ( this . activeSound ) this . activeSound . setVoice ( this . voice ) ;
146150 }
147151
@@ -221,17 +225,32 @@ export default class AbstractTTSEngine {
221225 // user languages that match the book language
222226 const matchingUserLangs = userLanguages . filter ( lang => lang . startsWith ( bookLanguage ) ) ;
223227
224- // Try to find voices that intersect these two sets
225- return AbstractTTSEngine . getMatchingVoice ( matchingUserLangs , bookLangVoices ) ||
228+ // First try to find the last chosen voice from localStorage for the current book language
229+ return AbstractTTSEngine . getMatchingStoredVoice ( bookLangVoices , bookLanguage )
230+ // Try to find voices that intersect these two sets
231+ || AbstractTTSEngine . getMatchingVoice ( matchingUserLangs , bookLangVoices )
226232 // no user languages match the books; let's return the best voice for the book language
227- ( bookLangVoices . find ( v => v . default ) || bookLangVoices [ 0 ] )
233+ || ( bookLangVoices . find ( v => v . default ) || bookLangVoices [ 0 ] )
228234 // No voices match the book language? let's find a voice in the user's language
229235 // and ignore book lang
230236 || AbstractTTSEngine . getMatchingVoice ( userLanguages , voices )
231237 // C'mon! Ok, just read with whatever we got!
232238 || ( voices . find ( v => v . default ) || voices [ 0 ] ) ;
233239 }
234240
241+ /**
242+ * @private
243+ * Get the voice last selected by the user for the book language from localStorage.
244+ * Returns undefined if no voice is stored or found.
245+ * @param {SpeechSynthesisVoice[] } voices browser voices to choose from
246+ * @param {ISO6391 } bookLanguage book language to look for
247+ * @return {SpeechSynthesisVoice | undefined }
248+ */
249+ static getMatchingStoredVoice ( voices , bookLanguage ) {
250+ const storedVoice = localStorage . getItem ( `BRtts-voice-${ bookLanguage } ` ) ;
251+ return ( storedVoice ? voices . find ( v => v . voiceURI === storedVoice ) : undefined ) ;
252+ }
253+
235254 /**
236255 * @private
237256 * Get the best voice that matches one of the BCP47 languages (order by preference)
0 commit comments