by Louis Vicat
Add 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.
Obsidian Pronounce π
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.
Features
- Inline trigger, no emoji required. Wrap a word in
~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.- Native Markdown
~~strikethrough~~is never affected β the parser ignores a doubled-up delimiter. - The delimiter (
~by default) is a single configurable character in Settings, in case it conflicts with another plugin.
- Quick listen on selection. Highlight any word or phrase, then:
- Right-click β Listen to pronunciation, or
- Run the Listen to selection command from the command palette
(assign your own hotkey, e.g.
Cmd/Ctrl + Shift + S, in Settings β Hotkeys), or - On mobile, add it to your toolbar above the keyboard: Settings β Mobile β Manage toolbar options β Add global command β Listen to selection.
- Read a whole vocabulary note in one pass. Run Read marked words in
note to have every
~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. - Slow down on repeat, Google Translate-style. Say the same word or
phrase again right after the first play β whether from the same
π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. - Language switcher in the status bar. A small badge (e.g.
πΈπͺ 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 frontmatterlang), the badge readsπ³οΈ Autoinstead. 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. - Strict, predictable language cascade. No guessing which language will
be used:
- Language forced inline on the word (
~word:en~). - Manual pick from the status bar / command palette (active for that note, for the rest of the session).
- The note's frontmatter:
--- lang: sv-SE --- - The plugin's default language, set in Settings.
- Language forced inline on the word (
- 100% cross-platform. Built exclusively on the standard
window.speechSynthesis(Web Speech API) β nochild_process, no system binaries. Same code path on desktop and mobile, works fully offline with on-device voices, and never sends your text anywhere.
Settings
- Default language β used when nothing else in the cascade applies.
- Voice β pick a specific system voice for the default language (e.g.
Alva Enhanced on macOS for Swedish). Voices are ranked automatically so
Apple's Premium/Enhanced tiers and the OS's own default voice are offered
first, and legacy novelty voices (Albert, Zarvox, ...) are pushed to the
bottom and labeled
[Novelty]. Download higher-quality voices from System Settings β Accessibility β Spoken Content (VoiceOver on macOS 15+) to get more/better options here. - Normal speech rate β 0.5xβ1.1x (defaults to 0.85x), used on the first click.
- Slow speech rate β 0.2xβ0.8x (defaults to 0.4x), used on repeat clicks on the same word (the Google Translate-style slow-motion toggle). Both are independent sliders, so you can tune how slow "slow" actually is.
- Pitch β 0.8xβ1.2x.
- Show in context menu β toggle the right-click Listen to pronunciation entry.
- Inline delimiter β the single character wrapping a word (default
~).
Installation
From the Community Plugins browser (once published)
- Settings β Community plugins β Browse.
- Search for Pronounce.
- Install, then enable it.
Manual install
- Download
main.js,manifest.jsonandstyles.cssfrom the latest release. - Copy them into
<your-vault>/.obsidian/plugins/pronounce/. - Reload Obsidian and enable Pronounce in Settings β Community plugins.
BRAT (beta testing)
Add LouisVct/obsidian-pronounce in the
BRAT plugin.
Known limitations
- Android doesn't work at all, and this can't be fixed from a plugin.
window.speechSynthesissimply 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.isDesktopOnlyis stillfalsebecause 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. - On iOS/iPadOS, downloaded Enhanced/Premium voices are never reachable β
only the Compact/pre-installed tier is. This is a platform limitation,
not a bug in this plugin: WKWebView's implementation of the Web Speech API
only exposes Compact voices, even when a higher-quality voice for that
language has been downloaded and selected in Settings β Accessibility β
Spoken Content. The only way around it is native
AVSpeechSynthesizeraccess, 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. - Voice availability and quality otherwise depend entirely on what's installed on the underlying OS/browser; the plugin can't bundle or download voices itself. If a language sounds robotic or doesn't speak at all, download that language's voice in your OS's accessibility settings β see the note on system voices above.
Development
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)
License
If Pronounce helps your language learning journey, consider buying me a coffee β to support development!
Created by Louis Vicat
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.