diff --git a/src/Translatable/Locales.php b/src/Translatable/Locales.php index 9b098eec..bb32ea94 100644 --- a/src/Translatable/Locales.php +++ b/src/Translatable/Locales.php @@ -95,6 +95,7 @@ public function load(): void foreach ($localesConfig as $key => $locale) { if (is_string($key) && is_array($locale)) { $this->locales[$key] = $key; + foreach ($locale as $country) { $countryLocale = $this->getCountryLocale($key, $country); $this->locales[$countryLocale] = $countryLocale; diff --git a/src/Translatable/Translatable.php b/src/Translatable/Translatable.php index 4bb99932..c5c9fc06 100644 --- a/src/Translatable/Translatable.php +++ b/src/Translatable/Translatable.php @@ -177,10 +177,12 @@ public function getTranslation(?string $locale = null, bool $withFallback = null if ($translation = $this->getTranslationByLocaleKey($locale)) { return $translation; } + if ($withFallback && $fallbackLocale) { if ($translation = $this->getTranslationByLocaleKey($fallbackLocale)) { return $translation; } + if ( is_string($configFallbackLocale) && $fallbackLocale !== $configFallbackLocale @@ -190,6 +192,16 @@ public function getTranslation(?string $locale = null, bool $withFallback = null } } + if ($withFallback && $configFallbackLocale === null) { + $configuredLocales = $this->getLocalesHelper()->all(); + + foreach ($configuredLocales as $configuredLocale) { + if ($translation = $this->getTranslationByLocaleKey($configuredLocale)) { + return $translation; + } + } + } + return null; } diff --git a/src/config/translatable.php b/src/config/translatable.php index 87f898b4..6864e284 100644 --- a/src/config/translatable.php +++ b/src/config/translatable.php @@ -78,6 +78,10 @@ | A fallback locale is the locale being used to return a translation | when the requested translation is not existing. To disable it | set it to false. + | If set to null it will loop through all configured locales until + | one existing is found or end of list reached. The locales are looped + | from top to bottom and for country based locales the simple one + | is used first. So "es" will be checked before "es_MX". | */ 'fallback_locale' => 'en', diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 9e2e8ec0..9eb5848b 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1,5 +1,6 @@ assertEquals('id:my city', $city->getTranslation('id', false)->name); $this->assertEquals('en:my city', $city->getTranslation('en', false)->name); } + + public function test_it_returns_first_existing_translation_as_fallback() + { + /** @var Locales $helper */ + $helper = $this->app->make(Locales::class); + + $this->app->make('config')->set('translatable.locales', [ + 'xyz', + 'en', + 'de' => [ + 'DE', + 'AT', + ], + 'fr', + 'el', + ]); + $this->app->make('config')->set('translatable.fallback_locale', null); + $this->app->make('config')->set('translatable.use_fallback', true); + $this->app->setLocale('xyz'); + $helper->load(); + + CountryTranslation::create([ + 'country_id' => 1, + 'locale' => $helper->getCountryLocale('de', 'DE'), + 'name' => 'Griechenland', + ]); + + /** @var Country $country */ + $country = Country::find(1); + $this->assertNull($country->getTranslation(null, false)); + + // returns first existing locale + $translation = $country->getTranslation(); + $this->assertInstanceOf(CountryTranslation::class, $translation); + $this->assertEquals('en', $translation->locale); + + // still returns simple locale for country based locale + $translation = $country->getTranslation($helper->getCountryLocale('de', 'AT')); + $this->assertInstanceOf(CountryTranslation::class, $translation); + $this->assertEquals('de', $translation->locale); + + $this->app->make('config')->set('translatable.locales', [ + 'xyz', + 'de' => [ + 'DE', + 'AT', + ], + 'en', + 'fr', + 'el', + ]); + $helper->load(); + + // returns simple locale before country based locale + $translation = $country->getTranslation(); + $this->assertInstanceOf(CountryTranslation::class, $translation); + $this->assertEquals('de', $translation->locale); + + $country->translations()->where('locale', 'de')->delete(); + $country->unsetRelation('translations'); + + // returns country based locale before next simple one + $translation = $country->getTranslation(); + $this->assertInstanceOf(CountryTranslation::class, $translation); + $this->assertEquals($helper->getCountryLocale('de', 'DE'), $translation->locale); + } } diff --git a/tests/models/CountryTranslation.php b/tests/models/CountryTranslation.php index 3ede2581..55315657 100644 --- a/tests/models/CountryTranslation.php +++ b/tests/models/CountryTranslation.php @@ -8,5 +8,9 @@ class CountryTranslation extends Eloquent { public $timestamps = false; - protected $fillable = ['name']; + protected $fillable = [ + 'country_id', + 'locale', + 'name', + ]; }