I’m at that stage of learning French where I can read a novel, but not without stopping every couple of paragraphs to look something up. Solid B1, creeping toward B2. I can follow the plot. I can get the gist. But every few lines there’s a word that could mean three different things depending on context, and if I just guess, I’m probably going to learn the wrong meaning and carry it around for months.
The standard advice is to look it up. And that’s correct. The act of actively searching for a word builds stronger neural pathways than having someone hand you the answer. But when I’m reading on my couch and I have to pick up my phone, open an app, type the word (with accents I don’t have memorized on the keyboard), read the definition, and then find my place again… I’m not reading anymore. I’m doing vocabulary drills that happen to be interrupted by a novel.
I wanted something in between. Not a flashcard system, not a study tool. A way to keep reading without stopping too much, and without filling in the gaps wrong from context.
Phone on the counter
The concept is dead simple. I set my phone on the counter, or the table, or wherever I’m reading. When I hit a word I don’t know, I say it out loud. The app recognizes the French, looks up the English translation, displays it, and reads it back to me. My eyes never leave the page.
I know this isn’t optimal for retention. I’m trading memory strength for reading flow. But the goal isn’t to memorize every word on first encounter. It’s to get through 40 pages instead of 12, and to not build a mental dictionary of wrong definitions by guessing from context clues that I’m not advanced enough to read correctly yet.
How it works
The whole thing is a single HTML file. No framework, no build step, no backend. It uses the Web Speech API (built into Chrome and Edge) for voice recognition with the language set to fr-FR, the MyMemory translation API for French-to-English lookups, and the browser’s built-in text-to-speech to read the result back.
There’s a gender detection feature too. French nouns are masculine or feminine, and the endings give you a decent clue. The app guesses based on common patterns and shows a colored badge next to the word, pink or blue. It’s heuristic, not dictionary-backed, so it’s wrong sometimes. But when I’m mid-page and just want a rough sense of the article to use, it does the job.

I can say whole phrases too, not just single words. Saying “entre guillemets” gives me “between quotation marks.” Saying “dispositif de secours” gives me “backup device.” If I’m somewhere I can’t talk out loud, or the recognition is mangling my pronunciation on a specific word, there’s a text input as a fallback.
The whole thing runs on GitHub Pages. No server, no cost, and I can pull it up on my phone’s browser while I read.
The debugging war
Getting speech recognition to work was straightforward. Getting it to work continuously was a different story.
The first version worked fine for one word. Say “bonjour,” get a definition, great. Say a second word and nothing happened. The app looked alive. The button still said “Stop Listening,” the status dot was green. But it had gone deaf.
Here’s what was happening: while the app processed a word (the API call, then the text-to-speech playback), a flag blocked all incoming speech. Anything I said during that window got dropped silently. No error, no feedback, just gone. And the browser’s text-to-speech onend event? It sometimes just doesn’t fire. Known quirk, no fix. When that happened, the flag stayed on forever and the app was bricked until I refreshed.
It got worse before it got better. At one point the microphone was re-prompting for permission on every recognition cycle. The app started catching its own TTS output and trying to look up its own definitions in an infinite loop. We didn’t just screw the pooch. Basically every dog in the neighborhood.
The fix was an interrupt system. Instead of dropping speech during processing, the app now queues the new word and cancels the current playback. A timeout fallback catches the cases where onend never fires. And recognition stops entirely during TTS so the microphone doesn’t pick up the speaker. Now I can say a new word mid-definition and it switches right over.
Tradeoffs I’m fine with
The MyMemory translation API is free, but the free tier caps at 5,000 characters per day. Since it’s on GitHub Pages with no login, every person who visits shares that same daily bucket. For something I use a few times a week, this hasn’t been a problem. If it ever is, I’ll swap APIs or add a key.
I tried adding English text-to-speech for the translation portion, so it would say “femme signifie” in French and then “woman” in English. Switching TTS languages mid-sentence didn’t work well in any browser I tested. I killed it after one session. Sometimes the simpler version is the better version.
Gender detection is a guess, not a lookup. Common patterns are right, exceptions are wrong. Good enough for a reading aid, not good enough for a grammar quiz.
Try it out
The app is live at jondufault.github.io/french-verbal-dictionary and the source is on GitHub. It’s one HTML file.
On the list for later: tracking how often each word gets looked up (to spot my persistent gaps), and a local cache with export so I can feed lookups into a spaced repetition system. For now it does the one thing I needed. I can read without stopping.
Leave a Reply