# Language & Internationalization (i18n) Architecture This document defines **strict rules** for implementing language support across the Orion platform. > **IMPORTANT:** These rules are mandatory. Violations will cause runtime errors, inconsistent UX, or security issues. --- ## Table of Contents 1. [Supported Languages](#supported-languages) 2. [Language Context Flow](#language-context-flow) 3. [Database Schema Rules](#database-schema-rules) 4. [Frontend Rules](#frontend-rules) 5. [API Rules](#api-rules) 6. [Template Rules](#template-rules) 7. [JavaScript Rules](#javascript-rules) 8. [Translation File Rules](#translation-file-rules) --- ## Supported Languages | Code | Language | Flag Code | Notes | |------|----------|-----------|-------| | `en` | English | `gb` | Fallback language | | `fr` | French | `fr` | Default for Luxembourg | | `de` | German | `de` | Second official language | | `lb` | Luxembourgish | `lu` | Native language | **Rule LANG-001: Only Use Supported Language Codes** ```python # ✅ GOOD: Use supported codes SUPPORTED_LANGUAGES = ["en", "fr", "de", "lb"] # ❌ BAD: Invalid codes language = "english" # ❌ Use "en" language = "french" # ❌ Use "fr" language = "lux" # ❌ Use "lb" ``` --- ## Language Context Flow ### Resolution Priority (per Frontend Type) Language resolution varies by frontend type. Each chain is evaluated top-to-bottom, first match wins: | Frontend | Priority (highest → lowest) | |----------|----------------------------| | **ADMIN** | User `preferred_language` → `"en"` | | **STORE** | Cookie (`lang`) → User `preferred_language` → Store `dashboard_language` → `"fr"` | | **STOREFRONT** | Customer `preferred_language` → Cookie (`lang`) → Store `storefront_language` → Browser `Accept-Language` → `"fr"` | | **PLATFORM** | Cookie (`lang`) → Browser `Accept-Language` → `"fr"` | The **cookie** (`lang`) is set by the language switcher UI via `POST /api/v1/platform/language/set` and represents the user's most recent explicit language choice. It takes priority over database preferences because it reflects an immediate UI action. ### Database Fields | Context | Language Source | Database Field | |---------|-----------------|----------------| | Store Dashboard | Store's `dashboard_language` | `stores.dashboard_language` | | Customer Storefront | Store's `storefront_language` | `stores.storefront_language` | | Admin Panel | User's `preferred_language` | `users.preferred_language` | --- ## Database Schema Rules ### Rule DB-001: Store Language Fields Are Required **Stores MUST have these language columns with defaults:** ```python # ✅ GOOD: All language fields with defaults class Store(Base): default_language = Column(String(5), nullable=False, default="fr") dashboard_language = Column(String(5), nullable=False, default="fr") storefront_language = Column(String(5), nullable=False, default="fr") storefront_languages = Column(JSON, nullable=False, default=["fr", "de", "en"]) ``` ```python # ❌ BAD: Nullable language fields class Store(Base): default_language = Column(String(5), nullable=True) # ❌ Must have default ``` ### Rule DB-002: User/Customer Preferred Language Is Optional ```python # ✅ GOOD: Optional with fallback logic class User(Base): preferred_language = Column(String(5), nullable=True) # Falls back to store/platform default class Customer(Base): preferred_language = Column(String(5), nullable=True) # Falls back to storefront_language ``` ### Rule DB-003: Pydantic Schemas Must Handle Missing Language Fields ```python # ✅ GOOD: Optional in response with defaults class StoreResponse(BaseModel): default_language: str = "fr" dashboard_language: str = "fr" storefront_language: str = "fr" storefront_languages: list[str] = ["fr", "de", "en"] # ❌ BAD: Required without defaults (breaks backward compatibility) class StoreResponse(BaseModel): default_language: str # ❌ Will fail if DB doesn't have value ``` --- ## Frontend Rules ### Rule FE-001: NEVER Use Inline Complex Alpine.js Data for Language Selector **Move complex JavaScript objects to functions. Inline x-data with Jinja breaks JSON serialization.** ```html