Most products that ship into the GCC are bilingual by default. The user's first language is Arabic, the technical vocabulary is English, the UI strings live in both, and the speech that comes out of the product has to handle both gracefully without sounding like two different products glued together. This post is a guide to designing the voice layer of a bilingual Arabic-English product so the seams don't show.
The audience is product designers and engineers building voice-first or voice-augmented products for MENA users. The post assumes you've already picked a TTS vendor; the question this post answers is how to architect the voice layer above the vendor.
The four bilingual patterns
Before the architecture, the use cases. Bilingual voice products fall into four patterns:
- Localised parallel: the product has separate Arabic and English voices, switchable via a settings toggle. The user picks one and stays. The two voices can be completely different (different speaker, different model, different vendor) because they never interact.
- Code-switching native: the user mixes Arabic and English in the same utterance ("احجز لي meeting Tuesday"), and the product responds in the same mixed register. This is how most GCC users actually speak; it's the highest-fidelity pattern but the hardest to ship.
- Language-of-context: the product detects the language of the input and responds in the same language. The user can switch languages mid-conversation by switching input language; the product follows.
- Brand-locked: the product has a single voice (typically a cloned brand voice) that speaks both Arabic and English. The challenge is making the same voice sound natural in both languages without obvious artefacts at the language boundaries.
A product team typically picks one of the four patterns up front; retrofitting later is expensive because the architectural choices propagate through the LLM prompt structure, the voice catalogue, and the user-facing language controls.
Pattern 1: localised parallel
This is the easiest pattern to ship and the one most products start with. The architecture:
- Two separate voice configurations (one Arabic-default, one English-default).
- A user-facing language toggle in settings.
- LLM prompts duplicated per language with appropriate localisation.
- Two TTS voice IDs, picked per-language.
What works:
- Simple to deploy.
- Clean QA: each language can be tested independently.
- Voice catalogue choice is unconstrained; pick the best Arabic voice and the best English voice without worrying about cross-language consistency.
What doesn't work:
- Doesn't handle the user who asks an English question in an Arabic session, or vice versa. The product either translates (which feels broken) or refuses (which feels worse).
- Doesn't handle the bilingual reality of GCC speech.
This pattern is fine for products with strong language separation (a Saudi government portal vs. its English mirror) but loses to the others for products targeting bilingual GCC consumers.
Pattern 2: code-switching native
This is the hardest pattern but the one closest to how GCC users actually speak. The architecture:
- A single TTS voice that supports both Arabic and English natively, ideally trained on a corpus that includes code-switched audio.
- An LLM prompted to respond in code-switched register matching the user's input.
- A language-detection layer that doesn't try to "fix" code-switching by collapsing to one language.
- SSML or per-segment language tags on the output text so the TTS knows which segments are Arabic and which are English.
The hardest engineering piece: per-segment language tags. The LLM output ("احجز لي meeting Tuesday") needs to be split into segments tagged by language ("احجز لي" Arabic, "meeting Tuesday" English), and each segment passed to the TTS with the appropriate language tag. Hakim's API accepts a per-segment language tag in the input text:
{
"segments": [
{ "text": "احجز لي", "language": "ar" },
{ "text": "meeting Tuesday", "language": "en" }
],
"voice_id": "layla-bilingual"
}
The TTS handles the prosody at the boundary (a brief micro-pause to mark the language transition, no awkward phoneme blend) so the output reads as natural code-switching rather than two stitched-together segments.
What works:
- Highest fidelity to actual GCC speech.
- Doesn't require the user to learn a "switch language" affordance; the product matches their natural register.
What doesn't work:
- Requires a TTS that genuinely handles code-switching. Most don't; they accept input in any language but produce monolingual prosody.
- Requires LLM prompting that doesn't collapse code-switched input to a single language, which is the default behaviour of most LLMs trained predominantly on monolingual corpora.
- Requires the segmentation layer to handle ambiguous tokens ("ميتنق" written in Arabic script for "meeting") gracefully.
Pattern 3: language-of-context
The middle ground. The architecture:
- Language detection on the user's input (often a 50-100 ms language-classifier call before the LLM).
- The LLM responds in the detected language.
- The TTS uses the voice configured for that language.
- The voice can change mid-session if the user switches languages.
What works:
- Handles language switching across utterances (the user types in English in turn 3 after speaking Arabic in turns 1-2; the product follows).
- Simpler than full code-switching support; the language boundary is between turns, not within a single utterance.
- Easier QA than pattern 2 because each turn is monolingual.
What doesn't work:
- Doesn't handle within-utterance code-switching ("احجز لي meeting Tuesday" gets classified as either Arabic or English and the response language is wrong for the part that wasn't classified).
- The language change between turns can feel jarring if the voice timbre shifts noticeably between the Arabic and English voices.
This pattern is the right pick for products where users tend to send monolingual messages (text-based chatbots, email-style voice notes) but occasionally switch.
Pattern 4: brand-locked
The pattern for products where the voice is part of the brand identity. The architecture:
- A single cloned or catalogue voice that handles both Arabic and English.
- The LLM responds in the user's language; the voice handles the language switch invisibly.
- Voice cloning trained or selected to sound natural in both languages.
This pattern is similar to language-of-context, but constrained to a single voice. The challenge is voice quality consistency: many cloned voices that sound natural in their native language sound noticeably less natural in their non-native language.
Hakim's voice cloning produces a clone that's trained on multilingual phoneme inventories, so the same cloned voice sounds natural in all 15 Arabic dialects plus 30+ other languages. The Arabic and English versions of the same cloned voice are recognisable as the same speaker, with consistent timbre and personality.
The four engineering pieces
Across the patterns, four engineering pieces have to be solid for a bilingual voice layer to work:
1. Language detection that doesn't over-correct
A language-detection layer that aggressively normalises code-switched input to a single language is the silent killer of bilingual UX. The detection should:
- Detect the dominant language of an input.
- Detect the presence of code-switching (multiple languages in a single input).
- NOT auto-correct one language to another (a cultural nuance: "WhatsApp" in an Arabic message should stay as "WhatsApp", not be transliterated to واتساب).
The default ICU and CLD3 language detectors are tuned for monolingual classification and over-correct on code-switched input. For bilingual MENA products, a layer that explicitly recognises code-switching is needed.
2. Prosody at the language boundary
When the output text crosses a language boundary, the TTS has to handle the prosody transition. The artefacts that show up on poor implementations:
- A noticeable pause longer than natural at the boundary.
- A pitch jump as the model switches its prosody profile.
- Phoneme blend artefacts where the Arabic phoneme inventory bleeds into the English production.
Hakim handles this with a 50-80 ms micro-pause at the boundary plus a prosody crossfade across the transition, so the boundary reads as natural code-switching rather than as two stitched segments. The prosody crossfade requires the model to know the language of each segment ahead of time, which is why per-segment language tags matter.
3. Voice catalogue ergonomics
For language-of-context and brand-locked patterns, the voice catalogue has to be navigable along the bilingual axis. The dimensions:
- Bilingual voices: voices that sound natural in both Arabic and English. A subset of the catalogue.
- Dialect-bilingual voices: voices that handle a specific Arabic dialect plus English (Khaleeji + English, Egyptian + English, etc.). The most common pattern for GCC product builders.
- Voice cloning bilingual: cloned voices that handle both languages from a single source sample. Harder to do well; the source sample has to include enough phonetic coverage.
Hakim's catalogue tags voices with a bilingual flag plus a secondary_languages list, so a developer can filter to "Khaleeji voices that also speak English" with a single API call.
4. LLM prompt patterns
The LLM is what generates the text the TTS speaks. The prompt patterns that work for bilingual products:
You are a bilingual Arabic-English assistant for {brand}. Match the
user's language. If the user code-switches between Arabic and English
within a single message, respond in the same code-switched register;
do NOT collapse to a single language.
When using English technical terms in Arabic responses, write them
in English script (e.g. "احجز لي meeting Tuesday") rather than
transliterating ("احجز لي ميتنق Tuesday"). The user's voice
assistant will pronounce them correctly.
The second instruction is critical. LLMs trained on bilingual MENA corpora often default to transliterating English terms into Arabic script (because that's how they appear in the training data); the TTS then has to either pronounce the transliteration phonetically (sounds wrong) or guess at the original English (sometimes right, sometimes wrong). Forcing the LLM to keep English in Latin script gives the TTS unambiguous input.
How to pick a pattern
Three questions that determine which pattern fits:
- How bilingual are your users in practice? If they consistently send monolingual messages, language-of-context (pattern 3) is enough. If they code-switch heavily, code-switching native (pattern 2) is the right pick.
- Is the voice a brand asset? If yes, brand-locked (pattern 4) constrains the catalogue choice but provides voice consistency. If no, the bilingual voice doesn't need to be a single voice.
- What's your engineering budget? Localised parallel (pattern 1) is the cheapest to ship; code-switching native (pattern 2) is the most expensive. The right answer for a startup is often pattern 3 with a path to pattern 2 once the product has product-market fit.
The Hakim-specific bilingual support
Hakim's bilingual voice support across the four patterns:
- Pattern 1 (localised parallel): every voice in the catalogue declares its primary language and dialect. Filter to Arabic, pick a voice; filter to English, pick another. Works out of the box.
- Pattern 2 (code-switching native): per-segment language tags on the input text, prosody crossfade at boundaries, bilingual voices in the catalogue. The most common Hakim deployment for GCC consumer products.
- Pattern 3 (language-of-context): voice catalogue includes voices tagged with multiple supported languages. Pick one voice ID, pass either Arabic or English text, the renderer adapts. Good for chatbots and conversational interfaces.
- Pattern 4 (brand-locked): voice cloning produces a multilingual clone from a single source sample. The cloned voice handles 15 Arabic dialects + 30+ other languages. Used by GCC banks, telcos, and airlines for branded voice agents.
The streaming endpoint and the batch endpoint both support per-segment language tags. Documentation at /docs/multilingual; a working demo at /playground.
A short architecture checklist
For teams building bilingual Arabic-English voice products:
- Pick a pattern (1-4 above) before picking a TTS vendor. Architectural choices flow from the pattern.
- Test the TTS on code-switched input ("احجز لي meeting Tuesday"). If the output sounds like two stitched segments, the vendor isn't ready for code-switching native.
- Audit the LLM prompt to ensure it doesn't collapse code-switched input to a single language.
- Keep English technical terms in Latin script in the LLM output; let the TTS handle the bilingual rendering.
- For brand-locked patterns, audit the cloned voice on both languages before committing. Many cloned voices that sound great in one language sound noticeably worse in the other.
- Instrument language-detection accuracy in production; over-corrected detection silently degrades UX.
If you want to see Hakim's per-segment language tag API against a sample bilingual script, /playground accepts mixed Arabic-English input directly. For specific deployment patterns or an architecture review, email hello@tryhakim.ai with the product context.