diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -15,9 +15,7 @@
 The tool can also be used to generate completely new files from scratch; see
 below for details.
 
-If you want to learn more, here are some relevant links:
- * Discussion about Tip-Toi: http://www.quadrierer.de/geekythinking/blog/?itemid=368 (German)
- * Discussion about Tip-Toi and the related TING pen, including discussion on how to print your own books: http://www.mikrocontroller.net/topic/214479 (German)
+If you want to learn more please have a look into our wiki (https://github.com/entropia/tip-toi-reveng/wiki).
 
 The tttool tool
 ---------------
@@ -102,7 +100,7 @@
     `cabal`, and you should run the two commands
 
         cabal update
-        cabal install --dependencies-only
+        cabal install --only-dependencies
 
  3. Now you can build the program using
 
@@ -153,7 +151,7 @@
 Text to speech
 --------------
 
-If you have libttspico-utils and vorbis-tools installed, you can have tttool
+If you have `libttspico-utils` and `vorbis-tools installed`, you can have tttool
 generate audio files from text for you, which makes developing your yaml file
 much easier. See [text2speech.yaml](text2speech.yaml) for more information.
 
@@ -172,6 +170,7 @@
  * [tiptoi hacking](https://blogs.fsfe.org/guido/2014/05/tiptoi-hacking-und-systemanforderungen/) by Guido Arnold
  * [TipToi Hacking](http://www.nerd.junetz.de/blogbox/index.php?/archives/1377-TipToi-Hacking.html) and [TipToi Hacking II](http://www.nerd.junetz.de/blogbox/index.php?/archives/1378-TipToi-Hacking-II.html) by Mr. Blog
  * [Various posts](https://www.joachim-breitner.de/blog/tag/Tiptoi) by Joachim “nomeata” Breitner (the main author of `tttool`)
+ * [Self-made animal figures](https://www.youtube.com/watch?v=Yic57Y9VORA&app=desktop) demonstration video
 
 TODO
 ----
@@ -193,5 +192,5 @@
  * `matlab/` contains scripts to analyse gme files in Matlab
  * `wip/` (work in progess) contains notes about the parts of the gme files that are not
    fully understood yet.
-
+ * `perl-tools` contains a perl based script, to generate a PDF with all OID codes from a yaml-file as well some functions to generate PNG-files, inject pHYs-chunks with resolution hints into GD generated PNG files as result from some testing
 
diff --git a/src/Language.hs b/src/Language.hs
new file mode 100644
--- /dev/null
+++ b/src/Language.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Language where
+
+import Data.Aeson.Types
+import Control.Monad
+import Data.Text
+
+
+data Language = En | De | Fr
+
+defaultLanguage :: Language
+defaultLanguage = En
+
+ppLang :: Language -> String
+ppLang En = "en"
+ppLang De = "de"
+ppLang Fr = "fr"
+
+instance ToJSON Language where
+    toJSON = toJSON . ppLang
+
+instance FromJSON Language where
+    parseJSON (String "en") = return En
+    parseJSON (String "de") = return De
+    parseJSON (String "fr") = return Fr
+    parseJSON (String s) = fail $ "Unknown language \"" ++ unpack s ++ "\"."
+    parseJSON _ = mzero
+
diff --git a/src/TextToSpeech.hs b/src/TextToSpeech.hs
--- a/src/TextToSpeech.hs
+++ b/src/TextToSpeech.hs
@@ -10,16 +10,90 @@
 import Control.Monad
 import Data.Hashable
 import Text.Printf
+import Control.Exception
+import System.IO.Error
+import System.Environment
+import System.Info (os)
 
-ttsFileName txt = "tts-cache" </> "tts-" ++ map go (shorten txt) <.> "ogg"
+import Language
+
+ttsFileName lang txt =
+    "tts-cache" </> "tts-" ++ map go (shorten txt) ++ "-" ++ ppLang lang <.>  "ogg"
   where go '/'         = '_'
         go c | c < ' ' = '_'
         go c           = c
         shorten x | length x > 20 = printf "%s-%016X" (take 20 x) (hash x)
         shorten x                 = x
 
-textToSpeech :: FilePath -> String -> IO ()
-textToSpeech fn txt = do
+
+pico :: Language -> FilePath -> String -> (String, [String])
+pico lang tmp txt =
+   ("pico2wave", ["--wave", tmp, "--lang", l, txt])
+  where
+    l = case lang of 
+            En -> "en-GB"
+            De -> "de-DE"
+            Fr -> "fr-FR"
+
+espeak :: Language -> FilePath -> String -> (String, [String])
+espeak lang tmp txt =
+ ("espeak", ["-v", l, "-w", tmp, "-s", "120", txt])
+  where
+    l = case lang of 
+            En -> "en"
+            De -> "de"
+            Fr -> "fr"
+
+espeak_contrib :: Language -> FilePath -> String -> (String, [String])
+espeak_contrib lang tmp txt =
+ ("./contrib/espeak", ["-v", l, "-w", tmp, "-s", "120", txt])
+  where
+    l = case lang of 
+            En -> "en"
+            De -> "de"
+            Fr -> "fr"
+
+
+engines :: Language -> FilePath -> String -> [(String, [String])]
+engines l ft txt =
+    [ pico l ft txt
+    , espeak l ft txt
+    , espeak_contrib l ft txt
+    ]
+
+oggenc :: FilePath -> FilePath -> (String, [String])
+oggenc from to = ("oggenc", ["-Q", "-o", to, from])
+
+oggenc_contrib :: FilePath -> FilePath -> (String, [String])
+oggenc_contrib from to = ("contrib/oggenc", ["-Q", "-o", to, from])
+
+encoders :: FilePath -> FilePath -> [(String, [String])]
+encoders from to =
+    [ oggenc from to
+    , oggenc_contrib from to
+    ] 
+
+tryPrograms [] e = e
+tryPrograms ((c,args):es) e = do
+    -- Missing programs cause exceptions on Windows, but error 127 on Linux.
+    -- Try to handle both here.
+    r <- tryJust (guard . isDoesNotExistError) $ do
+        env <- getEnvironment
+        let env' | os == "mingw32" = ("ESPEAK_DATA_PATH", "contrib") : env
+                 | otherwise       = env
+        ph <- runProcess  c args Nothing (Just env') Nothing Nothing Nothing
+        ret <- waitForProcess ph
+        if ret == ExitSuccess then return True
+        else if ret == ExitFailure 127 then return False
+        else do
+            putStrLn $ "Failed to execute \"" ++ c ++ "\" (" ++ show ret ++ ")"
+            exitFailure
+    case r of
+       Right True -> return ()
+       _ -> tryPrograms es e
+
+textToSpeech :: Language -> String -> IO ()
+textToSpeech lang txt = do
     ex <- doesFileExist fn
     if ex then return () else do
 
@@ -29,17 +103,15 @@
     (tmp,h) <- openTempFile (takeDirectory fn) (takeBaseName fn <.> "wav")
     hClose h
 
-    (ret, _, err) <- readProcessWithExitCode "pico2wave" ["--wave", tmp, "--lang", "en-GB", txt] ""
-    unless (ret == ExitSuccess) $ do
-        putStrLn "Failed to execute \"pico2wave\":"
-        putStrLn err
-        putStrLn "Do you have libttspico-utils installed?"
+    tryPrograms (engines lang tmp txt) $ do
+        putStrLn "No suitable text-to-speech-engine found."
+        putStrLn "Do you have libttspico-utils or espeak installed?"
 
-    (ret, _, err) <- readProcessWithExitCode "oggenc" ["-o", fn, tmp] ""
-    unless (ret == ExitSuccess) $ do
-        putStrLn "Failed to execute \"oggenc\":"
-        putStrLn err
+    tryPrograms (encoders tmp fn) $ do
+        putStrLn "Could not find \"oggenc\"."
         putStrLn "Do you have vorbis-tools installed?"
 
     removeFile tmp
     return ()
+  where
+    fn = ttsFileName lang txt
diff --git a/src/TipToiYaml.hs b/src/TipToiYaml.hs
--- a/src/TipToiYaml.hs
+++ b/src/TipToiYaml.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE RecordWildCards, DeriveGeneric, CPP #-}
+{-# LANGUAGE RecordWildCards, DeriveGeneric, CPP, TupleSections #-}
 
 module TipToiYaml
     ( tt2ttYaml, ttYaml2tt
@@ -22,6 +22,7 @@
 import System.Directory
 import qualified Data.Map as M
 import qualified Data.Set as S
+import qualified Data.Vector as V
 import Control.Monad.Writer.Strict
 #if MIN_VERSION_time(1,5,0)
 import Data.Time.Format (defaultTimeLocale)
@@ -38,10 +39,12 @@
 import Text.Parsec.Language (emptyDef)
 import GHC.Generics
 import qualified Data.Foldable as F
+import qualified Data.Traversable as T
 import Control.Arrow
 import Control.Applicative ((<*>), (<*))
 
 import TextToSpeech
+import Language
 import Types
 import Constants
 import KnownCodes
@@ -59,7 +62,8 @@
     , ttyWelcome :: Maybe String
     , ttyProduct_Id :: Word32
     , ttyScriptCodes :: Maybe CodeMap
-    , ttySpeak :: Maybe (M.Map String String)
+    , ttySpeak :: Maybe SpeakSpecs
+    , ttyLanguage :: Maybe Language
     }
     deriving Generic
 
@@ -68,6 +72,41 @@
     }
     deriving Generic
 
+data SpeakSpec = SpeakSpec
+    { ssLanguage :: Maybe Language
+    , ssSpeak    :: M.Map String String
+    }
+
+instance FromJSON SpeakSpec where
+    parseJSON v = do
+        m <- parseJSON v
+        l <- T.traverse parseJSON  $ M.lookup "language" m
+        m' <- T.traverse parseJSON $ M.delete "language" m 
+        return $ SpeakSpec l m'
+
+instance ToJSON SpeakSpec where
+    toJSON (SpeakSpec (Just l) m) = toJSON $ M.insert "language" (ppLang l) m 
+    toJSON (SpeakSpec Nothing m)  = toJSON $ m
+
+toSpeakMap :: Language -> Maybe SpeakSpecs -> M.Map String (Language, String)
+toSpeakMap l Nothing = M.empty
+toSpeakMap l (Just (SpeakSpecs specs)) = M.unionsWith e $ map go specs
+  where
+    go (SpeakSpec ml m) = M.map ((l',)) m
+      where l' = fromMaybe l ml
+    e = error "Conflicting definitions in section \"speak\""
+          
+
+newtype SpeakSpecs = SpeakSpecs [SpeakSpec] 
+
+instance FromJSON SpeakSpecs where
+    parseJSON (Array a) = SpeakSpecs <$> mapM parseJSON  (V.toList a)
+    parseJSON v = SpeakSpecs . (:[]) <$> parseJSON v
+
+instance ToJSON SpeakSpecs where
+    toJSON (SpeakSpecs [x]) = toJSON x
+    toJSON (SpeakSpecs l)   = Array $ V.fromList $ map toJSON $ l
+    
 options = defaultOptions { fieldLabelModifier = map fix . map toLower . drop 3 }
        where fix '_' = '-'
              fix c   = c
@@ -94,6 +133,7 @@
     , ttyMedia_Path = Just path
     , ttyScriptCodes = Nothing
     , ttySpeak = Nothing
+    , ttyLanguage = Nothing
     }
 
 
@@ -211,13 +251,15 @@
             , Line _ cs as _ <- ls
             , r <- concatMap F.toList cs ++ concatMap F.toList as ]
 
+    let ttySpeakMap = toSpeakMap (fromMaybe defaultLanguage ttyLanguage) ttySpeak
+    
     -- Generate text-to-spech files
-    forM (maybe [] M.elems ttySpeak) $ \txt -> do
-        textToSpeech (ttsFileName txt) txt
+    forM (M.elems ttySpeakMap) $ \(lang, txt) ->
+        textToSpeech lang txt
 
-    files <- forM filenames' $ \fn -> case ttySpeak >>= M.lookup fn of
-        Just txt -> do
-            B.readFile (ttsFileName txt)
+    files <- forM filenames' $ \fn -> case M.lookup fn ttySpeakMap of
+        Just (lang, txt) -> do
+            B.readFile (ttsFileName lang txt)
         Nothing -> do
             let paths = [ combine dir relpath
                     | ext <- map snd fileMagics
@@ -469,6 +511,7 @@
             , let chars = [oid `div` 10^p `mod` 10| p <-[4,3,2,1,0]]
             , let line = ppLine t $ Line 0 [] [Play n | n <- [0..5]] ([10] ++ chars)
             ]
+        , ttyLanguage = Nothing
         }
   where
     t= M.fromList $
diff --git a/src/tttool.hs b/src/tttool.hs
--- a/src/tttool.hs
+++ b/src/tttool.hs
@@ -254,7 +254,10 @@
 export inf out = do
     (tt,_) <- parseTipToiFile <$> B.readFile inf
     let tty = tt2ttYaml (printf "media/%s_%%s" (takeBaseName inf)) tt
-    writeTipToiYaml out tty
+    ex <- doesFileExist out
+    if ex
+        then printf "File \"%s\" does already exist. Please remove it first\nif you want to export \"%s\" again.\n" out inf >> exitFailure
+        else writeTipToiYaml out tty
 
 
 assemble :: FilePath -> FilePath -> IO ()
diff --git a/tttool.cabal b/tttool.cabal
--- a/tttool.cabal
+++ b/tttool.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                tttool
-version:             1.0
+version:             1.1
 synopsis:            Working with files for the Tiptoi® pen
 description:         The Ravensburger Tiptoi® pen is programmed via special
                      files. Their file format has been reverse engineered; this
@@ -36,6 +36,7 @@
     GMERun,
     GMEWriter,
     Lint,
+    Language,
     OidCode,
     OneLineParser,
     PrettyPrint,
@@ -64,6 +65,7 @@
     text        == 0.11.*  ||  == 1.2.*,
     parsec      == 3.1.*,
     process     == 1.1.*   ||  == 1.2.*,
+    unordered-containers  == 0.2.*,
     vector      == 0.10.*,
     yaml        == 0.8.*
 
