Skip to content

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

  1. Always Unsubscribe: Call Unsubscribe() in OnDestroy to prevent memory leaks
  2. Use the Facade: Always access through Chamelingo static class, never ChamelingoManager directly
  3. Handle Missing Keys: Translation returns the key itself if not found - handle gracefully
  4. Batch Changes: When adding many keys, save once at the end
  5. Test Builds: Editor and Runtime use different code paths - always test builds
  6. 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.