Introduction
This is a middleware that takes care of setting the app locale to the passed in locale string (e.g en
, fr
).
My use case for this is an app that serves primarily as an API server, and incoming requests do not contain data on the preferred locale. Locale is determined by detecting the language of the text in a request parameter, e.g the text in $request->description
.
Creating the middleware
Let’s create the middleware with:
php artisan make:middleware SetLocale
Then open the file (\App\Http\Middleware\SetLocale
) and replace the content with:
<?php
namespace App\Http\Middleware;
use Closure;
class SetLocale
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $lang The language key to use in setting the app locale, e.g 'en', 'fr'
* @return mixed
*/
public function handle($request, Closure $next, string $lang)
{
app()->setLocale($lang);
return $next($request);
}
}
Note that the handle()
method, which usually only takes a $request
and a $next
closure, has a third parameter, which is our passed in parameter, $lang
. To learn more about creating parameterized middleware, read this post by Matt Stauffer, as well as the Laravel docs.
Next up let’s register the middleware in the \App\Http\Kernel
class.
NOTE: If you’ve never used middleware before, you need to ensure that this middleware is registered in the HTTP Kernel as a
routeMiddleware
—there’s no way you could pass parameters to a universal middleware.
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
// ...
protected $routeMiddleware = [
// ...
'setLocale' => \App\Http\Middleware\SetLocale::class,
];
// ...
}
Usage Examples
You may assign the middleware to a route:
<?php
Route::post('reviews', 'CreateReviewController')->middleware('setLocale:fr');
You may equally use it within a controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CreateReviewController extends Controller
{
public function __construct()
{
$lang = 'fr'; // You may add logic to dynamically get the lang key here
$this->middleware("setLocale:$lang");
}
/**
* Handle the incoming request.
*
* @return \Response
*/
public function __invoke(Request $request)
{
// Controller logic and response ..
}
}
Tests
To test the middleware, let’s create a unit test:
php artisan make:test SetLocaleMiddlewareTest --unit
Then flesh it out as below:
<?php
namespace Tests\Unit;
use App\Http\Kernel;
use App\Http\Middleware\SetLocale;
use Illuminate\Http\Request;
use Tests\TestCase;
class SetLocaleMiddlewareTest extends TestCase
{
/** @test */
public function it_is_correctly_registered_in_route_middleware_array_of_the_http_kernel()
{
$routeMiddleware = resolve(Kernel::class)->getRouteMiddleware();
$this->assertArrayHasKey('setLocale', $routeMiddleware);
// Assert it's pointing to the correct namespace
$this->assertEquals(SetLocale::class, $routeMiddleware['setLocale']);
}
/** @test */
public function it_correctly_sets_the_app_locale_to_the_passed_in_locale_string()
{
$request = new Request;
$middleware = new SetLocale;
$middleware->handle($request, function ($req) {
$this->assertEquals('fr', app()->getLocale());
}, 'fr');
}
}
For more on Laravel middleware testing, have a look at this blog post by Christopher Vundi.