From b121520ed6de455ca8b3908c4b160b8f5775299a Mon Sep 17 00:00:00 2001 From: boban Date: Sat, 16 May 2026 01:27:10 +0200 Subject: [PATCH] fix(i18n): include namespace in cache key/query, clean up singleton, test isolation Co-Authored-By: Claude Sonnet 4.6 --- .../Providers/DatabaseTranslationLoader.php | 5 +++-- app/Providers/AppServiceProvider.php | 11 +++++------ tests/Feature/Translation/TranslationServiceTest.php | 4 ++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/Domains/Translation/Providers/DatabaseTranslationLoader.php b/app/Domains/Translation/Providers/DatabaseTranslationLoader.php index 66ac048..8fe700c 100644 --- a/app/Domains/Translation/Providers/DatabaseTranslationLoader.php +++ b/app/Domains/Translation/Providers/DatabaseTranslationLoader.php @@ -10,7 +10,8 @@ class DatabaseTranslationLoader implements Loader { public function load($locale, $group, $namespace = null): array { - $cacheKey = "lang:{$locale}:{$group}"; + $ns = $namespace ?? '*'; + $cacheKey = "lang:{$ns}:{$locale}:{$group}"; $cached = Redis::hGetAll($cacheKey); if (! empty($cached)) { @@ -19,6 +20,7 @@ class DatabaseTranslationLoader implements Loader $translations = Translation::where('locale', $locale) ->where('group', $group) + ->where('namespace', $namespace ?? '*') ->pluck('value', 'key') ->toArray(); @@ -31,7 +33,6 @@ class DatabaseTranslationLoader implements Loader } public function addNamespace($namespace, $hint): void {} - public function addPath($path): void {} public function addJsonPath($path): void {} public function namespaces(): array diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index fe8fc04..f14221b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -15,18 +15,17 @@ class AppServiceProvider extends ServiceProvider */ public function register(): void { - $this->app->singleton('translation.loader', function ($app) { - return new DatabaseTranslationLoader; - }); + $this->app->singleton('translation.loader', fn() => new DatabaseTranslationLoader); // TranslationServiceProvider is deferred and re-binds translation.loader // when it resolves. We extend 'translator' to swap in our DB loader after // the translator instance is created. $this->app->extend('translator', function ($translator, $app) { $loader = new DatabaseTranslationLoader; - $reflection = new \ReflectionProperty($translator, 'loader'); - $reflection->setAccessible(true); - $reflection->setValue($translator, $loader); + // Keep the singleton up-to-date so app('translation.loader') returns ours. + $app->instance('translation.loader', $loader); + $prop = new \ReflectionProperty($translator, 'loader'); + $prop->setValue($translator, $loader); return $translator; }); diff --git a/tests/Feature/Translation/TranslationServiceTest.php b/tests/Feature/Translation/TranslationServiceTest.php index a853b90..125d1c3 100644 --- a/tests/Feature/Translation/TranslationServiceTest.php +++ b/tests/Feature/Translation/TranslationServiceTest.php @@ -5,10 +5,14 @@ use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Redis; beforeEach(function () { + Redis::del('lang:*:de:auth'); Redis::del('lang:de:auth'); + app('translator')->setLoaded([]); }); afterEach(function () { + app('translator')->setLoaded([]); + Redis::del('lang:*:de:auth'); Redis::del('lang:de:auth'); });