Voice Resolver Hook
Overview
Section titled “Overview”The resolveVoice hook lets integrating applications intercept the voice selector passed to speak() and transform it before the voice matching chain runs. This is useful when an external system passes voice names that don't match ResponsiveVoice's voice catalogue — instead of modifying every call site, a single hook can remap, normalize, or redirect selectors.
import { getResponsiveVoice } from '@responsivevoice/core';
const rv = await getResponsiveVoice({ apiKey: 'YOUR_KEY', resolveVoice: (selector) => { if (typeof selector === 'string') { const aliases: Record<string, string> = { 'Google UK English Female': 'UK English Female', 'Microsoft Zira': 'US English Female', }; return aliases[selector] ?? selector; } return selector; },});
// "Google UK English Female" is silently remapped to "UK English Female"rv.speak('Hello', 'Google UK English Female');Hook Signature
Section titled “Hook Signature”type ResolveVoiceHook = ( selector: VoiceSelector | undefined,) => VoiceSelector | undefined;| Parameter | Type | Description |
|---|---|---|
selector | VoiceSelector | undefined | The incoming voice selector, or undefined when no voice was specified |
| Returns | VoiceSelector | undefined | A transformed selector, or undefined to use defaultVoice |
VoiceSelector is a union of three forms (the post-parse output the hook receives):
| Type | JS form | Wire form | Meaning |
|---|---|---|---|
string | 'UK English Female' | same | Resolve by exact voice name |
RegexSelector | /Portuguese/ | { regex: 'Portuguese', flags: '' } | First voice matching the pattern |
VoiceQuery | { lang: 'pt' } | same | Structured filter (AND logic) |
The hook receives the post-parse VoiceSelector, where any incoming JS RegExp has already been normalized to the { regex, flags } literal form. The hook's return value can be either form — a returned RegExp is normalized the same way before reaching the resolver.
Return Value Semantics
Section titled “Return Value Semantics”| Hook returns | What happens |
|---|---|
A string | Resolves by name (exact match, then fallback chain) |
A RegExp or RegexSelector | Resolves by pattern (first match) |
A VoiceQuery | Resolves by structured query (lang, gender, provider) |
undefined | Falls through to the configured defaultVoice |
Patterns
Section titled “Patterns”Static aliasing
Section titled “Static aliasing”Map legacy or external voice names to ResponsiveVoice names:
resolveVoice: (selector) => { if (typeof selector === 'string') { const map: Record<string, string> = { 'old-voice-name': 'UK English Female', 'legacy-male': 'US English Male', }; return map[selector] ?? selector; } return selector;},Locale-based routing
Section titled “Locale-based routing”Redirect to a locale-appropriate voice when the exact name doesn't exist:
resolveVoice: (selector) => { if (typeof selector === 'string' && !knownVoices.has(selector)) { const locale = extractLocale(selector); const gender = extractGender(selector); return { lang: locale, gender }; } return selector;},Debug logging
Section titled “Debug logging”Observe what selectors are being passed without changing behavior:
resolveVoice: (selector) => { console.log('[RV] resolving voice:', selector); return selector;},TypeScript
Section titled “TypeScript”Both ResolveVoiceHook and VoiceSelector are exported from @responsivevoice/core:
import type { ResolveVoiceHook, VoiceSelector } from '@responsivevoice/core';
const myHook: ResolveVoiceHook = (selector) => { // your logic return selector;};