Skip to content

Commit 62ac3b3

Browse files
authored
Add support for trusted detectors (#14)
When a trusted detector returns a locale, it will be used as the app locale, regardless if it's a supported locale or not.
1 parent c1fca1d commit 62ac3b3

File tree

5 files changed

+106
-4
lines changed

5 files changed

+106
-4
lines changed

config/localizer.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@
3030
CodeZero\Localizer\Detectors\AppDetector::class,
3131
],
3232

33+
/**
34+
* Add any of the above detector class names here to make it trusted.
35+
* When a trusted detector returns a locale, it will be used
36+
* as the app locale, regardless if it's a supported locale or not.
37+
*/
38+
'trusted-detectors' => [
39+
//
40+
],
41+
3342
/**
3443
* The stores to store the first matching locale in.
3544
*/

src/Localizer.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Localizer
1414
protected $locales;
1515

1616
/**
17-
* \CoderZero\Localizer\Detectors\Detector instances.
17+
* \CoderZero\Localizer\Detectors\Detector class names or instances.
1818
*
1919
* @var \Illuminate\Support\Collection|array
2020
*/
@@ -27,18 +27,27 @@ class Localizer
2727
*/
2828
protected $stores;
2929

30+
/**
31+
* \CoderZero\Localizer\Detectors\Detector class names.
32+
*
33+
* @var \Illuminate\Support\Collection|array
34+
*/
35+
protected $trustedDetectors;
36+
3037
/**
3138
* Create a new Localizer instance.
3239
*
3340
* @param \Illuminate\Support\Collection|array $locales
3441
* @param \Illuminate\Support\Collection|array $detectors
3542
* @param \Illuminate\Support\Collection|array $stores
43+
* @param \Illuminate\Support\Collection|array $trustedDetectors
3644
*/
37-
public function __construct($locales, $detectors, $stores = [])
45+
public function __construct($locales, $detectors, $stores = [], $trustedDetectors = [])
3846
{
3947
$this->setSupportedLocales($locales);
4048
$this->detectors = $detectors;
4149
$this->stores = $stores;
50+
$this->trustedDetectors = $trustedDetectors;
4251
}
4352

4453
/**
@@ -52,7 +61,7 @@ public function detect()
5261
$locales = (array) $this->getInstance($detector)->detect();
5362

5463
foreach ($locales as $locale) {
55-
if ($this->isSupportedLocale($locale)) {
64+
if ($locale && ($this->isSupportedLocale($locale) || $this->isTrustedDetector($detector))) {
5665
return $locale;
5766
}
5867
}
@@ -105,6 +114,28 @@ protected function isSupportedLocale($locale)
105114
return in_array($locale, $this->locales);
106115
}
107116

117+
/**
118+
* Check if the given Detector class is trusted.
119+
*
120+
* @param \CodeZero\Localizer\Detectors\Detector|string $detector
121+
*
122+
* @return bool
123+
*/
124+
protected function isTrustedDetector($detector)
125+
{
126+
if (is_string($detector)) {
127+
return in_array($detector, $this->trustedDetectors);
128+
}
129+
130+
foreach ($this->trustedDetectors as $trustedDetector) {
131+
if ($detector instanceof $trustedDetector) {
132+
return true;
133+
}
134+
}
135+
136+
return false;
137+
}
138+
108139
/**
109140
* Get the class from Laravel's IOC container if it is a string.
110141
*

src/LocalizerServiceProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ protected function registerLocalizer()
7070
$locales = $app['config']->get("{$this->name}.supported-locales");
7171
$detectors = $app['config']->get("{$this->name}.detectors");
7272
$stores = $app['config']->get("{$this->name}.stores");
73+
$trustedDetectors = $app['config']->get("{$this->name}.trusted-detectors");
7374

74-
return new Localizer($locales, $detectors, $stores);
75+
return new Localizer($locales, $detectors, $stores, $trustedDetectors);
7576
});
7677
}
7778

tests/Feature/SetLocaleTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,31 @@ public function it_defaults_to_the_current_app_locale()
383383
$this->assertEquals('en', $response->original);
384384
}
385385

386+
/** @test */
387+
public function trusted_detectors_ignore_supported_locales_and_may_set_any_locale()
388+
{
389+
$this->setSupportedLocales(['en']);
390+
$this->setAppLocale('en');
391+
392+
$routeAction = ['locale' => 'nl'];
393+
394+
Config::set('localizer.trusted-detectors', [
395+
\CodeZero\Localizer\Detectors\RouteActionDetector::class,
396+
]);
397+
398+
Route::group($routeAction, function () {
399+
Route::get('some/route', function () {
400+
return App::getLocale();
401+
})->middleware(['web', SetLocale::class]);
402+
});
403+
404+
$response = $this->get('some/route');
405+
406+
$response->assertSessionHas($this->sessionKey, 'nl');
407+
$response->assertCookie($this->cookieName, 'nl');
408+
$this->assertEquals('nl', $response->original);
409+
}
410+
386411
/**
387412
* Set the current app locale.
388413
*

tests/Unit/LocalizerTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,42 @@ public function it_returns_the_best_match_if_an_array_of_locales_is_detected()
3939
$this->assertEquals('nl', $localizer->detect());
4040
}
4141

42+
/** @test */
43+
public function trusted_detectors_ignore_supported_locales_and_may_set_any_locale()
44+
{
45+
$supportedLocales = ['en'];
46+
$detectors = [
47+
Mockery::mock(Detector::class)->allows()->detect()->andReturns('nl')->getMock(),
48+
];
49+
$trustedDetectors = [
50+
Detector::class,
51+
];
52+
53+
$localizer = new Localizer($supportedLocales, $detectors, [], $trustedDetectors);
54+
55+
$this->assertEquals('nl', $localizer->detect());
56+
}
57+
58+
/** @test */
59+
public function empty_locales_from_trusted_detectors_are_ignored()
60+
{
61+
$supportedLocales = ['en'];
62+
$detectors = [
63+
Mockery::mock(Detector::class)->allows()->detect()->andReturns(false)->getMock(),
64+
Mockery::mock(Detector::class)->allows()->detect()->andReturns(null)->getMock(),
65+
Mockery::mock(Detector::class)->allows()->detect()->andReturns([])->getMock(),
66+
Mockery::mock(Detector::class)->allows()->detect()->andReturns('')->getMock(),
67+
Mockery::mock(Detector::class)->allows()->detect()->andReturns('en')->getMock(),
68+
];
69+
$trustedDetectors = [
70+
Detector::class,
71+
];
72+
73+
$localizer = new Localizer($supportedLocales, $detectors, [], $trustedDetectors);
74+
75+
$this->assertEquals('en', $localizer->detect());
76+
}
77+
4278
/** @test */
4379
public function it_returns_false_if_no_supported_locale_could_be_detected()
4480
{

0 commit comments

Comments
 (0)