# Language & Internationalization (i18n) Implementation ## Overview This document describes the implementation of multi-language support for the Wizamart platform. The system supports four languages (English, French, German, Luxembourgish) with flexible configuration at vendor, user, and customer levels. ## Supported Languages | Code | Language | Native Name | Flag | |------|----------|-------------|------| | `en` | English | English | GB | | `fr` | French | Francais | FR | | `de` | German | Deutsch | DE | | `lb` | Luxembourgish | Letzebuerg | LU | **Default Language**: French (`fr`) - reflecting the Luxembourg market context. ## Database Changes ### Migration: `fcfdc02d5138_add_language_settings_to_vendor_user_customer` #### Vendors Table New columns added to `vendors`: ```sql ALTER TABLE vendors ADD COLUMN default_language VARCHAR(5) NOT NULL DEFAULT 'fr'; ALTER TABLE vendors ADD COLUMN dashboard_language VARCHAR(5) NOT NULL DEFAULT 'fr'; ALTER TABLE vendors ADD COLUMN storefront_language VARCHAR(5) NOT NULL DEFAULT 'fr'; ALTER TABLE vendors ADD COLUMN storefront_languages JSON NOT NULL DEFAULT '["fr", "de", "en"]'; ``` | Column | Type | Description | |--------|------|-------------| | `default_language` | VARCHAR(5) | Fallback language for content when translation unavailable | | `dashboard_language` | VARCHAR(5) | Default UI language for vendor dashboard | | `storefront_language` | VARCHAR(5) | Default language for customer-facing shop | | `storefront_languages` | JSON | Array of enabled languages for storefront selector | #### Users Table ```sql ALTER TABLE users ADD COLUMN preferred_language VARCHAR(5) NULL; ``` | Column | Type | Description | |--------|------|-------------| | `preferred_language` | VARCHAR(5) | User's preferred dashboard language (overrides vendor setting) | #### Customers Table ```sql ALTER TABLE customers ADD COLUMN preferred_language VARCHAR(5) NULL; ``` | Column | Type | Description | |--------|------|-------------| | `preferred_language` | VARCHAR(5) | Customer's preferred shop language (overrides vendor setting) | ## Architecture ### Language Resolution Flow #### Vendor Dashboard ``` User preferred_language | v (if not set) Vendor dashboard_language | v (if not set) System DEFAULT_LANGUAGE (fr) ``` #### Storefront ``` Customer preferred_language | v (if not set) Session/Cookie language | v (if not set) Vendor storefront_language | v (if not set) Browser Accept-Language header | v (if not supported) System DEFAULT_LANGUAGE (fr) ``` ### Files Created/Modified #### New Files | File | Description | |------|-------------| | `app/utils/i18n.py` | Core i18n utilities, translation loading, language resolution | | `middleware/language.py` | Language detection middleware | | `app/api/v1/shared/language.py` | Language API endpoints | | `app/templates/shared/macros/language_selector.html` | UI components for language selection | | `static/locales/en.json` | English translations | | `static/locales/fr.json` | French translations | | `static/locales/de.json` | German translations | | `static/locales/lb.json` | Luxembourgish translations | #### Modified Files | File | Changes | |------|---------| | `models/database/vendor.py` | Added language settings columns | | `models/database/user.py` | Added `preferred_language` column | | `models/database/customer.py` | Added `preferred_language` column | | `models/schema/vendor.py` | Added language fields to Pydantic schemas | | `models/schema/auth.py` | Added `preferred_language` to user schemas | | `models/schema/customer.py` | Added `preferred_language` to customer schemas | | `main.py` | Registered LanguageMiddleware | | `app/api/main.py` | Registered language API router | ## API Endpoints ### Language API (`/api/v1/language`) | Endpoint | Method | Description | |----------|--------|-------------| | `/api/v1/language/set` | POST | Set language preference (cookie) | | `/api/v1/language/current` | GET | Get current language info | | `/api/v1/language/list` | GET | List all available languages | | `/api/v1/language/clear` | DELETE | Clear language preference | ### Request/Response Examples #### Set Language ```http POST /api/v1/language/set Content-Type: application/json { "language": "de" } ``` Response: ```json { "success": true, "language": "de", "message": "Language set to Deutsch" } ``` ## Translation Files Translation files are stored in `static/locales/{lang}.json` with the following structure: ```json { "common": { "save": "Save", "cancel": "Cancel" }, "auth": { "login": "Login", "logout": "Logout" }, "nav": { "dashboard": "Dashboard", "products": "Products" } } ``` ### Key Naming Convention - Use dot notation for nested keys: `common.save`, `auth.login` - Use snake_case for key names: `product_name`, `order_status` - Group by feature/section: `products.add_product`, `orders.confirm_order` ## Template Integration ### Using Translations in Jinja2 ```jinja2 {# Import the translation function #} {% from 'shared/macros/language_selector.html' import language_selector %} {# Use translation function #} {{ _('common.save') }} {# With interpolation #} {{ _('welcome.message', name=user.name) }} {# Language selector component #} {{ language_selector( current_language=request.state.language, enabled_languages=vendor.storefront_languages ) }} ``` ### Request State Variables The LanguageMiddleware sets these on `request.state`: | Variable | Type | Description | |----------|------|-------------| | `language` | str | Resolved language code | | `language_info` | dict | Additional info (source, cookie value, browser value) | ## Middleware Order The LanguageMiddleware must run **after** ContextMiddleware (to know the context type) and **before** ThemeContextMiddleware. Execution order (request flow): 1. LoggingMiddleware 2. VendorContextMiddleware 3. ContextMiddleware 4. **LanguageMiddleware** <-- Detects language 5. ThemeContextMiddleware 6. FastAPI Router ## UI Components ### Full Language Selector ```jinja2 {{ language_selector( current_language='fr', enabled_languages=['fr', 'de', 'en'], position='right', show_label=true ) }} ``` ### Compact Selector (Flag Only) ```jinja2 {{ language_selector_compact( current_language='fr', enabled_languages=['fr', 'de', 'en'] ) }} ``` ### Language Settings Form For vendor settings pages: ```jinja2 {{ language_settings_form( current_settings={ 'default_language': vendor.default_language, 'dashboard_language': vendor.dashboard_language, 'storefront_language': vendor.storefront_language, 'storefront_languages': vendor.storefront_languages } ) }} ``` ## Flag Icons The language selector uses [flag-icons](https://flagicons.lipis.dev/) CSS library. Ensure this is included in your base template: ```html ``` Usage: `` for French flag. ## Testing ### Manual Testing Checklist - [ ] Language cookie is set when selecting language - [ ] Page reloads with correct language after selection - [ ] Vendor dashboard respects user's preferred_language - [ ] Storefront respects customer's preferred_language - [ ] Browser language detection works (clear cookie, use browser with different language) - [ ] Fallback to default language works for unsupported languages - [ ] Language selector shows only enabled languages on storefront ### API Testing ```bash # Set language curl -X POST http://localhost:8000/api/v1/language/set \ -H "Content-Type: application/json" \ -d '{"language": "de"}' # Get current language curl http://localhost:8000/api/v1/language/current # List languages curl http://localhost:8000/api/v1/language/list ``` ## Future Enhancements 1. **Admin Language Support**: Currently admin is English-only. The system is designed to easily add admin language support later. 2. **Translation Management UI**: Add a UI for vendors to manage their own translations (product descriptions, category names, etc.). 3. **RTL Language Support**: The `is_rtl_language()` function is ready for future RTL language support (Arabic, Hebrew, etc.). 4. **Auto-Translation**: Integration with translation APIs for automatic content translation. ## Rollback To rollback this migration: ```bash alembic downgrade -1 ``` This will remove: - `default_language`, `dashboard_language`, `storefront_language`, `storefront_languages` from `vendors` - `preferred_language` from `users` - `preferred_language` from `customers`