fix: 优化移动端朗读语音加载与语言匹配

This commit is contained in:
guoqingshan
2026-08-02 11:56:29 +08:00
parent 75fc9cc7a4
commit ab427d2fdc
+59 -19
View File
@@ -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;
function speakText(text, lang) {
if (!text) return;
if (!window.speechSynthesis) { return; }
if (window.speechSynthesis.getVoices().length === 0) {
window.speechSynthesis.onvoiceschanged = function() {
doSpeak(text, lang);
window.speechSynthesis.onvoiceschanged = null;
};
window.speechSynthesis.getVoices();
return;
} }
doSpeak(text, lang); return speechVoices;
} }
function doSpeak(text, lang) { function pickSpeechVoice(lang) {
window.speechSynthesis.cancel(); refreshSpeechVoices();
var target = lang.toLowerCase();
var exact = speechVoices.find(function(voice) {
return String(voice.lang || '').toLowerCase() === target;
});
if (exact) return exact;
var prefix = target.split('-')[0];
return speechVoices.find(function(voice) {
return String(voice.lang || '').toLowerCase().split('-')[0] === prefix;
}) || null;
}
function buildSpeechUtterance(text, lang) {
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();