Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
93
app/Http/Middleware/SetLocale.php
Normal file
93
app/Http/Middleware/SetLocale.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Resolves the locale for the request and applies it to the framework, to
|
||||
* Carbon, and to translatable model attributes.
|
||||
*
|
||||
* Precedence, most specific first:
|
||||
*
|
||||
* 1. ?lang=xx — an explicit, single-request override (API friendly)
|
||||
* 2. session — what the signed-in visitor picked in the switcher
|
||||
* 3. users.locale — their stored preference
|
||||
* 4. Accept-Language — what their client asked for
|
||||
* 5. locales.default
|
||||
*/
|
||||
class SetLocale
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$locale = $this->resolve($request);
|
||||
|
||||
app()->setLocale($locale);
|
||||
|
||||
// Dates rendered in the panel and serialised by the API follow suit.
|
||||
CarbonImmutable::setLocale($locale);
|
||||
Carbon::setLocale($locale);
|
||||
|
||||
// Translatable attributes read this locale, and fall back to
|
||||
// locales.fallback when a record has no translation for it.
|
||||
app()->setFallbackLocale((string) config('locales.fallback'));
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
// Lets caches and clients see which language they actually received.
|
||||
$response->headers->set('Content-Language', $locale);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function resolve(Request $request): string
|
||||
{
|
||||
$supported = array_keys(config('locales.supported'));
|
||||
|
||||
$candidates = [
|
||||
$request->query(config('locales.query_parameter')),
|
||||
// The API stack is stateless, so there is no session to consult.
|
||||
// hasSession() is the safe check — session() throws when unset.
|
||||
$request->hasSession()
|
||||
? $request->session()->get(config('locales.session_key'))
|
||||
: null,
|
||||
$request->user()?->locale,
|
||||
$this->fromAcceptLanguage($request, $supported),
|
||||
config('locales.default'),
|
||||
];
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if (is_string($candidate) && in_array($candidate, $supported, true)) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return (string) config('locales.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick the best supported locale from the Accept-Language header, honouring
|
||||
* its quality values. "ca-ES" matches the "ca" we support.
|
||||
*
|
||||
* @param array<int, string> $supported
|
||||
*/
|
||||
protected function fromAcceptLanguage(Request $request, array $supported): ?string
|
||||
{
|
||||
foreach ($request->getLanguages() as $language) {
|
||||
$base = strtolower(str_replace('_', '-', $language));
|
||||
$base = explode('-', $base)[0];
|
||||
|
||||
if (in_array($base, $supported, true)) {
|
||||
return $base;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user