A dictation assistant for code-switching language learners.
LingoGap lets you dictate in English and seamlessly drop into your native language the moment a word escapes you. Those foreign words are transcribed, automatically translated back to English, highlighted inline, and kept for review — so a momentary gap in your vocabulary never breaks your flow.
When you learn a language, the hardest moment is the gap — you know the whole sentence except one word. Most people stop, break their train of thought, and reach for a dictionary. LingoGap closes that gap in real time:
"I really wanted to explain my idea in English but I got stuck on [poczucie odpowiedzialności → sense of responsibility] and had to switch."
You keep speaking. LingoGap fills in the word, translates it, and remembers it for later.
- 🎙️ Real-time speech-to-text — powered by the browser-native Web Speech API (continuous recognition with live interim results).
- 🔀 Mid-sentence language switching — toggle Polish mode with a button or the Alt key without stopping the recording.
- 🌐 Automatic Polish → English translation — spoken Polish is translated on the fly via the MyMemory API (no API key required) and cached to avoid repeat lookups.
- ✨ Inline highlighting — translated words are highlighted; hover to see exactly what you originally said in Polish.
- ✏️ Editable transcript — fix mistakes directly, using a simple
[polish | english]bracket syntax to mark translated segments. - 📋 One-click copy of the full transcript.
- 📊 Live stats — segment count and number of translated words, with a one-click clear.
- 🌗 Dark / light theme with a persistent toggle.
- Click Start Recording and speak in English.
- When you forget a word, click Switch to Polish (or press Alt).
- Say the word in Polish — it is auto-translated, highlighted, and inserted into your sentence.
- Click Back to English (or press Alt again) to continue.
- Hover any highlighted word to reveal the original Polish.
Under the hood, switching modes stops the current recognition session and restarts it with the matching language (en-US ↔ pl-PL), because the Web Speech API only recognizes one language per stream. Final Polish segments are passed to the translation service, and the result is rendered as a highlighted, hover-annotated segment.
| Area | Technology |
|---|---|
| Framework | React 19 + TypeScript |
| Build tool | Vite 8 |
| Styling | Tailwind CSS 4 |
| UI components | HeroUI |
| Animation | Framer Motion |
| Routing | React Router 7 |
| Theming | next-themes |
| Speech | Web Speech API (browser-native) |
| Translation | MyMemory Translation API |
- Node.js 18+ and npm
- A Chromium-based browser (Chrome or Edge) — the Web Speech API is not available in all browsers.
git clone https://github.com/Dotims/LingoGap.git
cd LingoGap/lingoGap
npm install
npm run devThen open the URL printed by Vite (default http://localhost:5173).
| Script | Description |
|---|---|
npm run dev |
Start the Vite dev server with HMR |
npm run build |
Type-check and build for production |
npm run preview |
Preview the production build locally |
npm run lint |
Run ESLint |
In edit mode, translated words use a bracket notation so you can adjust both sides:
[polska fraza | english phrase]
Plain text outside brackets is treated as regular English. This is also a convenient way to seed a transcript by hand.
lingoGap/
├── src/
│ ├── components/
│ │ ├── DictationPanel.tsx # Main dictation UI
│ │ ├── Header.tsx
│ │ ├── ThemeToggle.tsx
│ │ └── ui/buttons.tsx
│ ├── hooks/
│ │ └── useDictationRecognition.tsx # Speech recognition + language switching
│ ├── lib/
│ │ ├── transcriptUtils.ts # Segments, tokenizing, edit parsing
│ │ └── translationService.ts # Polish → English translation + cache
│ ├── pages/
│ │ ├── HomePage.tsx
│ │ └── FlashcardsPage.tsx
│ └── App.tsx
└── package.json
- Flashcards — persist translated words and review them on the Flashcards page (currently a placeholder).
- Additional source languages beyond Polish.
- Spaced-repetition review.
- Export vocabulary.
LingoGap relies on the Web Speech API and is fully supported in Chrome and Edge. In unsupported browsers the app displays a notice instead of the recorder.
