9

I'm making a project for school where we'll teach children to calculate for the first time. Unfortunately these children can't read so the task will be spoken to them in there native language, which in this case is Dutch.

I've been looking around and most text-to-speech javascript libs provide great support for English, but not for any other language. Also the HTML5 speechSynthesis doesn't support Dutch:

Speech synthesis voices currently supported in Chrome 35

In further research I've come across an article where you can use Google Translate Voice to generate any text into speech.

You take this as a base URL: http://translate.google.com/translate_tts

Attach your language you want so in my case Dutch

http://translate.google.com/translate_tts?tl=nl

and attach your text:

"This is a test" translated to Dutch

You would expect this to work with longer text but it doesn't.

Text to speech which is not working

Are there any other solutions? The Google Voice speaks Dutch pretty well so I would like the link to somehow work.

timr
  • 6,668
  • 7
  • 47
  • 79

1 Answers1

4

DISCLAIMER: This is probably not allowed by Google. Don't use this without permission from Google.

It's possible to use Google's text to speech with texts of any size. It requires a little tweaking though.

Here's the script:

function textToSpeech(text, language) {
    if(text === undefined || text === null || text.length === 0)
        return

    var vid = document.createElement("video")
    var textParts = []

    text.split(" ").forEach(function(word) {
        var textPartsIndex = textParts.length - 1
        var currentStr = textParts[textPartsIndex]
        if(currentStr !== undefined && currentStr.length + word.length < 100)
            textParts[textPartsIndex] += " " + word
        else
            textParts.push(word)
    })

    function play(txt) {
        vid.src = "http://translate.google.com/translate_tts?tl=" + language + "&q=" + txt
        vid.load()
        vid.play()
    }

    var partIndex = 0
    play(textParts[partIndex])

    vid.addEventListener("ended", function() {
        var part = textParts[++partIndex]
        if(part !== undefined)
            play(part)
        else
            vid.removeEventListener("ended")
    })
}

BEFORE using it you must close all Chrome browser instances and, on a windows machine, open "Run" (WIN+R) and type "chrome --no-referrers" without "

On your page, you can now write (I don't understand dutch, so it's just some sample text I found)

textToSpeech("Ik ga ervan uit dat de mens een groot vermogen bezit om externe informatie op te slorpen ,\" legt professor Georges uit . Hij kan zelfs 5 tot 6 maal méér informatie verwerken dan het debiet van het gesproken woord , 120 woorden per minuut . Teamgeest is voor mij geen ijdel woord . In de tweede plaats komen puur betekenisloze verhaspelingen niet in aanmerking , want die zijn niet ontstaan door verwarring met een ander woord .", "nl")

If your application is only run locally, ie not hosted, you don't have to run chrome with the --no-referrers command.

The reason for disabling referrers is that Google cancels your request if there's a referrer-header.

IFRAME VERSION WHICH DOESN'T REQUIRE --no-referrers

http://jsfiddle.net/9tTeg/

<body>
<script>
textToSpeech("Ik ga ervan uit dat de mens een groot vermogen bezit om externe informatie op te slorpen ,\" legt professor Georges uit . Hij kan zelfs 5 tot 6 maal méér informatie verwerken dan het debiet van het gesproken woord , 120 woorden per minuut . Teamgeest is voor mij geen ijdel woord . In de tweede plaats komen puur betekenisloze verhaspelingen niet in aanmerking , want die zijn niet ontstaan door verwarring met een ander woord .", "nl")

function textToSpeech(text, language) {
    if(text === undefined || text === null || text.length === 0)
        return

    var vid = document.createElement("iframe")
    document.body.appendChild(vid)
    var textParts = []

    text.split(" ").forEach(function(word) {
        var textPartsIndex = textParts.length - 1
        var currentStr = textParts[textPartsIndex]
        if(currentStr !== undefined && currentStr.length + word.length < 100)
            textParts[textPartsIndex] += " " + word
        else
            textParts.push(word)
    })

    function play(txt) {
        vid.src = "http://translate.google.com/translate_tts?tl=" + language + "&q=" + txt
    }

    var partIndex = 0
    play(textParts[partIndex])

    var intervalId = setInterval(function() {
        var part = textParts[++partIndex]
        if(part !== undefined)
            play(part)
        else
            clearInterval(intervalId)       
    }, 9000)
}
</script>
</body>

Improvements: Instead of separating the string by words, use dot and comma, so the pauses are more natural. Each part is currently being played with 9 seconds each, but if the words are grouped by dots and commas, you could instead calculate the amount of time each part has by looking at the length of the part, since 9 seconds might be too much then.

Jan Sommer
  • 3,698
  • 1
  • 21
  • 35
  • Nice, but I can't tell the children to run Chrome like that. – timr May 29 '14 at 14:03
  • It's the best you'll get if you want to use the browser and Google's text to speech service. An alternative is to use iframes instead of the video tag, but then you'll have to add a delay of ~10 seconds between all requests, since you won't know when the audio is done playing. – Jan Sommer May 29 '14 at 14:16
  • Or be creative! Send the kids a .lnk-file in their e-mail with which target "chrome --no-referrer". You can of course also pay for a text to speech service. – Jan Sommer May 29 '14 at 14:19
  • True that! We might just want to use an embedded video with our own voice over on a private Youtube channel. Too bad there isn't a simple solution for text-to-speech in 2014. – timr May 29 '14 at 15:00