diff --git a/tts.js b/tts.js index bf665c5..b53add8 100644 --- a/tts.js +++ b/tts.js @@ -22,7 +22,12 @@ const getAlphabet = el => { } const getSegmenter = (lang = 'en', granularity = 'word') => { - const segmenter = new Intl.Segmenter(lang, { granularity }) + // `lang` may be explicitly null when getLang() walks to the document + // root without finding a language attribute — common for PDFs, which + // almost never declare a language. The default parameter above only + // applies when the argument is `undefined`, not `null`, so we need a + // separate fallback here to avoid `Intl.Segmenter(null, ...)` throwing. + const segmenter = new Intl.Segmenter(lang || 'en', { granularity }) const granularityIsWord = granularity === 'word' return function* (strs, makeRange) { const str = strs.join('') diff --git a/view.js b/view.js index 7397ea2..6d20e27 100644 --- a/view.js +++ b/view.js @@ -585,8 +585,14 @@ export class View extends HTMLElement { const doc = this.renderer.getContents()[0].doc if (this.tts && this.tts.doc === doc) return const { TTS } = await import('./tts.js') - this.tts = new TTS(doc, textWalker, highlight || (range => - this.renderer.scrollToAnchor(range, true)), granularity) + this.tts = new TTS(doc, textWalker, highlight || (range => { + // Not every renderer implements scrollToAnchor — in particular, + // the PDF renderer is fixed-layout and has no notion of an + // anchor to scroll to. Guard the call so that TTS still works + // on PDFs, just without sentence-highlight sync. + if (typeof this.renderer.scrollToAnchor === 'function') + this.renderer.scrollToAnchor(range, true) + }), granularity) } startMediaOverlay() { const { index } = this.renderer.getContents()[0]