Files
orion/docs/development/migration/language-i18n-implementation.md
Samir Boulahtit d2b05441fc feat: add multi-language (i18n) support for vendor dashboard and storefront
- Add database fields for language preferences:
  - Vendor: dashboard_language, storefront_language, storefront_languages
  - User: preferred_language
  - Customer: preferred_language

- Add language middleware for request-level language detection:
  - Cookie-based persistence
  - Browser Accept-Language fallback
  - Vendor storefront language constraints

- Add language API endpoints (/api/v1/language/*):
  - POST /set - Set language preference
  - GET /current - Get current language info
  - GET /list - List available languages
  - DELETE /clear - Clear preference

- Add i18n utilities (app/utils/i18n.py):
  - JSON-based translation loading
  - Jinja2 template integration
  - Language resolution helpers

- Add reusable language selector macros for templates
- Add languageSelector() Alpine.js component
- Add translation files (en, fr, de, lb) in static/locales/
- Add architecture rules documentation for language implementation
- Update marketplace-product-detail.js to use native language names

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 22:36:09 +01:00

8.5 KiB

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:

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

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

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

POST /api/v1/language/set
Content-Type: application/json

{
    "language": "de"
}

Response:

{
    "success": true,
    "language": "de",
    "message": "Language set to Deutsch"
}

Translation Files

Translation files are stored in static/locales/{lang}.json with the following structure:

{
  "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

{# 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

{{ language_selector(
    current_language='fr',
    enabled_languages=['fr', 'de', 'en'],
    position='right',
    show_label=true
) }}

Compact Selector (Flag Only)

{{ language_selector_compact(
    current_language='fr',
    enabled_languages=['fr', 'de', 'en']
) }}

Language Settings Form

For vendor settings pages:

{{ 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 CSS library. Ensure this is included in your base template:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css">

Usage: <span class="fi fi-fr"></span> 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

# 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:

alembic downgrade -1

This will remove:

  • default_language, dashboard_language, storefront_language, storefront_languages from vendors
  • preferred_language from users
  • preferred_language from customers