Localization
Backend
- mcamara/laravel-localization prefixes routes with locale (e.g.
/en/dashboard).bootstrap/app.phpprepends LocaleCookieRedirect to the web stack; the locale route group useslocaleCookieRedirect,localizationRedirect,localeViewPath,setLocalizedFortifyRedirects. - config/laravellocalization.php —
supportedLocalesis overwritten at boot from the DB via SupportedLocalesService (cached; only enabled languages). Fallback: when the DB or cache is unavailable (e.g. CI before migrations), injection is skipped and file defaults are used so the app boots.urlsIgnored:/skipped,/admin,/admin/*,/horizon,/horizon/*,/translations,/translations/*(login/register stay under locale). - Content — Page uses Spatie Laravel Translatable (JSON columns for title, body, meta_title, meta_description); one row per logical page, locale chosen at runtime. Blog, FAQ, and Testimonials are row-per-locale (
BlogPost,Faq, andTestimonialhavelanguage_id; one row per locale per logical item). Settings and Landing sections use Spatie Translatable (JSON columns). Language model:languagestable keyed by code; each language hasis_enabled. - Enabling and disabling languages — In Filament, open Languages (CMS group) and use the Enabled toggle per language. Only enabled languages are included in
supportedLocales, the language switcher, and locale-prefixed routes. At least one language must remain enabled; the app default locale is always one of the enabled languages (when you disable the current default, another enabled language is set as default). - Locale JSON files —
lang/*.jsoncan be managed from the Filament admin panel via Translation Manager (Settings group). It uses spatie/laravel-translation-loader: translations are stored in thelanguage_linestable and optionally synced to/fromlang/*.json. Database entries override file-based translations when present. The list page shows a missing keys summary (locale buttons with counts); each opens Fill missing translations (/admin/language-lines/fill-missing?locale=…) to fill all missing keys for that locale in one form.
Frontend
- i18next + i18next-browser-languagedetector; translation files under
resources/js/i18n/. Backend passeslocale(and optionallylocale_switch_urls) via Inertia shared props; sync i18next and setdocument.documentElement.langanddir(e.g. RTL forar,fa). - Use logical CSS (
ps-*,pe-*) and direction-aware icons for RTL.