Files
orion/docs/development/migration/language-i18n-implementation.md
Samir Boulahtit e9253fbd84 refactor: rename Wizamart to Orion across entire codebase
Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart
with Orion/orion/ORION across 184 files. This includes database
identifiers, email addresses, domain references, R2 bucket names,
DNS prefixes, encryption salt, Celery app name, config defaults,
Docker configs, CI configs, documentation, seed data, and templates.

Renames homepage-wizamart.html template to homepage-orion.html.
Fixes duplicate file_pattern key in api.yaml architecture rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:46:56 +01:00

8.5 KiB

Language & Internationalization (i18n) Implementation

Overview

This document describes the implementation of multi-language support for the Orion platform. The system supports four languages (English, French, German, Luxembourgish) with flexible configuration at store, 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_store_user_customer

Stores Table

New columns added to stores:

ALTER TABLE stores ADD COLUMN default_language VARCHAR(5) NOT NULL DEFAULT 'fr';
ALTER TABLE stores ADD COLUMN dashboard_language VARCHAR(5) NOT NULL DEFAULT 'fr';
ALTER TABLE stores ADD COLUMN storefront_language VARCHAR(5) NOT NULL DEFAULT 'fr';
ALTER TABLE stores 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 store 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 store 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 store setting)

Architecture

Language Resolution Flow

Store Dashboard

User preferred_language
        |
        v (if not set)
Store 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)
Store 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/store.py Added language settings columns
models/database/user.py Added preferred_language column
models/database/customer.py Added preferred_language column
models/schema/store.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=store.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. StoreContextMiddleware
  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 store settings pages:

{{ language_settings_form(
    current_settings={
        'default_language': store.default_language,
        'dashboard_language': store.dashboard_language,
        'storefront_language': store.storefront_language,
        'storefront_languages': store.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
  • Store 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 stores 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 stores
  • preferred_language from users
  • preferred_language from customers