How FluidVoice Handles Different Languages: A Complete Technical Guide
FluidVoice manages multilingual speech recognition through a central VoiceEngineLanguageCatalog that defines language metadata, generates model-specific routes, and applies user selections to the transcription pipeline.
The FluidVoice iOS application supports dozens of languages across multiple speech-to-text engines including Apple Speech, Whisper, Cohere, Nemotron, and Parakeet. This article examines the complete architecture—from language definitions through UI selection to provider-level execution—based on the actual source code implementation.
The VoiceEngineLanguageCatalog: Central Language Registry
All language handling in FluidVoice originates in [VoiceEngineLanguageCatalog.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/VoiceEngineLanguageCatalog.swift). This file contains three critical responsibilities: static language definitions, route generation for available models, and persisting user selections.
Language Definitions Structure
The catalog maintains a comprehensive list of supported languages through the languageDefinitions property. Each language carries:
id– unique identifier (e.g.,"en","es","ja")displayName– localized human-readable namealiases– alternative names for search matchingisPopular– flag for prominent UI placement
// Conceptual representation based on implementation patterns
struct LanguageDefinition {
let id: String
let displayName: String
let aliases: [String]
let isPopular: Bool
}
The catalog exposes convenience accessors for different UI contexts:
// Retrieve all languages with at least one compatible model route
let allLanguages = VoiceEngineLanguageCatalog.allLanguages()
// Get prominently displayed languages for onboarding
let popularLanguages = VoiceEngineLanguageCatalog.popularLanguages()
// Search with normalized query matching against name, ID, and aliases
let searchResults = VoiceEngineLanguageCatalog.searchableLanguages(query: "espanol")
LanguageBinding: Mapping Languages to Speech Engines
The inner LanguageBinding enum defines how each speech engine consumes language information. This abstraction allows the same language definition to route differently depending on the target provider.
| Binding Type | Behavior | Example ID |
|---|---|---|
automatic |
Engine infers language from audio | whisper-automatic |
appleSpeech |
Uses Apple-specific locale identifier | apple-speech-en-US |
cohere |
Explicit language code for Cohere API | cohere-en |
nemotron |
Explicit language code for Nemotron API | nemotron-es |
whisper |
Explicit language code for Whisper model | whisper-fr |
Reference: LanguageBinding enum definition
Each binding generates a unique route identifier through its id computation, ensuring no collisions between different engine-language combinations.
Route Generation: Building Compatible Pipelines
The routeCandidates(for:) method transforms a language definition into actionable transcription pipelines. This function evaluates:
- Model availability – whether Parakeet V3, Cohere, Nemotron, or Whisper support the language
- Apple Speech compatibility – checking both modern analyzer locales and legacy speech recognition locales
- User preference eligibility – filtering to routes actually usable by installed models
// Generate all possible routes for a specific language
if let japanese = VoiceEngineLanguageCatalog.language(id: "ja") {
let candidates = VoiceEngineLanguageCatalog.routeCandidates(for: japanese)
// candidates might include:
// - Whisper-japanese (automatic or explicit)
// - Nemotron-japanese
// - Apple Speech with ja-JP locale
}
The returned [VoiceEngineLanguageRoute] objects encapsulate both the language and the specific binding required by each engine. Routes are then filtered against SettingsStore.shared.availableModels, ensuring only operational pipelines are presented to users.
Reference: routeCandidates implementation
Persisting Selections: The Apply Mechanism
Once a user selects a language-route combination, apply(_:, to:) commits the choice to persistent storage. This method:
- Extracts the
LanguageDefinitionandLanguageBindingfrom the route - Updates
SettingsStore.shared.selectedLanguage - Sets the appropriate model-specific language property (e.g.,
selectedWhisperLanguage,selectedNemotronLanguage) - Triggers transcription engine reconfiguration
// Apply a selected route to configure the transcription pipeline
let selectedRoute: VoiceEngineLanguageRoute = /* user selection */
VoiceEngineLanguageCatalog.apply(selectedRoute)
The SettingsStore persists these values across app launches and makes them observable for real-time UI updates.
Reference: apply method
UI Integration: Onboarding and Language Selection
FluidVoice's onboarding flow surfaces language selection through [WelcomeView.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/UI/WelcomeView.swift) and [OnboardingTryoutStepView.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/UI/OnboardingTryoutStepView.swift).
WelcomeView Language Interface
The welcome screen presents:
- Popular languages as tappable cards for immediate selection
- Search interface querying
searchableLanguages(query:)with debounced input - Full language list for manual browsing
// Simplified representation of WelcomeView language selection
struct LanguageSelectionSection: View {
@State private var searchQuery = ""
var body: some View {
if searchQuery.isEmpty {
PopularLanguagesGrid(
languages: VoiceEngineLanguageCatalog.popularLanguages()
)
} else {
SearchResultsList(
languages: VoiceEngineLanguageCatalog.searchableLanguages(query: searchQuery)
)
}
}
}
Reference: WelcomeView language UI section
Try-It-Out Flow
After language selection, OnboardingTryoutStepView displays example prompts in the chosen language and initiates a test transcription. This validates that the selected route functions correctly before completing onboarding.
Reference: OnboardingTryoutStepView examples and flow
Provider-Level Language Execution
Individual speech engines consume the persisted language settings through model-specific properties in [SettingsStore.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift). The NemotronProvider exemplifies this pattern:
// NemotronProvider checking and applying language configuration
func setTargetLanguageIfNeeded() async throws {
let targetLanguage = SettingsStore.shared.selectedNemotronLanguage
// Only update if language actually changed
if currentLanguage != targetLanguage {
try await apiClient.setLanguage(targetLanguage)
currentLanguage = targetLanguage
}
}
Similar patterns exist across WhisperProvider, CohereProvider, and the Apple Speech integration. Each provider maps the generic LanguageDefinition to engine-specific parameters.
Reference: NemotronProvider language switch implementation
Adding New Language Support
The modular architecture enables straightforward language expansion:
- Add definition – append to
languageDefinitionsinVoiceEngineLanguageCatalog.swift - Declare model support – update
routeCandidates(for:)to include new language-model combinations - Configure provider mappings – ensure each relevant provider can consume the new language code
No UI changes are required unless the language qualifies for the "popular" designation.
Summary
VoiceEngineLanguageCatalogserves as the single source of truth for language metadata and routingLanguageBindingabstracts engine-specific language consumption patternsrouteCandidates(for:)dynamically generates compatible transcription pipelinesapply(_:, to:)persists selections toSettingsStorefor cross-session retention- Onboarding UI leverages catalog search and popular language APIs for intuitive selection
- Provider implementations execute language-specific configuration at runtime
Frequently Asked Questions
How does FluidVoice detect which languages are available on a device?
The catalog filters routeCandidates against SettingsStore.shared.availableModels, which reflects installed transcription engines and their capabilities. Apple Speech availability additionally checks SFSpeechRecognizer.supportedLocales() at runtime.
Can FluidVoice automatically detect spoken language without user selection?
Yes. The LanguageBinding.automatic option enables Whisper and other models to infer language from audio content. This route appears in candidate generation when the underlying model supports auto-detection.
What happens when a selected language has no compatible models?
The allLanguages() and popularLanguages() methods pre-filter to languages with at least one viable route. If model availability changes (e.g., via in-app purchase or update), the catalog automatically adjusts presented options.
How are language names localized for different UI languages?
The displayName property in LanguageDefinition returns localized strings through the standard iOS localization infrastructure. Aliases support cross-language search—entering "espanol" matches Spanish regardless of device language.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →