Skip to content

Commit 70e1fd1

Browse files
domgewivanvermeyen
authored andcommitted
Add locale middleware for localized routes (#10)
1 parent 77535b9 commit 70e1fd1

File tree

5 files changed

+302
-9
lines changed

5 files changed

+302
-9
lines changed

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,53 @@ Setting this option to `'en'` will result, for example, in URL's like this:
8484

8585
> This option has no effect if you use domains instead of slugs.
8686
87+
#### Automatically Set Locale for Localized Routes
88+
89+
To automatically set the locale when a localized route is active via a middleware simply set the option to true:
90+
91+
```php
92+
'use_locale_middleware' => true
93+
```
94+
95+
Alternatively, you can omit it completely or specify it for a specific route or route group:
96+
97+
```php
98+
Route::localized(function () {
99+
100+
Route::get('about', AboutController::class.'@index')
101+
->name('about')
102+
->middleware(\CodeZero\LocalizedRoutes\Middleware\LocalizedRouteLocaleHandler::class);
103+
104+
Route::group(
105+
[
106+
'as' => 'admin.',
107+
'middleware' => [\CodeZero\LocalizedRoutes\Middleware\LocalizedRouteLocaleHandler::class],
108+
],
109+
function () {
110+
Route::get('admin/reports', ReportsController::class.'@index')
111+
->name('reports.index');
112+
});
113+
114+
});
115+
```
116+
117+
#### ☑️ Set Options for the Current Localized Route Group
118+
119+
To set an option for one localized route group only, you can specify it as the second parameter of the localized route macro:
120+
121+
```php
122+
Route::localized(function () {
123+
124+
Route::get('about', AboutController::class.'@index')
125+
->name('about');
126+
127+
}, [
128+
'supported-locales' => ['en', 'nl', 'fr'],
129+
'omit_url_prefix_for_locale' => null,
130+
'use_locale_middleware' => false,
131+
]);
132+
```
133+
87134
## 🚗 Register Routes
88135

89136
Example:

config/localized-routes.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@
1515
*/
1616
'omit_url_prefix_for_locale' => null,
1717

18+
/**
19+
* If you want to automatically set the locale
20+
* for localized routes set this to true.
21+
*/
22+
'use_locale_middleware' => false,
23+
1824
];

src/Macros/LocalizedRoutesMacro.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App;
66
use Config;
77
use Route;
8+
use CodeZero\LocalizedRoutes\Middleware\LocalizedRouteLocaleHandler;
89

910
class LocalizedRoutesMacro
1011
{
@@ -15,13 +16,17 @@ class LocalizedRoutesMacro
1516
*/
1617
public static function register()
1718
{
18-
Route::macro('localized', function ($callback) {
19+
Route::macro('localized', function ($callback, $options = []) {
1920
// Remember the current locale so we can
2021
// change it during route registration.
2122
$currentLocale = App::getLocale();
2223

23-
$locales = Config::get('localized-routes.supported-locales', []);
24-
$omitPrefix = Config::get('localized-routes.omit_url_prefix_for_locale');
24+
$locales = $options['supported-locales']
25+
?? Config::get('localized-routes.supported-locales', []);
26+
$omitPrefix = $options['omit_url_prefix_for_locale']
27+
?? Config::get('localized-routes.omit_url_prefix_for_locale');
28+
$setMiddleware = $options['use_locale_middleware']
29+
?? Config::get('localized-routes.use_locale_middleware', false);
2530

2631
foreach ($locales as $locale => $domain) {
2732
// Allow supported locales to be a
@@ -37,23 +42,30 @@ public static function register()
3742
// to register translated route URI's.
3843
App::setLocale($locale);
3944

40-
// Create a new route and prepend
41-
// the locale to the route name.
42-
$route = Route::name("{$locale}.");
45+
// Prepent the locale to the route name
46+
$attributes = [
47+
'as'=>"{$locale}.",
48+
'localized-routes-locale'=>$locale
49+
];
4350

4451
// Add a custom domain route group
4552
// if a domain is configured.
4653
if ($domain !== null) {
47-
$route->domain($domain);
54+
$attributes['domain'] = $domain;
4855
}
4956

5057
// Prefix the URL unless the locale
5158
// is configured to be omitted.
5259
if ($domain === null && $locale !== $omitPrefix) {
53-
$route->prefix($locale);
60+
$attributes['prefix'] = $locale;
5461
}
5562

56-
$route->group($callback);
63+
if ($setMiddleware) {
64+
$attributes['middleware'] = [LocalizedRouteLocaleHandler::class];
65+
}
66+
67+
// Execute the callback inside route group
68+
Route::group($attributes, $callback);
5769
}
5870

5971
// Restore the original locale.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace CodeZero\LocalizedRoutes\Middleware;
4+
5+
use Closure;
6+
use \Illuminate\Support\Facades\App;
7+
8+
class LocalizedRouteLocaleHandler
9+
{
10+
/**
11+
* Set language for localized route
12+
*
13+
* @param \Illuminate\Http\Request $request
14+
* @param \Closure $next
15+
* @return mixed
16+
*/
17+
public function handle($request, Closure $next)
18+
{
19+
$action = $request->route()->getAction();
20+
21+
if ($action['localized-routes-locale']) {
22+
App::setLocale($action['localized-routes-locale']);
23+
}
24+
25+
return $next($request);
26+
}
27+
}

tests/Unit/Macros/LocalizedRoutesMacroTest.php

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@ protected function setSupportedLocales($locales)
1515
Config::set('localized-routes.supported-locales', $locales);
1616
}
1717

18+
/**
19+
* Set the use_locale_middleware config option
20+
*
21+
* @param boolean $value
22+
* @return void
23+
*/
24+
protected function setUseLocaleMiddleware($value)
25+
{
26+
Config::set('localized-routes.use_locale_middleware', $value);
27+
}
28+
29+
/**
30+
* Set the omit_url_prefix_for_locale config option
31+
*
32+
* @param string $value
33+
* @return void
34+
*/
35+
protected function setOmitUrlPrefixForLocale($value)
36+
{
37+
Config::set('localized-routes.omit_url_prefix_for_locale', $value);
38+
}
39+
1840
protected function getRoutes()
1941
{
2042
// Route::has() doesn't seem to be working
@@ -137,4 +159,183 @@ public function it_temporarily_changes_the_app_locale_when_registering_the_route
137159

138160
$this->assertEquals('en', App::getLocale());
139161
}
162+
163+
/** @test */
164+
public function it_does_not_change_the_locale_without_activation()
165+
{
166+
$this->setSupportedLocales(['en', 'nl']);
167+
168+
$originalLocale = App::getLocale();
169+
170+
Route::localized(function () {
171+
Route::get('/', function () {
172+
return App::getLocale();
173+
});
174+
});
175+
176+
$response = $this->call('GET', '/en');
177+
$response->assertOk();
178+
$this->assertEquals($originalLocale, $response->original);
179+
180+
$response = $this->call('GET', '/nl');
181+
$response->assertOk();
182+
$this->assertEquals($originalLocale, $response->original);
183+
}
184+
185+
/** @test */
186+
public function it_sets_the_right_locale_when_accessing_localized_routes()
187+
{
188+
$this->setSupportedLocales(['en', 'nl']);
189+
$this->setUseLocaleMiddleware(true);
190+
191+
Route::localized(function () {
192+
Route::get('/', function () {
193+
return App::getLocale();
194+
});
195+
});
196+
197+
$response = $this->call('GET', '/en');
198+
$response->assertOk();
199+
$this->assertEquals('en', $response->original);
200+
201+
$response = $this->call('GET', '/nl');
202+
$response->assertOk();
203+
$this->assertEquals('nl', $response->original);
204+
}
205+
206+
/** @test */
207+
public function it_sets_the_right_locale_when_accessing_localized_routes_with_omitted_prefix()
208+
{
209+
$this->setSupportedLocales(['en', 'nl']);
210+
$this->setUseLocaleMiddleware(true);
211+
$this->setOmitUrlPrefixForLocale('en');
212+
213+
Route::localized(function () {
214+
Route::get('/', function () {
215+
return App::getLocale();
216+
});
217+
});
218+
219+
$response = $this->call('GET', '/');
220+
$response->assertOk();
221+
$this->assertEquals('en', $response->original);
222+
223+
$response = $this->call('GET', '/nl');
224+
$response->assertOk();
225+
$this->assertEquals('nl', $response->original);
226+
}
227+
228+
/** @test */
229+
public function it_correctly_uses_scoped_config_options()
230+
{
231+
$this->setSupportedLocales(['en', 'nl']);
232+
$this->setOmitUrlPrefixForLocale(null);
233+
$this->setUseLocaleMiddleware(false);
234+
235+
$otherLocale = 'none_of_the_above';
236+
237+
App::setLocale($otherLocale);
238+
239+
Route::localized(function () {
240+
Route::get('/without', function () {
241+
return App::getLocale();
242+
});
243+
});
244+
245+
Route::localized(function () {
246+
Route::get('/with', function () {
247+
return App::getLocale();
248+
});
249+
}, [
250+
'use_locale_middleware' => true,
251+
'omit_url_prefix_for_locale' => 'en',
252+
'supported-locales' => ['en', 'nl', 'de']
253+
]);
254+
255+
$response = $this->call('GET', '/without');
256+
$response->assertNotFound();
257+
258+
$response = $this->call('GET', '/en/without');
259+
$response->assertOk();
260+
$this->assertEquals($otherLocale, $response->original);
261+
262+
$response = $this->call('GET', '/nl/without');
263+
$response->assertOk();
264+
$this->assertEquals($otherLocale, $response->original);
265+
266+
$response = $this->call('GET', '/with');
267+
$response->assertOk();
268+
$this->assertEquals('en', $response->original);
269+
270+
$response = $this->call('GET', '/nl/with');
271+
$response->assertOk();
272+
$this->assertEquals('nl', $response->original);
273+
274+
$response = $this->call('GET', '/de/with');
275+
$response->assertOk();
276+
$this->assertEquals('de', $response->original);
277+
}
278+
279+
/** @test */
280+
public function it_creates_localized_routes_within_route_groups()
281+
{
282+
$this->setSupportedLocales(['en', 'nl']);
283+
284+
Route::group([
285+
'as' => 'admin.',
286+
'prefix' => 'admin'
287+
], function () {
288+
Route::localized(function () {
289+
Route::get('route', function () {})
290+
->name('route.name');
291+
});
292+
});
293+
294+
$routes = $this->getRoutes();
295+
$domains = $routes->pluck('action.domain');
296+
$names = $routes->pluck('action.as');
297+
$uris = $routes->pluck('uri');
298+
299+
// Verify that no custom domains are registered.
300+
$this->assertTrue($domains->filter()->isEmpty());
301+
302+
$this->assertNotContains('admin.route.name', $names);
303+
$this->assertContains('admin.en.route.name', $names);
304+
$this->assertContains('admin.nl.route.name', $names);
305+
306+
$this->assertNotContains('admin/route', $uris);
307+
$this->assertContains('admin/en/route', $uris);
308+
$this->assertContains('admin/nl/route', $uris);
309+
310+
$this->call('GET', '/admin/route')->assertNotFound();
311+
$this->call('GET', '/admin/en/route')->assertOk();
312+
$this->call('GET', '/admin/nl/route')->assertOk();
313+
}
314+
315+
/** @test */
316+
public function it_sets_the_locale_for_localized_routes_within_route_groups()
317+
{
318+
$this->setSupportedLocales(['en', 'nl']);
319+
$this->setUseLocaleMiddleware(true);
320+
321+
Route::group([
322+
'as' => 'admin.',
323+
'prefix' => 'admin'
324+
], function () {
325+
Route::localized(function () {
326+
Route::get('route', function () {
327+
return App::getLocale();
328+
})
329+
->name('route.name');
330+
});
331+
});
332+
333+
$response = $this->call('GET', '/admin/en/route');
334+
$response->assertOk();
335+
$this->assertEquals('en', $response->original);
336+
337+
$response = $this->call('GET', '/admin/nl/route');
338+
$response->assertOk();
339+
$this->assertEquals('nl', $response->original);
340+
}
140341
}

0 commit comments

Comments
 (0)