From 409db9c7bf2e5904284032448068988b722e1014 Mon Sep 17 00:00:00 2001 From: Konstantinos Arvanitakis Date: Thu, 27 Aug 2026 01:28:37 +0300 Subject: [PATCH] Fix: Correcting Language Line fallback resolver --- docs/localization.md | 18 +++++++++++ src/Localization/Models/LanguageLine.php | 32 +++++++++++++++++++ src/Providers/LocalizationServiceProvider.php | 11 +++++++ 3 files changed, 61 insertions(+) create mode 100644 src/Localization/Models/LanguageLine.php diff --git a/docs/localization.md b/docs/localization.md index 4544a5c..1a1fd5a 100644 --- a/docs/localization.md +++ b/docs/localization.md @@ -178,6 +178,24 @@ namespaced groups so nothing collides. `__()` resolves the translation for whate `App::getLocale()` currently is, which `LocaleMiddleware` already sets per-request (see "Behavior" above) — no extra wiring needed between the two systems. +### Fallback locale follows the store's default language, not `config('app.fallback_locale')` + +`spatie/laravel-translation-loader`'s stock `LanguageLine::getTranslation()` falls back to +`config('app.fallback_locale')` — a static `.env` value — when a key has no text for the current +locale. That's a second, disconnected "default language" concept: an admin changing the default +language via the Filament **Languages** resource has no effect on it, so an untranslated label +could silently fall back to the wrong language. + +`Modules\Core\Localization\Models\LanguageLine` overrides `getTranslation()` to fall back to +`LanguageCache::defaultLocale()` instead — the same `languages.default` flag `LocaleMiddleware` +already treats as the single source of truth. It's swapped in via +`config('translation-loader.model')` (the package's own documented extension point for +"any model that extends `LanguageLine`"), set in `LocalizationServiceProvider::register()` so it +wins regardless of provider boot order (Laravel's `mergeConfigFrom()` only fills in config keys +not already set, so an explicit `register()`-time set always beats the package's own default). +No consuming app configuration needed — this is automatic once `LocalizationServiceProvider` is +registered. + ### Seeding A starter set of common e-shop labels (`nav.*`, `cart.*`, `product.*`, `auth.*`, `search.*`, diff --git a/src/Localization/Models/LanguageLine.php b/src/Localization/Models/LanguageLine.php new file mode 100644 index 0000000..17f4766 --- /dev/null +++ b/src/Localization/Models/LanguageLine.php @@ -0,0 +1,32 @@ +text[$locale])) { + return $this->text[$locale]; + } + + $fallback = app(LanguageCache::class)->defaultLocale(); + + return $fallback !== null ? ($this->text[$fallback] ?? null) : null; + } +} diff --git a/src/Providers/LocalizationServiceProvider.php b/src/Providers/LocalizationServiceProvider.php index c78bd96..112d481 100644 --- a/src/Providers/LocalizationServiceProvider.php +++ b/src/Providers/LocalizationServiceProvider.php @@ -16,10 +16,21 @@ use Modules\Core\Localization\Listeners\FlushTranslationCache; use Modules\Core\Localization\Listeners\LogTranslationActivity; use Modules\Core\Localization\Listeners\MigrateTranslationsForRenamedLanguage; use Modules\Core\Localization\Middleware\LocaleMiddleware; +use Modules\Core\Localization\Models\LanguageLine; use Modules\Core\Localization\Observers\LanguageCacheObserver; class LocalizationServiceProvider extends ServiceProvider { + public function register(): void + { + // Must run before Spatie\TranslationLoader\TranslationServiceProvider's + // register() merges its own config defaults - mergeConfigFrom() only fills + // in keys not already set, so setting this here (regardless of provider + // boot order) makes it win over the package's default + // Spatie\TranslationLoader\LanguageLine::class. + config(['translation-loader.model' => LanguageLine::class]); + } + public function boot(): void { $this->app['router']->aliasMiddleware('locale', LocaleMiddleware::class);