Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master dev mid mutate #1

Merged
merged 5 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions src/Bundles/Middleware/LocalizationMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,35 @@ class LocalizationMiddleware
{
public function handle(Request $request, Closure $next)
{
$headerLanguage = $request->header('Accept-Language');

if ($headerLanguage === null) {
return $next($request);
}

$locale = $this->parseHeader($request);

if (in_array($locale, ['', '*'], true) === false) {
if (strlen($locale) === 2) {
app()->setLocale($locale);
}

return $next($request);
}

private function parseHeader(Request $request)
private function parseHeader(Request $request): string
{
$acceptedLanguage = explode(',', $request->header('Accept-Language', ''));
$acceptedLanguage = explode(',', $request->header('Accept-Language'));

$extendedPreferredLanguages = [];

foreach ($acceptedLanguage as $language) {
$parts = explode(';', $language, 2);
[$tag, $quality] = explode(';', $language) + [null, null];

$locale = trim(str_contains($tag, '-')
? strstr($tag, '-', true)
: $tag);

$locale = trim(str_contains($parts[0], '-')
? strstr($parts[0], '-', true)
: $parts[0]);
$factor = isset($parts[1]) ? Str::after($parts[1], '=') : '1';
$factor = $quality ? Str::after($quality, '=') : '1';

if (isset($extendedPreferredLanguages[$factor]) === false) {
$extendedPreferredLanguages[$factor] = $locale;
Expand Down
4 changes: 3 additions & 1 deletion src/SamSkeletonServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@

use Illuminate\Support\ServiceProvider;

class SamSkeletonServiceProvider extends ServiceProvider {}
class SamSkeletonServiceProvider extends ServiceProvider
{
}
4 changes: 2 additions & 2 deletions tests/Middleware/ForceJsonMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
$this->middleware = new ForceJsonMiddleware();
});

it('can get request', function (): void {
it('returns the callback result', function (): void {
$middleware = $this->middleware->handle(createAcceptRequest(), fn (Request $request) => $request);

expect($middleware)
Expand All @@ -35,7 +35,7 @@
});
});

it('leave Accept header to original value', function ($payload): void {
it('leaves Accept header to original value', function ($payload): void {
$this->middleware->handle(createAcceptRequest($payload), function (Request $request) use ($payload) {
expect($request)
->headers->get('Accept')->toContain($payload)
Expand Down
125 changes: 84 additions & 41 deletions tests/Middleware/LocalizationMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,117 @@

namespace Totem\SamSkeleton\Tests\Middleware;

use Illuminate\Http\Response;
use Illuminate\Http\Request;
use Orchestra\Testbench\TestCase;
use Totem\SamSkeleton\Bundles\Middleware\LocalizationMiddleware;

use function Totem\SamSkeleton\Tests\createLangRequest;

uses(TestCase::class);

covers(LocalizationMiddleware::class);

beforeEach(function () {
$this->middleware = new LocalizationMiddleware();
$this->translator = resolve('translator');
$this->lines = [
config('app.locale') => 'test line for DEFAULT',
'en' => 'test line for EN',
'de' => 'test line for DEU',
];
foreach ($this->lines as $locale => $line) {
app('translator')->addLines(['test.fake_' => $line], $locale);
$this->translator->addLines(['test.fake_' => $line], $locale);
}
$this->middleware = new LocalizationMiddleware;
$this->translator = app('translator');
});

it('can get locale', function (): void {
expect([
$this->translator->getLocale(),
__('test.fake_', [], config('app.locale')),
])->sequence(
fn ($data) => $data
->toBe(config('app.locale')),
fn ($data) => $data
->toBe($this->lines[config('app.locale')]),
fn ($data) => $data->toBe(config('app.locale')),
fn ($data) => $data->toBe($this->lines[config('app.locale')]),
);
});

it('can parse', function ($payload, $value): void {
$this->middleware->handle(createLangRequest($payload), fn () => new Response);
describe('locale behavior', function (): void {
it('can parse header', function ($payload, $value): void {
$this->middleware->handle(createLangRequest($payload), fn () => null);

expect([
$this->translator->getLocale(),
__('test.fake_', [], $value),
])->sequence(
fn ($data) => $data
->toBe($value),
fn ($data) => $data
->toBe($this->lines[$value]),
);
})->with([
'single locale' => ['de', 'de'],
'locale with country' => ['en-US', 'en'],
'locale with country and quality value' => ['en-US;q=0.5', 'en'],
'multiple locales' => ['en, de', 'en'],
'multiple locales with countries' => ['en-US, de-DE', 'en'],
'multiple locales with countries and quality values' => ['en-US;q=0.8, de-DE;q=0.9', 'de'],
'mixed locale values' => ['de-DE, de;q=0.7, fr;q=0.9, en;q=0.8, *;q=0.5', 'de'],
]);
expect([
$this->translator->getLocale(),
__('test.fake_', [], $value),
])->sequence(
fn ($data) => $data->toBe($value),
fn ($data) => $data->toBe($this->lines[$value]),
);
})->with([
'single locale' => ['de', 'de'],
'locale with country' => ['en-US', 'en'],
'locale with country and quality value' => ['en-US;q=0.5', 'en'],
'multiple locales' => ['en, de', 'en'],
'multiple locales with countries' => ['en-US, de-DE', 'en'],
'multiple locales with countries and quality values' => ['en-US;q=0.8, de-DE;q=0.9', 'de'],
'mixed locale values' => ['de-DE, de;q=0.7, fr;q=0.9, en;q=0.8, *;q=0.5', 'de'],
]);

it('does not set locale', function ($payload): void {
$this->middleware->handle(createLangRequest($payload), fn () => new Response);
it('does not set locale', function ($payload): void {
$this->middleware->handle(createLangRequest($payload), fn () => null);

expect([
$this->translator->getLocale(),
__('test.fake_', [], config('app.locale')),
])->sequence(
fn ($data) => $data
->toBe(config('app.locale')),
fn ($data) => $data
->toBe($this->lines[config('app.locale')]),
);
expect([
$this->translator->getLocale(),
__('test.fake_', [], config('app.locale')),
app()->getLocale()
])->sequence(
fn ($data) => $data->toBe(config('app.locale')),
fn ($data) => $data->toBe($this->lines[config('app.locale')]),
fn ($data) => $data->not->toBe($payload),
);
})->with([
'header is not sent' => [''],
'header has asterisk' => ['*'],
'incompatible locale' => [fake()->sentence(1)],
'monkey string' => [' ; ,;']
]);

it('does not set locale when header is missing', function () {
$request = createLangRequest();
$request->headers->replace();

$this->middleware->handle($request, fn () => null);

expect([
$this->translator->getLocale(),
__('test.fake_', [], config('app.locale')),
app()->getLocale()
])->sequence(
fn ($data) => $data->toBe(config('app.locale')),
fn ($data) => $data->toBe($this->lines[config('app.locale')]),
fn ($data) => $data->toBe(config('app.locale')),
);
});
});

it('not changing return callback result', function ($payload): void {
$middleware = $this->middleware->handle(createLangRequest($payload), fn (Request $request) => $request);

expect($middleware)
->toBeInstanceOf(Request::class)
->headers->get('accept-language')->toContain($payload);
})->with([
'header is not sent' => [''],
'header has asterix' => ['*'],
'country code' => ['pl'],
'empty' => [''],
'empty space' => [' '],
'asterisk' => ['*'],
'monkey string' => [' ; ,;']
]);

it('not set accept-language header when request header is missing', function () {
$request = createLangRequest();
$request->headers->replace();

$middleware = $this->middleware->handle($request, fn (Request $request) => $request);

expect($middleware)->toBeInstanceOf(Request::class)
->headers->get('accept-language')->toBeNull();
});
4 changes: 2 additions & 2 deletions tests/Pest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

use Illuminate\Http\Request;

function createLangRequest(string $locale = ''): Request
function createLangRequest(string|null $locale = null): Request
{
return Request::create('/', 'GET', [], [], [], $locale ? ['HTTP_ACCEPT_LANGUAGE' => $locale] : []);
return Request::create('/', 'GET', [], [], [], $locale !== null ? ['HTTP_ACCEPT_LANGUAGE' => $locale] : []);
}

function createAcceptRequest(string $accept = ''): Request
Expand Down