Page MenuHomePhorge

D5784.1775203855.diff
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

D5784.1775203855.diff

diff --git a/src/app/Http/Middleware/Locale.php b/src/app/Http/Middleware/Locale.php
--- a/src/app/Http/Middleware/Locale.php
+++ b/src/app/Http/Middleware/Locale.php
@@ -14,8 +14,6 @@
*/
public function handle(Request $request, \Closure $next)
{
- $langDir = resource_path('lang');
- $enabledLanguages = ContentController::locales();
$lang = null;
// setLocale() will modify the app.locale config entry, so any subsequent
@@ -24,30 +22,16 @@
$default = \env('APP_LOCALE', 'en');
// Try to get the language from the cookie
- if (
- ($cookie = $request->cookie('language'))
- && in_array($cookie, $enabledLanguages)
- && ($cookie == $default || file_exists("{$langDir}/{$cookie}"))
- ) {
- $lang = $cookie;
+ $_lang = self::getLanguageCookie($request);
+ if (self::isLocaleAvailable($request, $_lang, $default)) {
+ $lang = $_lang;
}
- // If there's no cookie select try the browser languages
+ // If there's no cookie try the client languages
if (!$lang) {
- $preferences = array_map(
- static function ($lang) {
- return preg_replace('/[^a-z].*$/', '', strtolower($lang));
- },
- $request->getLanguages()
- );
-
- foreach ($preferences as $pref) {
- if (
- !empty($pref)
- && in_array($pref, $enabledLanguages)
- && ($pref == $default || file_exists("{$langDir}/{$pref}"))
- ) {
- $lang = $pref;
+ foreach ($request->getLanguages() as $_lang) {
+ if (self::isLocaleAvailable($request, $_lang, $default)) {
+ $lang = $_lang;
break;
}
}
@@ -67,4 +51,43 @@
return $next($request);
}
+
+ protected static function getLanguageCookie(Request $request): ?string
+ {
+ // Note: $request->cookie() works only with Laravel cookies that are encrypted,
+ // that's why we check the header manually
+ if (preg_match('/(^|; )language=([a-zA-Z-_]+)/', (string) $request->header('cookie'), $matches)) {
+ return $matches[2];
+ }
+
+ return null;
+ }
+
+ /**
+ * Check if the specified language is available
+ */
+ protected static function isLocaleAvailable(Request $request, &$lang, $default): bool
+ {
+ if (!is_string($lang) || $lang === '') {
+ return false;
+ }
+
+ $lang = preg_replace('/[^a-z].*$/', '', strtolower($lang));
+
+ // Always accept the default language without any additional checks
+ if ($lang == $default) {
+ return true;
+ }
+
+ $langDir = resource_path('lang');
+
+ // Allow any existing language for API requests
+ if (str_starts_with($request->path(), 'api/')) {
+ return file_exists("{$langDir}/{$lang}");
+ }
+
+ // Allow languages enabled for UI
+ $enabledLanguages = ContentController::locales();
+ return in_array($lang, $enabledLanguages) && file_exists("{$langDir}/{$lang}");
+ }
}
diff --git a/src/tests/Feature/Middleware/LocaleTest.php b/src/tests/Feature/Middleware/LocaleTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Feature/Middleware/LocaleTest.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace Tests\Feature\Middleware;
+
+use Tests\TestCase;
+
+class LocaleTest extends TestCase
+{
+ /**
+ * Test setting locale using Cookie
+ */
+ public function testLocaleFromCookie(): void
+ {
+ $user = $this->getTestUser('john@kolab.org');
+
+ $headers = ['Accept-Language' => '*'];
+
+ // Test with no headers (expect default locale)
+ $response = $this->actingAs($user)->withHeaders($headers)->get('api/auth/location');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale(\config('app.locale')));
+
+ // Test with 'language' cookie - invalid language
+ $headers['Cookie'] = 'language=unk';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('api/auth/location');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale(\config('app.locale')));
+
+ // Test with 'language' cookie - valid API language
+ $headers['Cookie'] = 'language=fi';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('api/auth/location');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale('fi'));
+
+ // Test with 'language' cookie - invalid UI language
+ $headers['Cookie'] = 'language=fi';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('dashboard');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale(\config('app.locale')));
+
+ // Test with 'language' cookie - valid UI language
+ $headers['Cookie'] = 'language=fr';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('dashboard');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale('fr'));
+ }
+
+ /**
+ * Test setting locale using Accept-Language
+ */
+ public function testLocaleFromAcceptLanguage(): void
+ {
+ $user = $this->getTestUser('john@kolab.org');
+
+ $headers = ['Accept-Language' => '*'];
+
+ // Test with no headers (expect default locale)
+ $response = $this->actingAs($user)->withHeaders($headers)->get('api/auth/location');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale(\config('app.locale')));
+
+ // Test with 'language' cookie - invalid language
+ $headers['Accept-Language'] = 'unk;q=0.9';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('api/auth/location');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale(\config('app.locale')));
+
+ // Test with 'language' cookie - valid API language
+ $headers['Accept-Language'] = 'fi;q=0.9';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('api/auth/location');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale('fi'));
+
+ // Test with 'language' cookie - invalid UI language
+ $headers['Accept-Language'] = 'fi;q=0.9';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('dashboard');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale(\config('app.locale')));
+
+ // Test with 'language' cookie - valid UI language
+ $headers['Accept-Language'] = 'fi;q=0.9, fr;q=0.8';
+ $response = $this->actingAs($user)->withHeaders($headers)->get('dashboard');
+ $response->assertStatus(200);
+
+ $this->assertTrue(\app()->isLocale('fr'));
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 3, 8:10 AM (18 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18806277
Default Alt Text
D5784.1775203855.diff (6 KB)

Event Timeline