Building Lingo Canvas: From Local Project to Global Thinking
๐Live Demo
๐ปGitHub Repository
Most of us build applications in English. Not because everyone speaks English. But because itโs convenient. Framework documentation is in English. Error messages are in English. Most open-source ecosystems default to English. So naturally, our apps do too.
But hereโs the uncomfortable truth:
- ๐ The internet is global.
- ๐งฉ Most applications are not.
That realization slowly shaped the foundation of my project : Lingo Canvas.
๐ง What Is Lingo Canvas?
Lingo Canvas is an AI-powered canvas application built with:
It allows users to:
- ๐จ Generate dynamic content visually on a canvas
- ๐ Switch between multiple languages instantly
- ๐ Experience both UI and generated content adapt to the selected language
At first glance, it might look like a simple AI canvas tool. But underneath, it became something deeper. It became an experiment in designing software that does not assume a single language.
๐ฏ The Motivation Behind the Project
Originally, I wanted to build something interactive and AI-driven. Something visual.
Something dynamic.
But while designing it, I asked myself:
What if someone who doesnโt speak English opens this app?
Will they feel included?
Or will they feel like theyโre visiting someone elseโs space?
That question changed everything.
Because it made me realize:
Localization is not just about translating words.
Itโs about shaping user experience.
๐ The Shift in Thinking
Instead of building everything first and worrying about translations later, I decided to treat multilingual support as part of the architecture from the beginning.
That meant:
- ๐งฑ Structuring text intentionally
- ๐ Planning for runtime language switching
- โ๏ธ Considering right-to-left layout behavior
- ๐งฉ Separating static UI from dynamic AI-generated content
Lingo Canvas stopped being just a canvas experiment.
It became a study in building global-ready applications.
๐ What This Series Will Cover
In the upcoming parts, I will break down:
- โ Why traditional localization approaches fail in dynamic apps
- ๐๏ธ The architectural decisions behind Lingo Canvas
- ๐ How I separated deterministic UI localization from AI content regeneration
- โ๏ธ The role of lingo.dev in creating a structured localization workflow
- ๐ Lessons learned while building a multilingual AI product
This is not just a project showcase.
It is a journey from:
"Letโs add translations later"
to
"Localization is infrastructure."
โ ๏ธ Why Traditional React Localization Breaks at Scale
When I first thought about making Lingo Canvas multilingual, I assumed the solution was simple:
- ๐ฆ Install an i18n library
- ๐ Create translation JSON files
- ๐ค Wrap text in a
t()function - โ Done
That approach works. Until it doesnโt.
๐ชค The โIt Works for Two Languagesโ Trap
For small projects, traditional localization looks fine.
You create:
// en.json
{
"welcome": "Welcome",
"generate": "Generate"
}
// de.json
{
"welcome": "Willkommen",
"generate": "Generieren"
}
Then you switch language state and everything updates.
Clean. Simple. Efficient.
But hereโs what starts happening as your app grows:
- ๐ Translation keys multiply
- ๐ท๏ธ Naming becomes inconsistent
- โ Some keys are missing in certain languages
- ๐จ Refactoring UI breaks translations silently
- ๐ฌ Adding a new language feels risky
And suddenly, localization becomes technical debt.
๐ The Hidden Problem: Localization Is Tightly Coupled to Components
In many React apps, text is defined directly inside components.
Example:
<button>{t("generate")}</button>
At first glance, this is fine.
But over time:
- ๐งฑ Components grow
- ๐จ UI changes
- ๐ Keys get reused incorrectly
- ๐ Context-specific translations get mixed
The result?
You stop trusting your translation system.
๐ค Now Add Dynamic Content
Static UI is one problem. Dynamic content is another level. Lingo Canvas generates content inside a canvas dynamically.
So I had to think:
- Should I translate generated content word-by-word?
- Or regenerate it contextually in the selected language?
Traditional i18n systems are designed for deterministic UI. They are not designed for AI-generated experiences. Thatโs where things start breaking conceptually.
๐๏ธ Designing a Hybrid Localization Architecture
At this point, I knew one thing clearly:
- โ Traditional localization alone wasnโt enough.
- ๐๏ธ Lingo Canvas wasnโt just a static dashboard.
- ๐ค It was an interactive AI-powered canvas.
That meant I was dealing with two very different types of text:
- ๐ Predictable interface text (buttons, labels, menus)
- โจ Unpredictable, AI-generated content inside the canvas
Treating both the same would be a mistake. So instead of forcing everything into one system, I designed a hybrid model.
๐งฉ Separate Static UI from Dynamic Content
This was the turning point. I divided localization into two layers:
Layer 1 : Deterministic UI
This includes:
- ๐งญ Navigation labels
- ๐ Buttons
- ๐ ๏ธ Toolbars
- โ๏ธ Settings
- ๐ท๏ธ Static headings
This text is predictable. It doesnโt change contextually. It just needs to exist in multiple languages reliably. This layer is where structured localization belongs.
Layer 2 : Dynamic AI Content
This includes:
- ๐ Generated canvas text
- ๐ง AI-created explanations
- ๐ Context-aware content blocks
This text is not predictable.
It changes based on:
- ๐ค User input
- ๐งพ Prompts
- ๐ Context
- ๐ Interaction flow
Trying to pre-translate this would be impossible. Instead of translating itโฆ
I regenerate it in the selected language. That distinction changed everything.
๐ค Translation vs Regeneration
This became the core philosophy of the project.
Translation
- ๐ Word substitution
- ๐ Deterministic
- ๐ Dictionary-based
- โ Works well for static UI
Regeneration
- ๐ง Context-aware
- ๐ฏ Meaning-driven
- ๐ค AI-based
- โจ Ideal for dynamic content
If I tried to translate AI-generated English text into German, I would lose nuance. Instead, I generate directly in German when the language is switched. That preserves intent, not just vocabulary.
Why This Hybrid Model Worksโ
By separating responsibilities:
- UI remains stable and structured
- AI content remains contextual and natural
- Adding a new language doesnโt break the app
- Language switching feels intentional
Instead of forcing localization into one bucket, I allowed the system to reflect reality.
Some text is static. Some text is alive. And they deserve different strategies.
๐ง The Architectural Mindset Shift
Before this project, I thought:
โLocalization is about translation files.โ
After building this hybrid system, I realized:
Localization is about system boundaries.
Itโs about deciding:
- ๐ What should be deterministic?
- ๐ What should be contextual?
- ๐ What belongs in dictionaries?
- ๐ค What belongs in generation logic?
That architectural clarity made everything simpler.
Not easier , but cleaner.
๐งฑ Structuring the UI Layer with a Proper Localization Workflow
Once I separated static UI from dynamic content, the next question was obvious:
How do I make the UI localization reliable and scalable?
Because hereโs the truth:
Most localization problems are not caused by translation.
They are caused by poor structure.
โ ๏ธ The Mistake Most Projects Make
In many React apps, localization starts like this:
- ๐ Create a
localesfolder - โ Add
en.json - โ Add
de.json - ๐ค Use a
t()function - ๐ Ship it
That works for small projects.
But when the app grows:
- ๐ท๏ธ Keys become inconsistent
- ๐๏ธ Files become cluttered
- ๐จ Refactoring breaks translations silently
- ๐ฌ Adding new languages feels risky
Localization slowly turns into hidden technical debt. I didnโt want that. So instead of thinking about translation filesโฆ
I thought about workflow.
๐๏ธ Designing Localization as a System
For the deterministic UI layer, I needed:
- ๐งฉ Structured translation keys
- ๐ท๏ธ Clear naming conventions
- ๐ Predictable fallback behavior
- ๐ A clean way to manage multiple locales
- ๐ก๏ธ Confidence when adding new languages
This is where a structured localization tool becomes important. Not because it translates automatically. But because it enforces discipline.
๐ Making Language Switching Feel Instant (Without Breaking the Canvas)
Adding multiple languages is one thing. Making language switching feel smooth is another. In Lingo Canvas, users can change language at runtime.
- โก No refresh.
- ๐ซ No reload.
- ๐ง No disruption.
But making that work required careful thinking.
๐ The Core Challenge
When a user switches language, three things must happen:
- โก The UI must update immediately.
- โ๏ธ The layout must adapt (especially for RTL languages).
- ๐๏ธ The canvas content must remain stable.
If even one of these fails, the experience feels broken. So I had to design the system carefully.
๐งญ Step 1: Centralized Language State
Language selection is managed at a global level. Instead of passing language props everywhere, I used a centralized state approach.
When the language changes:
- ๐ The localization provider updates
- ๐ UI components re-render with new translations
- โ๏ธ Layout direction adjusts if needed
This ensures consistency across the entire application. No component is โout of sync.โ
โ๏ธ Step 2: Handling RTL Layouts
Supporting languages like Arabic is not just about translating text.
It affects:
- ๐ Text alignment
- ๐ Flex direction
- ๐ Spacing
- ๐งญ UI flow
So when the language switches to an RTL language:
- The
dirattribute updates tortl - Layout adjusts automatically
- Components remain readable and aligned
This small detail dramatically improves user comfort.
๐ก๏ธ Step 3: Protecting the Canvas State
Hereโs where things get tricky.
The canvas contains:
- ๐ท Shapes
- ๐ Positions
- ๐ฑ๏ธ User interactions
- ๐ค AI-generated content
When language changes, I donโt want:
- Shapes to reset
- User work to disappear
- The canvas to reinitialize
So I separated:
- UI rendering logic
- Canvas state logic
Language switching triggers UI re-rendering, but the canvas state remains intact. That separation preserves user work. Which is critical.
๐ Step 4: Regenerating Dynamic Content (When Needed)
For AI-generated content:
If the user switches language, I donโt simply translate existing English text.
Instead, I regenerate it in the selected language.
This ensures:
- ๐ฏ Context stays accurate
- ๐ฃ๏ธ Tone feels natural
- ๐ก Meaning remains intact
The UI updates instantly. The content regenerates intentionally. That distinction makes the experience feel thoughtful rather than mechanical.
๐ฏ The UX Goal
Language switching should feel:
- โก Immediate
- ๐ฟ Natural
- ๐ Predictable
- ๐ก๏ธ Non-destructive
If users hesitate before switching languages, something is wrong.
The goal is confidence.
And that confidence comes from architectural separation, not hacks.
๐ Resources
If you're building a multilingual app and want a structured way to manage UI localization, you can explore:
- ๐ Lingo.dev โ https://lingo.dev
It provides tooling and workflow support for managing translations in modern web applications.
๐ง What Building a Multilingual AI App Taught Me About Architecture
When I started Lingo Canvas, I thought I was building a canvas tool. By the end of it, I realized I was redesigning how I think about software architecture. Localization was never supposed to be the โmain challenge.โ But it quietly became the most educational part of the project.
๐๏ธ Lesson 1: Localization Is Not a Feature
Itโs easy to treat multilingual support as something you โadd later.โ
But once your app grows:
- ๐ Text lives everywhere
- ๐งฉ Components depend on language
- โ๏ธ Layout reacts to direction
- ๐ค Dynamic content behaves differently
Localization touches rendering, state, UX, and even performance. That makes it infrastructure. And infrastructure decisions must be intentional.
๐ Lesson 2: Not All Text Is Equal
Some text is stable and predictable. Some text is contextual and alive. Trying to force both into one system leads to compromise.
Separating:
- ๐งฑ Deterministic UI localization
- ๐ Dynamic AI content regeneration
made the system cleaner and more scalable.
Architecture improves when responsibilities are clearly divided.
๐ Lesson 3: Language Switching Is a UX Signal
When a user switches language, they are telling you something:
โI want this experience in my space.โ
If switching language:
- ๐ข Feels slow
- ๐ฅ Breaks layout
- ๐ Resets state
- โ ๏ธ Feels incomplete
The product loses trust instantly. Language switching should feel seamless. That only happens when localization is designed, not patched.
๐ Lesson 4: Global Thinking Changes Design Decisions
Once I started thinking globally, I began asking different questions:
- ๐ท๏ธ Is this key structured clearly?
- โ What happens when we add five more languages?
- โ๏ธ Does this layout break in RTL?
- ๐ค Should this text be translated or regenerated?
Those questions improved more than just localization. They improved the entire architecture.
๐ Final Thoughts
Lingo Canvas started as an experiment in AI + canvas interaction. It ended up being a lesson in multilingual product design. If I had built everything first and โadded translations later,โ the app would work. But it wouldnโt feel intentional. Designing for multiple languages from the beginning forced clarity. And clarity always improves software.
If you're building something today, ask yourself:
Are you building for your language?
Or for the internet? ๐
Because the difference between those two mindsets changes everything.
Top comments (0)