[ 'app_name' => 'CargoLink', 'nav_home' => 'Overview', 'nav_shipper' => 'Shipper Desk', 'nav_owner' => 'Truck Owner Desk', 'nav_admin' => 'Admin Panel', 'hero_title' => 'Move cargo faster with verified trucks.', 'hero_subtitle' => 'Post shipments, collect offers, and pay via Thawani or bank transfer. Built for local and nearby cross-border moves.', 'hero_tagline' => 'Multilingual Logistics Marketplace', 'register_shipper' => 'Register as Shipper', 'register_owner' => 'Register as Truck Owner', 'cta_shipper' => 'Post a shipment', 'cta_owner' => 'Find loads', 'cta_admin' => 'Open admin', 'stats_shipments' => 'Shipments posted', 'stats_offers' => 'Active offers', 'stats_confirmed' => 'Confirmed trips', 'section_workflow' => 'How it works', 'recent_shipments' => 'Recent shipments', 'step_post' => 'Shipper posts cargo details and preferred payment.', 'step_offer' => 'Truck owners respond with their best rate.', 'step_confirm' => 'Admin confirms booking and status.', 'shipper_dashboard' => 'Shipper Dashboard', 'new_shipment' => 'Create shipment', 'shipper_name' => 'Shipper name', 'shipper_company' => 'Company', 'origin' => 'Origin city', 'destination' => 'Destination city', 'cargo' => 'Cargo description', 'weight' => 'Weight (tons)', 'pickup_date' => 'Pickup date', 'delivery_date' => 'Delivery date', 'payment_method' => 'Payment method', 'payment_thawani' => 'Thawani online payment', 'payment_bank' => 'Bank transfer', 'submit_shipment' => 'Submit shipment', 'shipments_list' => 'Your latest shipments', 'status' => 'Status', 'offer' => 'Best offer', 'actions' => 'Actions', 'view' => 'View', 'owner_dashboard' => 'Truck Owner Dashboard', 'available_shipments' => 'Available shipments', 'offer_price' => 'Offer price', 'offer_owner' => 'Truck owner name', 'submit_offer' => 'Send offer', 'admin_dashboard' => 'Admin Dashboard', 'update_status' => 'Update status', 'save' => 'Save', 'shipment_detail' => 'Shipment detail', 'created_at' => 'Created', 'best_offer' => 'Best offer', 'assign_owner' => 'Assigned owner', 'no_shipments' => 'No shipments yet. Create the first one to get started.', 'no_offers' => 'No offers yet.', 'success_shipment' => 'Shipment posted successfully.', 'success_offer' => 'Offer submitted to the shipper.', 'success_status' => 'Status updated.', 'error_required' => 'Please fill in all required fields.', 'error_invalid' => 'Please enter valid values.', 'status_posted' => 'Posted', 'status_offered' => 'Offered', 'status_confirmed' => 'Confirmed', 'status_in_transit' => 'In transit', 'status_delivered' => 'Delivered', 'footer_note' => 'This is the initial MVP slice. Payments are not yet connected.', 'marketing_title_1' => 'For Shippers', 'marketing_desc_1' => 'Find the right truck for your cargo quickly and securely. Post your load and get offers instantly.', 'marketing_title_2' => 'For Truck Owners', 'marketing_desc_2' => 'Maximize your earnings and eliminate empty miles. Browse available shipments and offer your rate.', 'motivation_phrase' => 'Empowering the logistics of tomorrow.', 'why_choose_us' => 'Why Choose CargoLink?', 'feature_1_title' => 'Fast Matching', 'feature_1_desc' => 'Connect with available trucks or shipments in minutes.', 'feature_2_title' => 'Secure Payments', 'feature_2_desc' => 'Your transactions are protected with security.', 'feature_3_title' => 'Verified Users', 'feature_3_desc' => 'We verify all truck owners to ensure peace of mind.', ], 'ar' => [ 'app_name' => 'CargoLink', 'nav_home' => 'نظرة عامة', 'nav_shipper' => 'لوحة الشاحن', 'nav_owner' => 'لوحة مالك الشاحنة', 'nav_admin' => 'لوحة الإدارة', 'hero_title' => 'انقل شحنتك بسرعة مع شاحنات موثوقة.', 'hero_subtitle' => 'أنشئ شحنة، استلم عروضاً، وادفع عبر ثواني أو التحويل البنكي.', 'hero_tagline' => 'منصة لوجستية متعددة اللغات', 'register_shipper' => 'التسجيل كشاحن', 'register_owner' => 'التسجيل كمالك شاحنة', 'cta_shipper' => 'إنشاء شحنة', 'cta_owner' => 'البحث عن الشحنات', 'cta_admin' => 'الدخول للإدارة', 'stats_shipments' => 'الشحنات المنشورة', 'stats_offers' => 'العروض الحالية', 'stats_confirmed' => 'الرحلات المؤكدة', 'section_workflow' => 'طريقة العمل', 'recent_shipments' => 'أحدث الشحنات', 'step_post' => 'يقوم الشاحن بإدخال تفاصيل الشحنة وطريقة الدفع.', 'step_offer' => 'يرسل أصحاب الشاحنات أفضل عروضهم.', 'step_confirm' => 'تؤكد الإدارة الحجز وتحدث الحالة.', 'shipper_dashboard' => 'لوحة الشاحن', 'new_shipment' => 'إنشاء شحنة', 'shipper_name' => 'اسم الشاحن', 'shipper_company' => 'الشركة', 'origin' => 'مدينة الانطلاق', 'destination' => 'مدينة الوصول', 'cargo' => 'وصف الحمولة', 'weight' => 'الوزن (طن)', 'pickup_date' => 'تاريخ الاستلام', 'delivery_date' => 'تاريخ التسليم', 'payment_method' => 'طريقة الدفع', 'payment_thawani' => 'الدفع الإلكتروني عبر ثواني', 'payment_bank' => 'تحويل بنكي', 'submit_shipment' => 'إرسال الشحنة', 'shipments_list' => 'أحدث الشحنات', 'status' => 'الحالة', 'offer' => 'أفضل عرض', 'actions' => 'إجراءات', 'view' => 'عرض', 'owner_dashboard' => 'لوحة مالك الشاحنة', 'available_shipments' => 'الشحنات المتاحة', 'offer_price' => 'سعر العرض', 'offer_owner' => 'اسم مالك الشاحنة', 'submit_offer' => 'إرسال العرض', 'admin_dashboard' => 'لوحة الإدارة', 'update_status' => 'تحديث الحالة', 'save' => 'حفظ', 'shipment_detail' => 'تفاصيل الشحنة', 'created_at' => 'تم الإنشاء', 'best_offer' => 'أفضل عرض', 'assign_owner' => 'المالك المعتمد', 'no_shipments' => 'لا توجد شحنات بعد. ابدأ بإنشاء أول شحنة.', 'no_offers' => 'لا توجد عروض بعد.', 'success_shipment' => 'تم نشر الشحنة بنجاح.', 'success_offer' => 'تم إرسال العرض إلى الشاحن.', 'success_status' => 'تم تحديث الحالة.', 'error_required' => 'يرجى تعبئة جميع الحقول المطلوبة.', 'error_invalid' => 'يرجى إدخال قيم صحيحة.', 'status_posted' => 'منشورة', 'status_offered' => 'بعرض', 'status_confirmed' => 'مؤكدة', 'status_in_transit' => 'قيد النقل', 'status_delivered' => 'تم التسليم', 'footer_note' => 'هذه هي النسخة الأولية. الدفع غير متصل بعد.', 'marketing_title_1' => 'للشاحنين', 'marketing_desc_1' => 'ابحث عن الشاحنة المناسبة لحمولتك بسرعة وأمان.', 'marketing_title_2' => 'لأصحاب الشاحنات', 'marketing_desc_2' => 'عظّم أرباحك وتجنب العودة فارغاً.', 'motivation_phrase' => 'تمكين الخدمات اللوجستية للمستقبل.', 'why_choose_us' => 'لماذا تختار كارجو لينك؟', 'feature_1_title' => 'مطابقة سريعة', 'feature_1_desc' => 'تواصل مع الشاحنات المتاحة في دقائق.', 'feature_2_title' => 'مدفوعات آمنة', 'feature_2_desc' => 'معاملاتك محمية بأعلى معايير الأمان.', 'feature_3_title' => 'مستخدمون موثوقون', 'feature_3_desc' => 'نقوم بالتحقق من جميع أصحاب الشاحنات لضمان راحتك.', ], ]; function t(string $key): string { global $translations, $lang; return $translations[$lang][$key] ?? $key; } function e($value): string { return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); } function ensure_schema(): void { $sql = <<exec($sql); try { db()->exec("ALTER TABLE users ADD COLUMN status ENUM('pending','active','rejected') NOT NULL DEFAULT 'active'"); } catch (Exception $e) {} db()->exec( "CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, full_name VARCHAR(255) NOT NULL, role ENUM('admin','shipper','truck_owner') NOT NULL, status ENUM('pending','active','rejected') NOT NULL DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" ); db()->exec( "CREATE TABLE IF NOT EXISTS shipper_profiles ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL UNIQUE, company_name VARCHAR(255) NOT NULL, phone VARCHAR(40) NOT NULL, country_id INT NULL, city_id INT NULL, address_line VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_shipper_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" ); db()->exec( "CREATE TABLE IF NOT EXISTS truck_owner_profiles ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL UNIQUE, phone VARCHAR(40) NOT NULL, country_id INT NULL, city_id INT NULL, address_line VARCHAR(255) NOT NULL, truck_type VARCHAR(120) NOT NULL, load_capacity DECIMAL(10,2) NOT NULL, plate_no VARCHAR(80) NOT NULL, id_card_path TEXT NOT NULL, truck_pic_path VARCHAR(255) NOT NULL, registration_path TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_owner_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" ); } function set_flash(string $type, string $message): void { $_SESSION['flash'] = ['type' => $type, 'message' => $message]; } function get_flash(): ?array { if (!empty($_SESSION['flash'])) { $flash = $_SESSION['flash']; unset($_SESSION['flash']); return $flash; } return null; } function url_with_lang(string $path, array $params = []): string { global $lang; $params = array_merge(['lang' => $lang], $params); return $path . '?' . http_build_query($params); } function current_url_with_lang(string $newLang): string { $params = $_GET; $params['lang'] = $newLang; $path = basename($_SERVER['PHP_SELF'] ?? 'index.php'); return $path . '?' . http_build_query($params); } function status_label(string $status): string { $map = [ 'posted' => t('status_posted'), 'offered' => t('status_offered'), 'confirmed' => t('status_confirmed'), 'in_transit' => t('status_in_transit'), 'delivered' => t('status_delivered'), ]; return $map[$status] ?? $status; } function get_settings(): array { static $settings = null; if ($settings !== null) { return $settings; } $settings = []; try { $stmt = db()->query("SELECT setting_key, setting_value FROM settings"); while ($row = $stmt->fetch()) { $settings[$row['setting_key']] = $row['setting_value']; } } catch (Throwable $e) { } return $settings; } function get_setting(string $key, $default = ''): string { $settings = get_settings(); return $settings[$key] ?? $default; }