Multilanguage (i18n) for SaaS shouldn't be a headache. ๐
Just shared my production-ready system for #LaraFoundry:
Dual-layer: DB (Auth) vs Cookies (Guest)
5-level detection chain (IP, Browser, Session)
Seamless Inertia + Vue 3 integration
Deep dive
#Laravel #VILstack #BuildInPublic #PHP
Two separate middleware flows for i18n in LaraFoundry:
Auth users: locale saved in DB, persists across devices
Guests: locale in cookie (10-year expiry), detected via IP + browser
Different persistence strategies. Same detection chain. Same result.
#Laravel #SaaS #LaraFoundry #WebDev
LaraFoundry ships with built-in content translation via DeepL + Google Translate.
One interface, two providers. Swap in config:
'translator_default' => env('TRANSLATION_SERVICE', 'deepl')
Your code doesn't care which API it calls. The contract handles it.
#Laravel #DeepL #API #LaraFoundry
How I pass translations from Laravel to Vue without extra API calls:
HandleInertiaRequests middleware shares locale + translations as props. vue-i18n picks them up. Global t() function available everywhere.
{{ t('Dashboard') }} - done.
#Laravel #Vue #Inertia #LaraFoundry
The entire frontend i18n setup in LaraFoundry
That's literally it. No per-component imports.
#Laravel #Vue #JavaScript #LaraFoundry
Fun detail: LaraFoundry detects user's country from IP on first visit and auto-sets the language.
Ukrainian IP -> Ukrainian UI. No clicks needed.
The country_locale_map in config makes it dead simple to customize.
#SaaS #LaraFoundry #i18n #PHP
The locale detection chain in LaraFoundry:
1. User's saved preference (DB)
2. Session
3. Browser Accept-Language
4. IP geolocation (ip-api.com)
5. Default
Runs on every request. Detection happens once, then it's cached in session + cookie + DB.
#Laravel #i18n #LaraFoundry
"We'll localize it later."
Every SaaS project ever.
I just built a full multilanguage system for LaraFoundry - my Laravel SaaS framework.
Auto-detects language from browser + IP geolocation. 4 languages ready. Zero config for the user.
Thread coming this week.
#BuildInPublic #LaraFoundry #i18n
LaraFoundry update: 5 modules shipped. ๐
โ
Registration
โ
Authentication
โ
Multi-tenancy (Native)
โ
Logging (Activitylog + Custom)
โ
Multilanguage (i18n)
๐๏ธ Next: Navigation & Menu System
Building a battle-tested core in public so you don't have to.
Join the journey ๐
#LaraFoundry #SaaS #PHP
LaraFoundry Logging module recap:
- spatie/laravel-activitylog (extended)
- jenssegers/agent (device detection)
- opcodesio/log-viewer (web UI)
- laravel/telescope (dev debugger)
- Async geolocation via queued jobs
- 60+ events,zero manual log calls
#LaraFoundry #BuildInPublic #Laravel #OpenSource
Testing event-driven logging means testing the full chain:
User action -> Event -> Listener -> Service -> DB record -> Geo job
Each link can break independently. each link gets its own test.
A logging system that silently breaks is worse than no logging.
#Laravel #PestPHP #Testing #LaraFoundry
"We'll add logging later."
Famous last words in every SaaS project.
In LaraFoundry, logging is a Day 1 feature. Not an afterthought.
60+ events. Device fingerprinting. Geolocation. All automatic.
Thread below
www.linkedin.com/posts/dmitry...
#Laravel #SaaS #BuildInPublic #LaraFoundry
Building LaraFoundry: A modular Laravel core to kickstart your next SaaS. ๐ ๏ธ
Current status:
โ
Auth & Permissions
โ
Multi-tenancy (no-package)
โ
Logging Module (New!)
๐๏ธ Next module in progress...
Shipping in public. Join the journey! ๐
#SaaS #Laravel #BuildInPublic #LaraFoundry
LaraFoundry Multi-Tenancy Module:
- 1 trait for data isolation
- 100+ permissions
- 8 Gates
- 5 role templates
- 3 middleware components
- 5-level permission hierarchy
- Smart menu filtering + FAR pattern
- 19 test files
All battle-tested on Kohana.io.
#LaraFoundry #Laravel #MultiTenancy
Company A cannot touch Company B. Period. 19 test files proving it.
#LaraFoundry #Laravel #Security #Testing
This single Pest test proves the override system works
Revoke beats role. Grant beats role. Hierarchy intact.
#LaraFoundry #Laravel #Testing #PestPHP
Each user can set their own landing page per company.
Storekeeper -> "Warehouse report"
Manager -> "Orders report"
If permissions change and that page becomes inaccessible? Auto-cleared. User gets notified. Falls back to next available page.
#LaraFoundry #Laravel #SaaS #UX
User bookmarks Orders page. Owner removes their orders permission. User clicks bookmark.
Most SaaS: 403 page.
LaraFoundry: redirect to first accessible page + flash message.
I call it the FAR pattern - First Allowed Route. Zero 403 pages in production.
#LaraFoundry #Laravel #UX #BuildInPublic
In LaraFoundry, if you can't access a page-you don't see it in the menu.
Every menu item has a 'policyName'. Every request runs 'checkUserAndCompanyPolicy'.
A Storekeeper sees: Warehouse.
A Manager sees: Orders, Production, Contragents.
An Owner sees: everything.
#LaraFoundry #Laravel #Permissions
Active company stored in both session AND database.
Session = fast.
Database = reliable.
If session clears - middleware resolves from DB.
If DB is slow - session serves the request.
Belt and suspenders.
#LaraFoundry #Laravel #MultiTenancy #SaaS
LaraFoundry middleware chain for multi-tenancy:
1. SetActiveCompanyMiddleware - resolves tenant
2. CheckAccessMiddleware - ban + payment check
3. CheckCompanyAccess - owner-only gates
Order matters. Can't check permissions before you know the company.
#LaraFoundry #Laravel #Middleware #Architecture
Your Manager role has 'orders.delete'.
One specific manager shouldn't delete orders.
Solution: revoke that ONE permission for that ONE user.
No new role. No code change. Just 'is_revoked = true' in the pivot table.
#LaraFoundry #Laravel #Permissions #SaaS
When a company is created in LaraFoundry, 5 role templates are auto-cloned:
- Manager
- Accountant
- Storekeeper
- Logistician
- Worker
Company owner can customize all of them + create new ones. No developer needed.
#LaraFoundry #Laravel #SaaS #BuildInPublic
LaraFoundry permission priority:
1. Super Admin -> always true
2. Owner -> full company access
3. Revoked -> blocks even if role allows
4. Individual grant -> overrides role
5. Role-based -> inherited permissions
One method: 'hasPermissionTo()'. Five levels of logic.
#LaraFoundry #Laravel #RBAC
Simple permissions -> config file.
Complex authorization -> dedicated Gate classes.
Clean. Testable. Each module gets its own file.
#LaraFoundry #Laravel #Gates #CleanCode
100+ permissions in my SaaS. Zero in AuthServiceProvider.
All defined in one config file. All auto-registered as Gates on boot.
Sync with `php artisan permissions:sync`. Done.
#LaraFoundry #Laravel #Authorization #BuildInPublic
LaraFoundry's `BelongsToCompany` trait:
One trait on your model. Zero chance of data leaks. Global scope handles everything.
#LaraFoundry #Laravel #Eloquent #SaaS
The scariest bug in multi-tenant SaaS: showing Company A's data to Company B.
It only takes ONE forgotten `where('company_id', ...)`.
LaraFoundry solves this at the model level with a single trait. Automatic. Unforgettable.
#LaraFoundry #Laravel #MultiTenancy #Security
Every Laravel SaaS tutorial teaches you auth.
None of them teach you what happens after login:
- Which company does this request belong to?
- Can this user see the Orders page?
- What if they work for 2 companies?
I built a complete multi-tenancy system.
#LaraFoundry #Laravel #SaaS #BuildInPublic
LaraFoundry Authentication Module:
- 6 login methods (email, OAuth x3, QR code, PIN)
- 3 admin security layers
- 5 middleware components
- 0 third-party auth services
- Full Pest test suite
All extracted from a production SaaS (Kohana.io). All battle-tested.
#LaraFoundry #Laravel #BuildInPublic