Louis Vicat118 downloadsAdd a discreet speaker button next to any word or phrase to hear its exact pronunciation instantly, in any language - built for language learners. 100% local, works offline, on desktop and mobile.
Add a discreet speaker button next to any word or phrase and hear its exact pronunciation instantly — in any language, on any device. Built for language learners who keep vocabulary tables and want a single click or tap, without emoji-hunting or copy-pasting.
Existing TTS plugins (Apple TTS, Text to Speech, ...) are built to read
whole notes aloud for accessibility, and most rely on desktop-only binaries
(e.g. macOS's say) that don't work on mobile. Pronounce does the opposite:
it's a tiny, per-word 🔊 button built entirely on the standard
window.speechSynthesis API, no native binaries. In practice that means it
works great on macOS, Windows, Linux, and iOS/iPadOS (see the voice
quality note below for iOS); Android is currently unsupported — see
Known limitations.
Note on system voices. Pronounce runs 100% locally and offline to protect your privacy — it relies entirely on your device's own speech engine, it never sends text anywhere. To get the most natural-sounding voices (e.g. Alva Enhanced for Swedish, Samantha for English), make sure the voice for your target language is downloaded on your device:
- macOS — System Settings → Accessibility → Spoken Content → System voice (or the VoiceOver Utility on macOS 15+).
- iOS (iPhone/iPad) — Settings → Accessibility → Spoken Content → Voices. Note: only the base/Compact tier is actually usable here — see Known limitations.
- Windows — Settings → Time & Language → Speech.
Android isn't listed above because no voice setup will make this work there yet — see Known limitations.
~ and it turns into
a 🔊 button, in both Reading view and Live Preview.~mot~ → speaker button using the note's current language.~bonjour:fr~ (or ~bonjour|fr~) → forces French for that one word,
regardless of context. Both the short code (sv) and the full BCP-47
code (sv-SE) work — ~sked:sv~ and ~sked:sv-SE~ both call the
Swedish voice.~~strikethrough~~ is never affected — the parser
ignores a doubled-up delimiter.~ by default) is a single configurable character in
Settings, in case it conflicts with another plugin.Cmd/Ctrl + Shift + S, in
Settings → Hotkeys), or~word~ in the open note read aloud top to bottom,
with a short pause between each — a quick listening review of a whole
table without clicking every button. Run the command again to stop
partway through.🔊
button, a different button for that same text elsewhere in the note, or
the Listen to selection command — and it speaks at a separately
configurable slow rate so you can pick apart each syllable. Say it again
to go back to normal speed. It's a strict toggle keyed on the text itself
(not a timer, and not tied to a specific button), so repeating the exact
same word/phrase anywhere always alternates Normal → Slow → Normal.🇸🇪 SV) shows
the language currently active for the open note. Click it — or run
Pronounce: Switch language from the command palette — for an instant
picker. When nothing has been forced (no manual pick, no frontmatter
lang), the badge reads 🏳️ Auto instead. Picking 🏳️ Auto at the
top of that menu clears any manual override for the note, handing control
back to its frontmatter or the plugin default.~word:en~).---
lang: sv-SE
---
window.speechSynthesis (Web Speech API) — no child_process, no system
binaries. Same code path on desktop and mobile, works fully offline with
on-device voices, and never sends your text anywhere.[Novelty]. Download higher-quality voices from
System Settings → Accessibility → Spoken Content (VoiceOver on
macOS 15+) to get more/better options here.~).main.js, manifest.json and styles.css from the
latest release.<your-vault>/.obsidian/plugins/pronounce/.Add LouisVct/obsidian-pronounce in the
BRAT plugin.
window.speechSynthesis simply doesn't exist in the Android WebView that
Obsidian's mobile app is built on (Obsidian uses Capacitor, which embeds
Android's system WebView, not Chrome) — it's a Chromium bug open since May
2015 with no fix in sight, confirmed on
Obsidian's own forum:
a moderator explicitly declined it as a third-party/upstream issue outside
Obsidian's control. Every Web Speech API-based plugin hits this, not just
Pronounce. isDesktopOnly is still false because the plugin's own code
has no desktop-only dependency and fails gracefully (a console warning,
not a crash) — it's the platform, not the plugin, that's the gap.AVSpeechSynthesizer
access, unavailable to a web-based Obsidian plugin. Desktop platforms
(macOS, Windows, Linux) aren't affected — Enhanced/Premium/Natural voices
there are correctly detected and preferred.npm install
npm run dev # esbuild in watch mode
npm run build # type-check + production build
Symlink or copy the repo into a test vault's
.obsidian/plugins/pronounce/ folder to iterate live.
Project layout:
obsidian-pronounce/
├── manifest.json # Plugin metadata (id, name, version, isDesktopOnly: false)
├── package.json # Build dependencies (obsidian, typescript, esbuild)
├── tsconfig.json
├── src/
│ ├── main.ts # Entry point: commands, status bar, language cascade
│ ├── settings.ts # Settings tab, persistence, language list
│ ├── ttsService.ts # Wrapper around window.speechSynthesis
│ └── inlineWidget.ts # Reading-mode processor + Live Preview (CodeMirror 6) widget
└── styles.css # Speaker button + status bar styling (theme-aware)
If Pronounce helps your language learning journey, consider buying me a coffee ☕ to support development!
Created by Louis Vicat