UNESCO Mali joins 32nd national reforestation campaign launch
Read aloud2 min listen
Environmental initiative
UNESCO Mali joins 32nd national reforestation campaign launch
The 32nd edition, themed “Youth at the Heart of Environmental Citizenship for a Greener and More Resilient Mali,” aligns with national efforts to restore ecosystems, combat desertification and preserve natural resources.
July 31, 2026
180) {
if (buf.trim()) out.push(buf.trim());
buf = w;
} else {
buf = buf ? (buf + ' ' + w) : w;
}
});
if (buf.trim()) out.push(buf.trim());
});
return out;
}
function getVoice() {
var voices = synth.getVoices();
var prefix = lang === 'en' ? 'en' : 'fr';
var best = voices.find(function (v) { return v.lang.toLowerCase().startsWith(prefix) && /Google|Natural|Siri|Premium/.test(v.name); });
return best || voices.find(function (v) { return v.lang.toLowerCase().startsWith(prefix); }) || null;
}
function updateUI(playing, paused) {
isPlaying = playing;
isPaused = paused;
var active = playing && !paused;
if (iconPlay && iconPause) {
iconPlay.style.display = active ? 'none' : 'block';
iconPause.style.display = active ? 'block' : 'none';
}
root.classList.toggle(cfg.c.on, active);
if (stopBtn) stopBtn.style.display = playing ? 'inline-flex' : 'none';
if (progressWrap) progressWrap.style.display = playing ? 'block' : 'none';
}
function updateProgress() {
if (!chunks.length || !progressBar) return;
progressBar.style.width = Math.min(100, Math.round(((currentIndex + 1) / chunks.length) * 100)) + '%';
}
function startKeepAlive() {
clearInterval(keepAliveTimer);
keepAliveTimer = setInterval(function () {
if (synth.speaking && !synth.paused) { synth.pause(); synth.resume(); }
}, 8000);
}
function stopKeepAlive() { clearInterval(keepAliveTimer); }
function speakCurrentChunk() {
if (currentIndex >= chunks.length) {
stopReading();
if (metaText) metaText.textContent = cfg.done;
return;
}
var utt = new SpeechSynthesisUtterance(chunks[currentIndex]);
utt.rate = currentRate;
var voice = getVoice();
if (voice) utt.voice = voice;
utt.lang = lang === 'en' ? 'en-US' : 'fr-FR';
utt.onend = function () {
currentIndex++;
updateProgress();
if (isPlaying && !isPaused) speakCurrentChunk();
};
utt.onerror = function (e) {
if (e.error !== 'canceled' && e.error !== 'interrupted') {
currentIndex++;
if (isPlaying && !isPaused) speakCurrentChunk();
}
};
updateProgress();
synth.speak(utt);
}
function startReading() {
if (isPaused) {
synth.resume();
updateUI(true, false);
startKeepAlive();
return;
}
synth.cancel();
chunks = extractArticleText();
currentIndex = 0;
if (!chunks.length) return;
updateUI(true, false);
startKeepAlive();
speakCurrentChunk();
}
function pauseReading() {
synth.pause();
updateUI(true, true);
stopKeepAlive();
}
function stopReading() {
synth.cancel();
stopKeepAlive();
currentIndex = 0;
updateUI(false, false);
if (progressBar) progressBar.style.width = '0%';
}
if (playBtn) playBtn.addEventListener('click', function () {
if (isPlaying && !isPaused) pauseReading(); else startReading();
});
if (stopBtn) stopBtn.addEventListener('click', stopReading);
if (speedBtn) speedBtn.addEventListener('click', function () {
speedIdx = (speedIdx + 1) % cfg.speeds.length;
currentRate = cfg.speeds[speedIdx];
speedBtn.textContent = cfg.rateFmt.replace('%s', currentRate);
if (isPlaying && !isPaused) { synth.cancel(); speakCurrentChunk(); }
});
window.addEventListener('beforeunload', function () { synth.cancel(); });
if (typeof synth.onvoiceschanged !== 'undefined') synth.onvoiceschanged = function () { getVoice(); };
})();