Skip to content

Commit

Permalink
Merge branch 'main' of github.com:spatie/laravel-translatable
Browse files Browse the repository at this point in the history
  • Loading branch information
freekmurze committed Feb 20, 2025
2 parents aab7dc7 + 87167fd commit 032d85b
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 54 deletions.
16 changes: 8 additions & 8 deletions src/HasTranslations.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function initializeHasTranslations(): void

public static function usingLocale(string $locale): self
{
return (new self())->setLocale($locale);
return (new self)->setLocale($locale);
}

public function useFallbackLocale(): bool
Expand Down Expand Up @@ -99,7 +99,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc
$translation = $callbackReturnValue;
}
} catch (Exception) {
//prevent the fallback to crash
// prevent the fallback to crash
}
}

Expand All @@ -108,7 +108,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc
if ($this->hasGetMutator($key)) {
return $this->mutateAttribute($key, $translation);
}

if ($this->hasAttributeMutator($key)) {
return $this->mutateAttributeMarkedAttribute($key, $translation);
}
Expand All @@ -133,9 +133,9 @@ public function getTranslations(?string $key = null, ?array $allowedLocales = nu
$translatableConfig = app(Translatable::class);

if ($this->isNestedKey($key)) {
[$key, $nestedKey] = explode('.',str_replace('->', '.', $key), 2);
[$key, $nestedKey] = explode('.', str_replace('->', '.', $key), 2);
}

return array_filter(
Arr::get($this->fromJson($this->getAttributeFromArray($key)), $nestedKey ?? null, []),
fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales, $translatableConfig->allowNullForTranslation, $translatableConfig->allowEmptyStringForTranslation),
Expand Down Expand Up @@ -168,12 +168,12 @@ public function setTranslation(string $key, string $locale, $value): self
$value = $this->attributes[$key];
} elseif ($this->hasAttributeSetMutator($mutatorKey)) { // handle new attribute mutator
$this->setAttributeMarkedMutatedAttributeValue($mutatorKey, $value);

$value = $this->attributes[$mutatorKey];
}

$translations[$locale] = $value;

if ($this->isNestedKey($key)) {
unset($this->attributes[$key], $this->attributes[$mutatorKey]);

Expand Down
6 changes: 3 additions & 3 deletions src/TranslatableServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ public function configurePackage(Package $package): void

public function packageRegistered(): void
{
$this->app->singleton(Translatable::class, fn () => new Translatable());
$this->app->singleton(Translatable::class, fn () => new Translatable);
$this->app->bind('translatable', Translatable::class);

Factory::macro('translations', function (string|array $locales, mixed $value) {
return is_array($value)
? array_combine((array)$locales, $value)
: array_fill_keys((array)$locales, $value);
? array_combine((array) $locales, $value)
: array_fill_keys((array) $locales, $value);
});
}
}
2 changes: 1 addition & 1 deletion tests/EventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
beforeEach(function () {
Event::fake();

$this->testModel = new TestModel();
$this->testModel = new TestModel;
});

it('will fire an event when a translation has been set', function () {
Expand Down
1 change: 1 addition & 0 deletions tests/TestSupport/TestModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class TestModel extends Model
protected $table = 'test_models';

protected $guarded = [];

public $timestamps = false;

public $translatable = ['name', 'other_field', 'field_with_mutator'];
Expand Down
1 change: 1 addition & 0 deletions tests/TestSupport/TestModelWithFallbackLocale.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class TestModelWithFallbackLocale extends Model
protected $table = 'test_models';

protected $guarded = [];

public $timestamps = false;

public $translatable = ['name', 'other_field', 'field_with_mutator'];
Expand Down
1 change: 1 addition & 0 deletions tests/TestSupport/TestModelWithoutFallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class TestModelWithoutFallback extends Model
protected $table = 'test_models';

protected $guarded = [];

public $timestamps = false;

public $translatable = ['name', 'other_field', 'field_with_mutator'];
Expand Down
94 changes: 52 additions & 42 deletions tests/TranslatableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Spatie\Translatable\Test\TestSupport\TestModelWithoutFallback;

beforeEach(function () {
$this->testModel = new TestModel();
$this->testModel = new TestModel;
});

it('will return package fallback locale translation when getting an unknown locale', function () {
Expand Down Expand Up @@ -56,21 +56,21 @@
Storage::fake();

Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) {
//something assertable outside the closure
Storage::put("test.txt", "test");
// something assertable outside the closure
Storage::put('test.txt', 'test');
});

$this->testModel->setTranslation('name', 'en', 'testValue_en');
$this->testModel->save();

expect($this->testModel->getTranslationWithFallback('name', 'fr'))->toBe('testValue_en');

Storage::assertExists("test.txt");
Storage::assertExists('test.txt');
});

it('will use callback fallback return value as translation', function () {
Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) {
return "testValue_fallback_callback";
return 'testValue_fallback_callback';
});

$this->testModel->setTranslation('name', 'en', 'testValue_en');
Expand All @@ -94,21 +94,21 @@
Storage::fake();

Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) {
//something assertable outside the closure
Storage::put("test.txt", "test");
// something assertable outside the closure
Storage::put('test.txt', 'test');
});

$this->testModel->setTranslation('name', 'en', 'testValue_en');
$this->testModel->save();

expect($this->testModel->getTranslationWithFallback('name', 'en'))->toBe('testValue_en');

Storage::assertMissing("test.txt");
Storage::assertMissing('test.txt');
});

it('wont fail if callback fallback throw exception', function () {
Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) {
throw new \Exception();
throw new \Exception;
});

$this->testModel->setTranslation('name', 'en', 'testValue_en');
Expand Down Expand Up @@ -375,18 +375,20 @@
});

it('is compatible with accessors on non translatable attributes', function () {
$testModel = new class () extends TestModel {
$testModel = new class extends TestModel
{
public function getOtherFieldAttribute(): string
{
return 'accessorName';
}
};

expect('accessorName')->toEqual((new $testModel())->otherField);
expect('accessorName')->toEqual((new $testModel)->otherField);
});

it('can use accessors on translated attributes', function () {
$testModel = new class () extends TestModel {
$testModel = new class extends TestModel
{
public function getNameAttribute($value): string
{
return "I just accessed {$value}";
Expand All @@ -399,7 +401,8 @@ public function getNameAttribute($value): string
});

it('can be converted to array when using accessors on translated attributes', function () {
$testModel = new class () extends TestModel {
$testModel = new class extends TestModel
{
public function getNameAttribute($value)
{
return "I just accessed {$value}";
Expand All @@ -418,7 +421,8 @@ public function getNameAttribute($value)
});

it('can use mutators on translated attributes', function () {
$testModel = new class () extends TestModel {
$testModel = new class extends TestModel
{
public function setNameAttribute($value)
{
$this->attributes['name'] = "I just mutated {$value}";
Expand Down Expand Up @@ -476,7 +480,8 @@ public function setNameAttribute($value)
});

it('can correctly set a field when a mutator is defined', function () {
$testModel = (new class () extends TestModel {
$testModel = (new class extends TestModel
{
public function setNameAttribute($value)
{
$this->attributes['name'] = "I just mutated {$value}";
Expand All @@ -490,7 +495,8 @@ public function setNameAttribute($value)
});

it('can set multiple translations when a mutator is defined', function () {
$testModel = (new class () extends TestModel {
$testModel = (new class extends TestModel
{
public function setNameAttribute($value)
{
$this->attributes['name'] = "I just mutated {$value}";
Expand Down Expand Up @@ -530,7 +536,8 @@ public function setNameAttribute($value)
});

it('uses the attribute to mutate the translated value', function () {
$testModel = (new class () extends TestModel {
$testModel = (new class extends TestModel
{
public $mutatedValues = [];

protected function name(): Attribute
Expand All @@ -551,10 +558,11 @@ protected function name(): Attribute
});

it('can translate a field based on the translations of another one', function () {
$testModel = (new class () extends TestModel {
$testModel = (new class extends TestModel
{
public function setOtherFieldAttribute($value, $locale = 'en')
{
$this->attributes['other_field'] = $value . ' ' . $this->getTranslation('name', $locale);
$this->attributes['other_field'] = $value.' '.$this->getTranslation('name', $locale);
}
});

Expand All @@ -579,7 +587,8 @@ public function setOtherFieldAttribute($value, $locale = 'en')
});

it('handle null value from database', function () {
$testModel = (new class () extends TestModel {
$testModel = (new class extends TestModel
{
public function setAttributesExternally(array $attributes)
{
$this->attributes = $attributes;
Expand Down Expand Up @@ -820,7 +829,7 @@ public function setAttributesExternally(array $attributes)
it('can disable attribute locale fallback on a per model basis', function () {
config()->set('app.fallback_locale', 'en');

$model = new TestModelWithoutFallback();
$model = new TestModelWithoutFallback;

$model->setTranslation('name', 'en', 'testValue_en');
$model->save();
Expand All @@ -833,7 +842,7 @@ public function setAttributesExternally(array $attributes)
it('can set fallback locale on model', function () {
config()->set('app.fallback_locale', 'en');

$model = new TestModelWithFallbackLocale();
$model = new TestModelWithFallbackLocale;

TestModelWithFallbackLocale::$fallbackLocale = 'fr';

Expand Down Expand Up @@ -929,29 +938,30 @@ public function setAttributesExternally(array $attributes)
});

it('can set and retrieve translations for nested fields', function () {
$testModel = new class () extends TestModel {
$testModel = new class extends TestModel
{
public $translatable = ['nested->field', 'nested->deep->field'];
};

$nestedFieldKey = 'nested->field';
$nestedDeepFieldKey = 'nested->deep->field';

$testModel = $testModel::create([
$nestedFieldKey => ['ar' => 'nestedFieldKey_ar'],
]);

app()->setLocale('nl');
$testModel->$nestedFieldKey = 'nestedFieldKey_nl';
$testModel->setTranslation($nestedFieldKey ,'en', 'nestedFieldKey_en');

$testModel->setTranslation($nestedFieldKey, 'en', 'nestedFieldKey_en');

$testModel->setTranslations($nestedDeepFieldKey, [
'ar'=> 'nestedDeepFieldKey_ar',
'en'=> 'nestedDeepFieldKey_en',
'ar' => 'nestedDeepFieldKey_ar',
'en' => 'nestedDeepFieldKey_en',
]);

$testModel->save();

expect($testModel->getTranslations())
->toEqual([
$nestedFieldKey => [
Expand All @@ -960,31 +970,31 @@ public function setAttributesExternally(array $attributes)
'en' => 'nestedFieldKey_en',
],
$nestedDeepFieldKey => [
'ar'=> 'nestedDeepFieldKey_ar',
'en'=> 'nestedDeepFieldKey_en',
'ar' => 'nestedDeepFieldKey_ar',
'en' => 'nestedDeepFieldKey_en',
],
]);


expect($testModel->getTranslations($nestedDeepFieldKey))
->toEqual([
'ar'=> 'nestedDeepFieldKey_ar',
'en'=> 'nestedDeepFieldKey_en',
]);
'ar' => 'nestedDeepFieldKey_ar',
'en' => 'nestedDeepFieldKey_en',
]);

// fallback en used here while no nl lang in this field
expect($testModel->$nestedDeepFieldKey)
->toEqual('nestedDeepFieldKey_en');

app()->setLocale('ar');
expect($testModel->$nestedFieldKey)->toBe('nestedFieldKey_ar');
expect($testModel->getTranslation($nestedDeepFieldKey, 'en'))->toBe('nestedDeepFieldKey_en');
});

it('uses mutators for setting and getting translated values of nested fields', function () {
$testModel = new class () extends TestModel {
$testModel = new class extends TestModel
{
public $translatable = ['nested->field', 'nested->deep->field'];

public function setNestedFieldAttribute($value)
{
$this->attributes['nested->field'] = strtolower($value);
Expand All @@ -1006,12 +1016,12 @@ protected function nestedDeepField(): Attribute

$nestedFieldKey = 'nested->field';
$nestedDeepFieldKey = 'nested->deep->field';

app()->setLocale('ar');
$testModel->$nestedFieldKey = 'NESTED FIELD AR';
$testModel->$nestedFieldKey = 'NESTED FIELD AR';
$testModel->$nestedDeepFieldKey = 'NESTED DEEP FIELD AR';
$testModel->save();

expect($testModel->$nestedFieldKey)
->toEqual('Nested field ar');

Expand Down

0 comments on commit 032d85b

Please sign in to comment.