Technical Documentation
This documentation provides an architectural overview of Chamelingo's internal design for developers interested in understanding how the localization system works behind the scenes.
Target Audience
This documentation is intended for advanced users and developers who want to understand Chamelingo's architecture. For standard usage, refer to the Getting Started and User Guide.
Architecture Overview
Chamelingo follows a modular, event-driven architecture built on several core subsystems:
graph TB
UI["UI Components Layer<br/>(ChamelingoTextBase,<br/>ChamelingoTMP,<br/>UI Decorators)"]
API["Public API Layer<br/>Chamelingo<br/>(Static Facade)"]
Manager["Manager Layer<br/>ChamelingoManager<br/>(Singleton)"]
Translation["Translation<br/>Provider"]
DataAccess["Data Access<br/>Strategy"]
Observer["Observer<br/>Events"]
Storage["Storage Layer<br/>(Resources/Files)"]
UI --> API
API --> Manager
Manager --> Translation
Manager --> Observer
Translation --> DataAccess
DataAccess --> Storage
Core Components
1. Public API Layer
The Chamelingo static class serves as the main entry point and facade for all localization functionality.
Key Responsibilities: - Provides simple, unified API for users - Delegates to ChamelingoManager - Prevents direct access to manager internals
Design Pattern: Facade Pattern
Available Methods:
- CurrentLanguage - Get the active language
- LoadLanguage(CultureInfo) - Change language
- Translate(string) - Get translation for a key
- Translate(string, TextCasing) - Get translation with formatting
- Subscribe(Action) - Listen for language changes
- Unsubscribe(Action) - Stop listening
- GetAvailableLanguages() - Get all languages
2. Manager Layer (ChamelingoManager)
ChamelingoManager is the core singleton that handles all localization logic internally.
Key Features:
- Singleton Pattern: Thread-safe lazy initialization
- Automatic Initialization: Loads on first access
- Language Priority: User preference → Saved preference → System language → Default → First available
- Translation Cache: In-memory dictionary for fast lookups
- Event System: Observer pattern for language change notifications
- Persistence: Saves user's language choice to PlayerPrefs
Initialization Flow:
flowchart TD
Start(["First Access to<br/>Chamelingo API"])
Singleton["Create<br/>ChamelingoManager<br/>singleton"]
DataAccess["Create data access<br/>strategy from settings"]
Provider["Create translation<br/>provider"]
Language["Determine initial<br/>language priority<br/>system"]
Load["Load translations<br/>into memory"]
Ready(["Ready for use"])
Start --> Singleton
Singleton --> DataAccess
DataAccess --> Provider
Provider --> Language
Language --> Load
Load --> Ready
Internal Class
ChamelingoManager is marked with [EditorBrowsable(EditorBrowsableState.Never)] to hide it from IntelliSense. Always use the Chamelingo static facade instead.
3. Translation Provider
TranslationProvider bridges the manager and data access layer.
Responsibilities: - Load translation sets from data access - Provide available languages list - Simple interface for the manager
No caching - translations are cached at the manager level.
4. Data Access Layer
Supports multiple storage formats with a unified interface (IEditorDataAccess for editor, IRuntimeDataAccess for builds).
Supported Formats:
| Format | File Structure | Best For |
|---|---|---|
| JSON | One .json per language |
Small-medium projects, readable files |
| CSV (Per Language) | One .csv per language |
Spreadsheet workflow, easy editing |
| CSV (Single File) | All languages in one .csv |
Compact storage, fewer files |
Design Pattern: Strategy Pattern
Each format implements the data access interface with:
- LoadLanguageTranslationSet_Runtime() - Load from Resources
- LoadLanguageTranslationSet_Editor() - Load from Assets folder
- SaveLanguageTranslationSet_Editor() - Save changes (editor only)
- GetAvailableLanguages_Runtime/Editor() - List languages
- DeleteLanguageTranslationSet_Editor() - Remove language
- CreateBackup_Editor() - Backup before changes
File Locations:
- Editor: Assets/Chamelingo/Translations/
- Runtime: Resources/Chamelingo/
5. UI Components
Runtime components that automatically localize text on language changes.
Component Hierarchy:
ChamelingoTextBase (Abstract)
├─ Translation Key support
├─ Text Casing support
├─ Composite Text support
├─ Event subscriptions
│
├──> ChamelingoTMP (TextMeshPro)
└──> ChamelingoUnityText (Legacy UI.Text)
Features: - Simple Mode: Direct translation key → translated text - Composite Mode: Template with dynamic parameters - Auto-Refresh: Optional polling for dynamic content - Bidirectional Sync: Text changes sync with component (editor only)
Lifecycle: 1. Awake: Initialize processors 2. Start: Subscribe to language changes, load initial text 3. OnEnable: Re-subscribe if disabled 4. OnDisable: Unsubscribe 5. OnDestroy: Final cleanup
6. Event System
Observer Pattern for decoupled language change notifications.
Features: - Immediate callback on subscription (delivers current language) - Thread-safe subscription management - HashSet prevents duplicate subscriptions - Automatic callback on language change
Usage:
// Subscribe
Chamelingo.Subscribe(OnLanguageChanged);
// Callback receives CultureInfo immediately and on changes
void OnLanguageChanged(CultureInfo newLanguage)
{
// Update UI, reload data, etc.
}
// Always unsubscribe
Chamelingo.Unsubscribe(OnLanguageChanged);
Editor Integration
Unity Editor Hub
The Chamelingo Hub is an editor window providing centralized translation management.
Location: Window > Chamelingo
Features: - Create, edit, and delete translation keys - View translation coverage, errors and warnings - Access auto-translation services
Project Settings Provider
Integrates with Unity's Project Settings window.
Location: Edit > Project Settings > Chamelingo
Configuration: - Data Access Type (JSON, CSV formats) - Default language selection - Auto-translation service setup (Google Translate, DeepL, etc.)
Custom Editors
ChamelingoTextBaseEditor enhances Inspector for text components: - Mode toggle (Simple vs Composite) - Translation key dropdown with search - Key status indicator (exists/missing) - Create key button - Composite template editor with parameter management - Text casing options - Bidirectional text sync (component ↔ text field)
TextComponentDecorator adds localization hints to standard Text/TMP components: - Banner showing localization status - Quick "Localize This" button to add Chamelingo component
Auto-Translation Services
Chamelingo supports multiple translation service providers.
Design Pattern: Strategy Pattern
Supported Services: - MyMemory (Free, no API key) - LibreTranslate (Self-hosted or public instance) - Google Translate (API key required) - DeepL Free (API key required) - DeepL Pro (API key required) - Azure Translator (API key required)
Interface: ITranslationService
- Translate(text, sourceCulture, targetCulture) - Translate text
- TestConnection() - Verify service availability
- Setup(apiKey) - Configure service
- DisplayName - Service name for UI
Usage: Configure in Project Settings, then use "Auto-Translate" in the Hub.
Data Flow Diagrams
Language Change Flow
flowchart TD
Start["Chamelingo<br/>.LoadLanguage<br/>culture"]
Validate{"Validate<br/>language<br/>exists"}
Update["Update<br/>CurrentLanguage"]
Save["Save to<br/>PlayerPrefs"]
Load["Load translations<br/>into memory cache"]
Notify["Notify all<br/>subscribers"]
UI["UI Components<br/>refresh"]
Callbacks["Custom callbacks<br/>execute"]
Complete(["Complete"])
Abort(["Abort"])
Start --> Validate
Validate -->|Valid| Update
Validate -->|Invalid| Abort
Update --> Save
Save --> Load
Load --> Notify
Notify --> UI
Notify --> Callbacks
UI --> Complete
Callbacks --> Complete
Translation Request Flow
flowchart TD
Start["Chamelingo<br/>.Translate key"]
Manager["ChamelingoManager<br/>.Translate key"]
Cache{"Check in-memory<br/>cache Dictionary"}
Hit(["Return cached<br/>value"])
Miss(["Return key<br/>as fallback"])
Start --> Manager
Manager --> Cache
Cache -->|HIT| Hit
Cache -->|MISS| Miss
Note: All translations for the current language are loaded into memory when the language is changed. Individual translation lookups don't hit the disk.
Composite Text Processing
flowchart TD
Start["ChamelingoTextBase<br/>Composite Mode"]
Extract["Extract placeholders<br/>from template"]
Process["For each<br/>parameter"]
TransKey["TranslationKey:<br/>Translate +<br/>apply casing"]
Static["StaticText:<br/>Use as-is"]
CompValue["ComponentValue:<br/>Read from<br/>referenced component"]
CompEvent["ComponentEvent:<br/>Subscribe to<br/>updates"]
Replace["Replace placeholders<br/>with values"]
SetText(["Set final text"])
Start --> Extract
Extract --> Process
Process --> TransKey
Process --> Static
Process --> CompValue
Process --> CompEvent
TransKey --> Replace
Static --> Replace
CompValue --> Replace
CompEvent --> Replace
Replace --> SetText
Performance Considerations
Caching Strategy
Translation Cache:
- Entire language loaded into Dictionary<string, string>
- O(1) lookup time for translations
- Cache cleared and reloaded on language change
- No disk I/O during gameplay
Lazy Initialization: - ChamelingoManager created on first API access - Translations loaded on first language load - Components subscribe on Start()
Optimization Techniques
1. Memory Efficiency: - Only active language loaded in memory - Old translations cleared on language change
2. Composite Text: - Template parsing cached - Event subscriptions managed efficiently - Optional auto-refresh with configurable interval
3. Editor Performance: - Hub uses lazy loading for large key lists - Dropdown searches are filtered client-side - Asset database refreshes batched
Extensibility Points
Custom Text Components
Extend ChamelingoTextBase for custom UI frameworks:
public abstract class ChamelingoTextBase : MonoBehaviour
{
public abstract string GetText();
protected abstract void SetText(string text);
// Framework handles rest (subscriptions, lifecycle, composite text)
}
Thread Safety
Main Thread Required: - All Unity API calls - Language changes - Translation lookups - UI updates - PlayerPrefs access
Thread-Safe: - Event subscription/unsubscription (uses locks) - Singleton initialization (double-checked locking)
Unity Main Thread
Chamelingo is designed for Unity's single-threaded model. Do not call APIs from background threads.
Best Practices
- Always Unsubscribe: Call
Unsubscribe()inOnDestroyto prevent memory leaks - Use the Facade: Always access through
Chamelingostatic class, neverChamelingoManagerdirectly - Handle Missing Keys: Translation returns the key itself if not found - handle gracefully
- Batch Changes: When adding many keys, save once at the end
- Test Builds: Editor and Runtime use different code paths - always test builds
- Use Composite Wisely: Auto-refresh has performance cost - disable when not needed
Additional Resources
- User Guide - Feature documentation and workflows
- FAQ - Common questions and troubleshooting
For questions or discussions, visit our GitHub Discussions.