fix: 优化移动端朗读语音加载与语言匹配
This commit is contained in:
@@ -1,32 +1,72 @@
|
|||||||
function initSpeech() {
|
var speechVoices = [];
|
||||||
|
var speechVoicesLoaded = false;
|
||||||
|
|
||||||
|
function refreshSpeechVoices() {
|
||||||
if (!window.speechSynthesis) return;
|
if (!window.speechSynthesis) return;
|
||||||
var voices = window.speechSynthesis.getVoices();
|
var voices = window.speechSynthesis.getVoices();
|
||||||
if (voices.length > 0) return;
|
if (voices && voices.length) {
|
||||||
window.speechSynthesis.onvoiceschanged = function() {};
|
speechVoices = voices;
|
||||||
|
speechVoicesLoaded = true;
|
||||||
|
}
|
||||||
|
return speechVoices;
|
||||||
}
|
}
|
||||||
|
|
||||||
function speakText(text, lang) {
|
function pickSpeechVoice(lang) {
|
||||||
if (!text) return;
|
refreshSpeechVoices();
|
||||||
if (!window.speechSynthesis) { return; }
|
var target = lang.toLowerCase();
|
||||||
if (window.speechSynthesis.getVoices().length === 0) {
|
var exact = speechVoices.find(function(voice) {
|
||||||
window.speechSynthesis.onvoiceschanged = function() {
|
return String(voice.lang || '').toLowerCase() === target;
|
||||||
doSpeak(text, lang);
|
});
|
||||||
window.speechSynthesis.onvoiceschanged = null;
|
if (exact) return exact;
|
||||||
};
|
var prefix = target.split('-')[0];
|
||||||
window.speechSynthesis.getVoices();
|
return speechVoices.find(function(voice) {
|
||||||
return;
|
return String(voice.lang || '').toLowerCase().split('-')[0] === prefix;
|
||||||
}
|
}) || null;
|
||||||
doSpeak(text, lang);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function doSpeak(text, lang) {
|
function buildSpeechUtterance(text, lang) {
|
||||||
window.speechSynthesis.cancel();
|
|
||||||
var utterance = new SpeechSynthesisUtterance(text);
|
var utterance = new SpeechSynthesisUtterance(text);
|
||||||
var langMap = { 'es': 'es-ES', 'en': 'en-US', 'zh': 'zh-CN' };
|
var langMap = { 'es': 'es-ES', 'en': 'en-US', 'zh': 'zh-CN' };
|
||||||
utterance.lang = langMap[lang] || lang;
|
utterance.lang = langMap[lang] || lang;
|
||||||
|
var voice = pickSpeechVoice(utterance.lang);
|
||||||
|
if (voice) utterance.voice = voice;
|
||||||
utterance.rate = 0.9;
|
utterance.rate = 0.9;
|
||||||
utterance.pitch = 1;
|
utterance.pitch = 1;
|
||||||
window.speechSynthesis.speak(utterance);
|
return utterance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSpeak(text, lang) {
|
||||||
|
if (!window.speechSynthesis || !text) return;
|
||||||
|
window.speechSynthesis.cancel();
|
||||||
|
window.speechSynthesis.speak(buildSpeechUtterance(text, lang));
|
||||||
|
}
|
||||||
|
|
||||||
|
function speakText(text, lang) {
|
||||||
|
if (!text || !window.speechSynthesis) return;
|
||||||
|
refreshSpeechVoices();
|
||||||
|
if (speechVoicesLoaded) {
|
||||||
|
doSpeak(text, lang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attempts = 0;
|
||||||
|
var timer = setInterval(function() {
|
||||||
|
attempts++;
|
||||||
|
refreshSpeechVoices();
|
||||||
|
if (speechVoicesLoaded || attempts >= 8) {
|
||||||
|
clearInterval(timer);
|
||||||
|
doSpeak(text, lang);
|
||||||
|
}
|
||||||
|
}, 80);
|
||||||
|
window.speechSynthesis.getVoices();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSpeech() {
|
||||||
|
if (!window.speechSynthesis) return;
|
||||||
|
refreshSpeechVoices();
|
||||||
|
window.speechSynthesis.onvoiceschanged = function() {
|
||||||
|
refreshSpeechVoices();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.readyState === 'complete') initSpeech();
|
if (document.readyState === 'complete') initSpeech();
|
||||||
|
|||||||
Reference in New Issue
Block a user