Abstract:
When adding new language support to a production system, the choice between migration and additive strategies can make the difference between a smooth rollout and a potential disaster. Here’s how we avoided a risky database migration by choosing to extend rather than replace our existing Traditional Chinese implementation.
Estimated reading time: 6 minutes
Locale Migration Strategy: When Adding Beats Replacing
I recently faced a classic engineering dilemma: how to add Simplified Chinese support to a system that already had Traditional Chinese implemented as zh
. The obvious approach was to migrate everything to proper locale codes (zh-TW
for Traditional, zh-CN
for Simplified), but that would have required a database migration across 8 tables with production data.
Instead, we chose an additive strategy that kept the existing zh
implementation intact while adding zh-CN
as a new locale. This decision saved us from potential data loss, service disruption, and the complexity of rolling back a migration gone wrong.
The Initial Approach: Full Migration Strategy
We started down the migration path with what seemed like the “correct” approach:
- Update locale configuration from
["en", "zh", "th"]
to["en", "zh-TW", "th"]
- Rename all prompt files from
*_zh.ts
to*_zh-TW.ts
- Update variable names throughout the codebase from
zh
tozhTW
- Modify pathnames to use
zh-TW
keys - Update TypeScript interfaces and switch statements
The migration script would have touched 8 database tables:
ai_provider_requests
(AI interaction logs)classroom_sessions
(user sessions)divination_sessions
(core app functionality)group_divination_chat_messages
(collaboration data)group_divination_readings
(shared results)group_divination_requests
(group activities)group_divination_topics
(content management)scenario_responses
(user interactions)
This was the moment we realized the scope of what we were attempting.
When Reality Hit: The Testing Error
During testing, a user encountered this error:
1
2
[GET TOPIC BY SLUG] Action called for slug: simulation-hypothesis-reality, locale: zh-TW
No active topic found for slug: simulation-hypothesis-reality, locale: zh-TW
The root cause was obvious: the database still contained zh
records, but our code was now looking for zh-TW
records. This mismatch would have required either:
- Immediate database migration (risky in production)
- Rollback of all changes (wasting development time)
- Hybrid approach (complex and error-prone)
The Technical Complexity We Avoided
AI Provider Logging Impact
Our aiProviderService.ts
logs every AI request with locale information. The logAIProviderRequest()
function stores locale in the database, meaning any migration would affect:
- Historical analytics data - potentially breaking trend analysis
- User session continuity - existing users might lose their history
- AI interaction logs - critical for debugging and optimization
Database Migration Scope
Eight tables across multiple domains meant:
- Complex rollback procedures if anything went wrong
- Extended downtime during migration
- Data validation requirements across all affected systems
- Testing complexity that scales exponentially with table count
Production Safety Concerns
- Data integrity risk - losing historical analytics data
- Rollback complexity - difficult to revert if issues arise
- Service disruption - potential downtime during migration
- Testing requirements - extensive validation needed across all features
The Decision: Additive Strategy
We chose to extend rather than replace:
- Keep:
zh
as Traditional Chinese (unchanged, existing users continue working) - Add:
zh-CN
as Simplified Chinese (new functionality) - Benefit: Zero downtime, no data migration, backward compatibility
The final configuration became:
1
export const locales = ["en", "zh", "zh-CN", "th"] as const;
Where:
zh
= Traditional Chinese (existing users, Hong Kong market)zh-CN
= Simplified Chinese (mainland China market)en
= Englishth
= Thai
Why This Approach Was Superior
Production Safety
- Zero downtime - no database migration required
- No data loss risk - existing user sessions remain valid
- Immediate rollback - if issues arise, we can simply disable
zh-CN
User Experience
- Backward compatibility - existing users continue using
zh
- Gradual adoption - new users can choose
zh-CN
without affecting others - Market segmentation - different locales serve different user segments
Development Velocity
- Faster implementation - no migration planning or testing required
- Lower risk - can deploy incrementally and test thoroughly
- Easier maintenance - two separate implementations are clearer than migration logic
Lessons Learned
Technical Architecture
- Locale changes require careful database migration planning - e.g., retrieving locale specific data, or when AI logging is involved
- AI logging makes locale consistency critical - every request gets stored with locale information
- TypeScript strict typing helps catch locale mismatches early - but doesn’t prevent runtime database issues
Product Strategy
- Additive > Migration - when possible, extend rather than replace existing functionality
- User impact assessment - consider existing user base before making breaking changes
- Market segmentation - different locales often serve different user segments with different needs
Implementation Principles
- Risk assessment - database scope changes require careful evaluation of production impact
- Rollback planning - always have a reversion strategy that doesn’t require complex migrations
- Testing strategy - comprehensive validation across all affected systems is essential
The Implementation Status
- ✅ Decision made: Additive strategy chosen
- ✅ All migration changes reverted via git (clean slate)
- 🔄 Currently implementing:
zh-CN
addition - ⏳ Pending: Complete
zh-CN
implementation and testing
Key Takeaways
- Migration strategies look correct but carry hidden risks - especially when involving production databases
- AI logging systems make locale changes more complex - every request gets stored with locale information
- Additive approaches often beat replacement strategies - extend functionality rather than breaking existing
- Production safety should trump “correctness” - a working system is better than a theoretically perfect but risky one
- Database migrations across multiple tables require extensive planning - the complexity scales exponentially
- User experience continuity matters - existing users shouldn’t lose functionality during updates
- Market segmentation can justify multiple implementations - different locales serve different user needs
The decision to use an additive strategy saved us from a potentially disastrous database migration while maintaining all existing functionality. Sometimes the “less correct” approach is the right one for production systems where stability and user experience matter more than theoretical purity.