Demystifying Mandarin: language learning apps comparison

Since I couple of years I’ve been intrigued by the “Chinese language”. Especially the Mandarin writing language always fascinated me. How can a language have sooo many ‘letters’ in its alphabet…And how in xxx’s name is one able to learn that many words and syllables?! 

From time to time I pick up some of the books on Mandarin writing and reading that are gathering dust here…But it’s never more than ‘picking up, leaving through it and putting it away.’

The 21st century however might have the solution beforehand! Apparently there’s a thing called apps. Small little software applications that run on your mobile phone. There’s a gazillion language learning app…and I tried many of them. In this post I briefly review those app that ‘survived’ my comparison and which I now can recommend!

Note: even though I only compared the apps to learn Mandarin Chinese, most can also be used to learn other languages.

I’ve sorted the apps in two sections:

  • A getting started sections: apps I recommended if you’re totally new to the language
  • An advanced section: great apps once you’ve learned the basics of the language

All apps have Android and iPhone versions.

Getting started app


Aka old faithful.

I love DuoLingo, I’ve used it to freshen up my Français and even briefly learned the essentials of Russian with it.

For Mandarin Chinese, the app is ‘handy’, but in my opinion not the best in line.


  • Learn to read syllables, words, sentences
  • Slow learning curve, that you can tweak yourself by simply starting extra topics.
  • Has a “review” section and excercise
  • Good gamification


  • Many excercises show a written syllable followed by the pronunciation. You then have to select what the syllable sounds like (in pinyin). Which is rather silly since the app itself already gave the answer.
  • Strange order of learning sometimes. Especially the beginning was confusing. This guys has a more extreme viewpoint on the problem, but he isn’t completely wrong.
  • No speaking/recording exercises
  • Uses the spaced repetition learning method a bit to stringent: as long as you fail for a certain question, it will keep coming back till you solve it. This especially gets annoying if you have to write a long sentence and have one minor mistake. Memrise does this way better.


A very stylish app that uses spaced repetion learning (of which I’m quiete a fan), but on steroids and in way more sleek and fun manner.


  • Fun to learn new syllables and words
  • Perfect for that 3-minute bathroom break


  • Only useful the freshen up your vocabulary
  • Learned syllables (for now) stay in their category: there’s no way to review all you learned throughout all categories. The “dojo” , which unlocks if you have learned enough words, does this, but not for the syllables
  • I disabled the writing questions because they popped up way more often than the other questions
  • There’s a certain predictable rhythms in the type of questions which, in my opinion, partly defeats the way one should learn the language.


At the moment, Memrise is the first app I start up if I feel like learning. It used to be DuoLingo, however Memrise (Pro) is way more fun and has more variation. I especially like the way it suggests what type of excercise you should do next.


  • Learn writing, reading, speaking and listening  (including with locals if you own the pro version)
  • The flow/difficulty of this app feel the best so far.
  • Very fun and good gamification with splendid UI.
  • If you answer incorrect, it will immediately show the corresponding flashcard (DuoLingo is way more irritating in that aspect)


  • Not all flashcards are complete (though it gives you the option add stuff yourself)



A very thorough and professional looking app. As far as I can tell, it’s made by Asian, as it’s only usable to learn certain Asian languages (which is a good thing).

This app quickly lets you write short sentences with the few words you’ve learned, which makes it a very fulfilling experience.


  • Rapid, usable results (e.g. understand short sentences)
  • Learn writing, reading and grammar
  • Good review section
  • Simple, yet nice and fun design.


  • A bit daunting at first, but way more forgiving then Mondly
  • Not so sexy as the other apps

Advanced apps


I’ve only briefly used this one because the learning curve was very steep. The main forte of this app is the integration with foreign speaker that help you correct your writing and speaking skills.

The app itself is very thorough and I’m pretty sure it will become very handy once I get through the basics.


And I though Busuu was hard, or DuaLingo irritating. I’m not sure yet what to think of Mondly. It’s very big, has many of the features all above apps also have. And it even has a bot to talk to.

I just don’t understand their learning method: they show an english word, like man, and then show 4 big pictures one of a man, a woman, a child and a tree. To Mandarin word that each picture depicts is written very small on each picture. In other words, you seem to be learning English and not mandarin.

Once you then get through those ‘warming up’ questions you are immediately thrown into the deep and have to solve large, difficult sentences without any help.

I’m not yet deleting the app because I like the amount of content they have and I think it well, just as Busuu, become more handy once I get through the basics.


This is a sweet one. The app contains many texts (mainly popular fairy tales) in both English and Mandarin. You can read (and listen) to the stories and choose what to see: only the Mandarin text, or in a splits view both languages. The app shows where you are in the stories, making it a great tool to really learn to read.

But yeah, this is definitely an advanced app. I’ll be back on it.

Honourable mentions

Some apps I didn’t test thoroughly (or not at all) but that might be interesting:

The Chairman’s Bao (price for the most funny named app)




So what app should I pick?

If you have to choose because you don’t have time to open 5 apps every day to learn, my personal top 5 for beginners would be:

  1. MemRise
  2. LingoDeer
  3. DuoLingo

Later on, if you’ve acquired the basics:

  1. LingoDeer
  2. Busuu
  3. Mondly

Exporting open office with equations to markdown and mathjax/tex formulas

Well, that was the most un-inspirational title ever. Especially because this is the first blog post in ages on here. Anyhow….

The problem:

So a colleague of mine wrote a very hefty 300 pages tome on electric fundamentals. It is written in Microsoft Word but, being the 21st century and all, we really would love to have this syllabus also as an online However, it contains over 700+ equations that just won’t get converted.

When we used gitbook-convert on the .docx the output it generated was okay-ish (though the image uris needed some manual labor afterwards). However, no equations to be found whatsoever, it simply skipped those like a lazy student.

The solution:

After dicking around with several “solutions” from stackoverflow we finally managed to get the solution ourself. As a fair warning: I suck/can’t use regex so you will see some cringy stuff down here…but hey, it works and that’s what count!

How we solved it:

  1. Saved the .docx document as an open office document (ODT) from within Microsoft Word.
  2. Send the odt through my epic code (seen below) which does:
    1. Unpack the odt file (it’s just a zip with lots of xml-files)
    2. Identify the equations in the document
    3. Transforms the equations to Mathjax compatible versions
    4. Insert transformed equations into odt
    5. Repack everything to an odt file
  3. Send the odt through gitbook-convert
  4. Profit!

Gimme epic code!

Ok, so step 2 was ofcourse the main problem. Here’s “a solution”, but as warned it’s just a quick’n dirty fix.

Step 1: Unpack the odt file

  System.IO.Compression.ZipFile.ExtractToDirectory(source, tempfolder);

Easy huh 😀

Step 2: Identify the equations in the document
Using a very science-y way we discovered that all equations are conveniently inside subfolders called “Object x” (x being a number) in which the actual equations is described in a separate content.xml document using mathml, the openoffice way of describing equations.

So we used a simple loop over all extracted folders to identify  the xml-files we needed.

            List<String> files = new List<String>();

                foreach (string d in Directory.GetDirectories(sDir))
                    if (d.Contains("Object"))
                        var filesc = Directory.GetFiles(d);

                        foreach (var item in filesc)
                            if (item.Contains("content.xml"))


            catch (System.Exception )
                //On to the next file!

            return files;

Step 3: Replace the equations in the document with Mathjax compatible version
This is the meaty part of the solution.
There’s several XSL-files to be found online that  transform MathML to MathJax/Tex format. So we used one such as this one.

So first we iterate over all the found xml-files from the previous step and transform them using the xsl-files:

                foreach (var item in files)
                    var myXslTrans = new XslCompiledTransform();
                    using (StringWriter sw = new StringWriter())
                    using (XmlWriter xwo = XmlWriter.Create(sw, myXslTrans.OutputSettings)) // use OutputSettings of xsl, so it can be output as HTML
                        myXslTrans.Transform(item, xwo);

Next we need to safe this transformed equation so we can later on inject it inside the actual odt-document.

Before saving the transformation I also cleaned it up a bit so that gitbook won’t start crying like a little baby (It’s not very happy with two opening curly braces next to each other and with multiline equations). After cleanup I save each equation in a dictionary with the foldername being the key since this is the same id the main odt-document (content.xml in the root of the odt/zip) used to pinpoint to the xml files in the Object-folder (long sentence, too tired to write out :p) .

And finally I add the much needed extra dollar signs since my xsl only adds one and we definitely need two at the start and end:(

                        string dirname = new DirectoryInfo(Path.GetDirectoryName(item)).Name;
                        string texform = sw.ToString();
                        if (!texform.StartsWith("$"))  //Replace multiline equations to single lines
                            texform = $"${texform.Replace(Environment.NewLine, String.Empty)}$";
                        texform = ("$" + texform + "$").Replace("{{", "{ {"); 
                        res += $"{dirname};{texform};{Environment.NewLine}";

                        eqslistres.Add(dirname, texform);

Step 4: Insert transformed equations into odt
Next step we replace all equation-xml-elements inside the main document  with new textspan-elements that contain our transformed equations:

            var doc = XDocument.Load(path + "\\content.xml");

            var desc = doc.Descendants("{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}" + "frame").ToList();
            for (int i = 0; i < desc.Count(); i++)
                var item = desc[i];
                var obj = item.Descendants("{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}" + "object").FirstOrDefault();
                if (obj != null)
                    var atr = obj.Attribute("{}" + "href").Value.Replace("./", string.Empty);
                    if (atr.EndsWith("/"))
                        atr = atr.Replace("/", string.Empty);
                    if (records.ContainsKey(atr))

                        XElement v = new XElement(XName.Get("span", "urn:oasis:names:tc:opendocument:xmlns:text:1.0"));


Step 5: Repack everything to an odt file
Last but not least: we save the new xml:

doc.Save(path + "\\content.xml");

And repack everything:

System.IO.Compression.ZipFile.CreateFromDirectory(tempfolder, "mynewepicbook.odt");

One final step

We can now send this odt through gitbook-convert and all the equations, as by magic, will be there and rendered in all it’s glory!

There’s only one final step to do. The formulas will only be rendered in gitbook if you add the mathjax-plugin. Add a book.json file to the root of your gitbook folder and add it:

"gitbook": "3.2.3",
"plugins": ["mathjax"]


Please note, that if you serve the book for the first time (using gitbook serve) the formules might not render in your browser. There’s some delay there. Simply refresh, or wait a few seconds and normally all should show up as promised!

And so we go from:



PS Check out the epic course (in Dutch) on Electric Fundamentals here!

How to create a simple office VSTO add-in :A step by step guide

In this short guide I will show how to create a simply outlook-plugin (VSTO  add-in), consisting of a button that can be clicked in the Ribbon-bar and that will result in some custom action (in this case saving all attachments to your computer).

The reason I wrote this guide is because the standard documentation didn’t really go all-the-way and/or went too deep too fast while creating a plugin I needed (a “Send All Attachments to Calibre” add-in, more info here).

Hence this epic guide.


Let’s go after the fold! Read more of this post

Send Attachment To Calibre-plugin for Outlook 2016

Wrote a small Outlook 2016 plugin (VSTO) that will easily send all attachments in an email to your Calibre database. All code and the installer can be found here:

See here how it works in full action:

A future blogpost will explain some of the inner workings.

8BitDo controller input in MonoGame (and Steam)

And you thought this blog was dead? I’m back 🙂

To business: I recently bought two 8bitdo Nintendo Controllers (8Bitdo Crissaegrim NES30 PROnes30-pro to use with RetroPi (works like a charm by the way).

However, to get them to work on my computer was something else.

The controllers don’t talk very nicely with your PC, so Steam and Monogame basically say ‘$$$$ you’ when you try to use the controller. However, the solution came in the form of this nifty tool: x360ce.

Ok, now what? Play steam games?!

The thing to know with x360ce is that you need to place the executable in each folder of the game(s) you’d like to play with your computer.

Paste the exe there, launch it, let it create the necessary files, test the controller and presto: you can now launch the game (from within steam if you also want your steam controllers to work) and the games will now detect your controller as if it were an Xbox 360 controller. (protip: this also works if you’re using the controller wireless, even with two of them connected without wires)

Pressing lots of stuff on the controller and simultaneous trying to take a screenshot...not easy, try it yourself!

Pressing lots of stuff on the controller and simultaneous trying to take a screenshot…not easy, try it yourself!

Monogame as well?

Yup, the same trick here. Simply put the x360ce exe in your debug/bin folder, launch it, and suddenly you can type fancy code such as (source) :

 if (capabilities.IsConnected)
                // Get the current state of Controller1
                GamePadState state = GamePad.GetState(PlayerIndex.One);

                // You can also check the controllers "type"
                if (capabilities.GamePadType == GamePadType.GamePad)
                    if (state.IsButtonDown(Buttons.A))

Hooray for this. On to toying around with this sweet nostalgic controller

A cheaper Freewrite: some linuxnoob tips

Not having the funds to buy myself a Freewrite (formerly known as HemingWrite) I blew the dust from an old, but still working netbook (Samsung N150) and followed this great tutorial “How to turn your laptop into a typewriter“.

Here’s some handy tips if you want to redo the tutorial yourself

After install black screen

Apparently the Ubuntu Server is very barebones and on my netbooks it simply boots to a blank screen with a blinking cursor. Nothing more. To get started, you need to open up a terminal using ctrl+alt+F1. Yeah, I’m a linux noob.

Only boots using usb stick 😦

I followed the tutorial as is and discovered that my fresh Ubuntu wouldn’t boot unless I inserted the original USB-stick from which I had installed Ubuntu in the first place. The problem? The Ubuntu installer installed Grub on the stick instead of on the master hard disk.
This can be remedied simply by using the command:

sudo grub-install /dev/sda

Autologin and boot to terminal

The part about configuring tty1 to automatic login doesn’t work anymore in more recent Ubuntu Server version. What you will need to do is override the getty.service, as explained here.


sudo systemctl edit getty@tty1

Then add the following content:



ExecStart=-/sbin/agetty --autologin yourusername --noclear %I 38400 linux


Save and exit.

Next, you will want to change the bootloader, grub, settings:

sudo nano /etc/default/grub

and change the GRUB_CMDLINE_LINUX_DEFAULT value to text.

Next up, write the changes to grub:

sudo update-grub

Connecting to wifi is real hard

Most modern wifi networks have WPA or WPA2 security, which is a bit of a pain in the a$$ to get connected to using a terminal-only shell.
Luckily a nifty tool called “nmtui” exist which is basically a text-based UI network configurator.It can be installed using:

sudo apt-get install network-manager

and can then be started by typing:


Getting battery status

Use upower as explained here.

Twoway databinding to a MongoDB collection in WPF

I’ll show how to have a two-way databinding between a templated listbox and a MongoDB collection.
I’m finally got around toying with MongoDb.What I’ll show next might not be the most correct way, but it works for me.


I have a Listview defined in XAML with a datatemplate:

        <ListBox Name="mylistbox">
                    <TextBox Text="{Binding Naam, Mode=TwoWay}"></TextBox>

I created an Entity class (can be a composite if you wish) which is is simple POCO with INotifyPropertyChanged implented. This Entity class well be serialized to my MongoDB collection as-is. Explained here, for example:

        public class Entity
            public string Naam { get; set; }

Retrieve the data and databind

Next up, we need to retrieve the data using a query (coll being my collection a retrieved earlier on (not shown)):

var query = coll.AsQueryable<Entity>().ToList();

The ToList part is important.This will ensure that we get a simple list of Entity objects as our ItemSource and not an IQueryable, otherwise the next part won’t work.

Write changes to database

You can now edit your data in your listbox and once you are ready, you can update all the changes to your MongoDB collection:

            foreach (var item in mylistbox.ItemsSource)