libra/docs/stories/story-1.3-bilingual-infrast...

4.2 KiB

Story 1.3: Bilingual Infrastructure (Arabic/English)

Epic Reference

Epic 1: Core Foundation & Infrastructure

User Story

As a user (admin or client), I want full bilingual support with Arabic as primary and English as secondary language, So that I can use the platform in my preferred language with proper RTL/LTR layout.

Story Context

Existing System Integration

  • Integrates with: Laravel localization, Tailwind CSS, user preferences
  • Technology: Laravel lang files, Tailwind RTL, Google Fonts
  • Follows pattern: Laravel localization best practices
  • Touch points: All views, navigation, date/time formatting

Acceptance Criteria

Functional Requirements

  • Language files for Arabic (ar) and English (en)
  • Language toggle in navigation (visible on all pages)
  • User language preference stored in users.preferred_language
  • Guest language stored in session
  • RTL layout for Arabic, LTR for English
  • All UI elements translatable via __() helper

Date/Time Formatting

  • Arabic: DD/MM/YYYY format
  • English: MM/DD/YYYY format
  • Both: 12-hour time format (AM/PM)
  • Both: Western numerals (123) - no Arabic numerals

Typography

  • Arabic fonts: Cairo or Tajawal (Google Fonts)
  • English fonts: Montserrat or Lato (Google Fonts)
  • Font weights: 300, 400, 600, 700
  • font-display: swap for performance

Integration Requirements

  • Language middleware sets locale from user preference or session
  • Direction attribute (dir="rtl" or dir="ltr") on HTML element
  • Tailwind RTL utilities working
  • Forms align correctly in both directions

Quality Requirements

  • No hardcoded strings in views
  • All translation keys organized by feature
  • Tests verify language switching
  • No layout breaks when switching languages

Technical Notes

Language Middleware

// Middleware to set locale
public function handle($request, Closure $next)
{
    $locale = session('locale',
        auth()->user()?->preferred_language ?? 'ar'
    );
    app()->setLocale($locale);
    return $next($request);
}

Translation File Structure

resources/lang/
  ar/
    auth.php
    pagination.php
    validation.php
    messages.php
    navigation.php
  en/
    auth.php
    pagination.php
    validation.php
    messages.php
    navigation.php

RTL Support with Tailwind 4

/* In app.css */
@import "tailwindcss";

@theme {
  /* RTL support via logical properties */
}

Font Configuration

/* Google Fonts import */
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&family=Montserrat:wght@300;400;600;700&display=swap');

@theme {
  --font-arabic: 'Cairo', 'Tajawal', sans-serif;
  --font-english: 'Montserrat', 'Lato', sans-serif;
}

Layout Template

<html lang="{{ app()->getLocale() }}" dir="{{ app()->getLocale() === 'ar' ? 'rtl' : 'ltr' }}">
<head>
    <style>
        body { font-family: var(--font-{{ app()->getLocale() === 'ar' ? 'arabic' : 'english' }}); }
    </style>
</head>

Date Formatting Helper

// In a helper or service
public function formatDate($date, $locale = null): string
{
    $locale = $locale ?? app()->getLocale();
    $format = $locale === 'ar' ? 'd/m/Y' : 'm/d/Y';
    return Carbon::parse($date)->format($format);
}

Definition of Done

  • Language toggle works in navigation
  • Arabic and English translations complete for core UI
  • RTL layout renders correctly for Arabic
  • LTR layout renders correctly for English
  • User preference persists in database
  • Guest preference persists in session
  • Dates format correctly per language
  • Fonts load properly for both languages
  • Tests pass for language switching
  • Code formatted with Pint

Dependencies

  • Story 1.1: Database schema (users.preferred_language column)
  • Story 1.4: Base UI (navigation for language toggle)

Risk Assessment

  • Primary Risk: RTL edge cases in complex layouts
  • Mitigation: Use Tailwind logical properties (start/end vs left/right), test early
  • Rollback: Fallback to LTR-only temporarily

Estimation

Complexity: Medium-High Estimated Effort: 4-5 hours