How We Made VORA Bilingual Without a Heavy Localization Stack
VORA supports both Korean and English across core product surfaces.We built this without a full localization framework, using a pragmatic architecture that worked for our stage. This post covers the approach, tradeoffs, and what we would change at la...
Series: VORA B.LOG
- 1. Why I shipped VORA before writing a single line of backend code
- 2. From Python Server to Pure Browser: The Architecture Pivot That Changed Everything
- 3. The Whisper WASM Experiment: Why Browser AI Is Harder Than It Looks
- 4. Why We Killed Speaker Identification (And What We Learned from Two Weeks of Failure)
- 5. Building an N-Best Reranking Layer for Better Korean STT (Without Extra API Calls)
- 6. Building the Priority Queue: How We Stopped Gemini API Chaos — and Why the First Two Designs Both Failed
- 7. Groq Dual-AI Integration: Why We Added a Second AI and What It Actually Fixed
- 8. The Meeting Summary Timer Bug: Why setInterval Isn't Enough for Reliable Scheduling
- 9. Building a Real Meeting Export: From Raw Transcript to a Usable Report
- 10. The Dark Theme Redesign: Building a UI That Looks Like a Professional Tool (After It Looked Like a Hobbyist Project)
- 11. The Branding Journey: From a Functional Name to VORA
- 12. How We Made VORA Bilingual Without a Heavy Localization Stack ← you are here
- 13. Deploying to Cloudflare Pages: Static Hosting, CORS Headers, and the Sitemap/Robots Incident
- 14. How I Fixed AI Over-correction
VORA supports both Korean and English across core product surfaces.
We built this without a full localization framework, using a pragmatic architecture that worked for our stage.
This post covers the approach, tradeoffs, and what we would change at larger scale.
Initial Approach: Paired Language Pages
For static pages, we used paired files:
page.html(English)page_ko.html(Korean)
Why this worked early:
- no build pipeline overhead
- straightforward deployment
- clear language-specific URLs for SEO
Why this became costly later:
- every structural update had to be duplicated
- link mismatches appeared over time
- consistency audits became manual and frequent
The Synchronization Problem
As page count grew, drift became inevitable:
- English page linking to Korean destination by mistake
- metadata language mismatch
- uneven updates between paired pages
None of these failures crash deployment, which makes them easy to miss until users hit them.
Runtime Strings for App UI
For dynamic app UI, we did not duplicate JavaScript logic.
We used a small runtime dictionary and selected language from the document context.
That gave us one behavior path with language-specific strings, reducing maintenance in the most complex part of the app.
SEO and Language Signaling
International discoverability required explicit language mapping between page pairs.
The main challenge was operational discipline, not syntax. Even minor copy-paste mistakes in language mapping can reduce search quality without obvious runtime errors.
Legal and Policy Pages
Policy surfaces needed language separation with clear ownership, not mixed bilingual documents.
This reduced ambiguity and made future updates easier to track per language audience.
What We Would Do Next
At the current scale, the lightweight approach still works.
At larger scale, we would move to template-driven generation with translation sources to remove manual page drift.
Likely migration path:
- keep content in language files
- generate language variants from one template
- enforce consistency checks in CI
Takeaway
If you support multiple languages, the core risk is not translation quality alone.
It is update consistency over time.
Pick an architecture that matches your current size, but design with a clear migration path before manual synchronization starts slowing every release.