From 560901d17c4fb9878719609836db98a47bf54e33 Mon Sep 17 00:00:00 2001 From: slovenianGooner Date: Wed, 5 Jun 2019 09:46:30 +0200 Subject: [PATCH 001/229] Allow false or true values in translations (#161) Applicable when trying to set active on one translation, but inactive on another. --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index a17ec17..0647334 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -65,7 +65,7 @@ public function getTranslations(string $key = null) : array $this->guardAgainstNonTranslatableAttribute($key); return array_filter(json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], function ($value) { - return $value !== null && $value !== false && $value !== ''; + return $value !== null && $value !== ''; }); } From c0c385367e353898ce635737707fa4abc6b15027 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Wed, 5 Jun 2019 09:47:10 +0200 Subject: [PATCH 002/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec816be..09fda87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.1.2 - 2019-06-06 + +- allow false and true values in translations + ## 4.1.1 - 2019-02-27 - fix service provider error From 9f451275a932757afad85e8449073aee38294e8f Mon Sep 17 00:00:00 2001 From: Gert de Pagter Date: Fri, 14 Jun 2019 16:48:09 +0200 Subject: [PATCH 003/229] Update badge alt text (#163) If the bade doesn't load, this will still allow users to see what the license is. It is also beneficial for users who use screen readers. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9689ee..9b61b03 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # A trait to make Eloquent models translatable [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) +[![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) [![Build Status](https://img.shields.io/travis/spatie/laravel-translatable/master.svg?style=flat-square)](https://travis-ci.org/spatie/laravel-translatable) [![Quality Score](https://img.shields.io/scrutinizer/g/spatie/laravel-translatable.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie/laravel-translatable) [![StyleCI](https://styleci.io/repos/55690447/shield?branch=master)](https://styleci.io/repos/55690447) From b3d549d67cbbed4db8b4b3c8459e6b4c0eea59a6 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Fri, 12 Jul 2019 18:11:38 +0200 Subject: [PATCH 004/229] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..2bec409 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +patreon: spatie From 2aa9f4faa4d539bef9d9990ecdf5a656ebe8d157 Mon Sep 17 00:00:00 2001 From: Simon Ellensohn Date: Tue, 16 Jul 2019 22:45:20 +0200 Subject: [PATCH 005/229] Only include required illuminate dependencies (#165) * Only include required illuminate dependencies * Access config class statically * Ignore phpunit cache --- .gitignore | 1 + composer.json | 3 ++- src/HasTranslations.php | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index f02a2f8..b6285d6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build composer.lock docs vendor +.phpunit.result.cache diff --git a/composer.json b/composer.json index d21e632..722b4fb 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ ], "require": { "php" : "^7.2", - "laravel/framework": "~5.8.0" + "illuminate/database": "~5.8.0", + "illuminate/support": "~5.8.0" }, "require-dev": { "phpunit/phpunit": "^8.0", diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 0647334..c90b040 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -3,6 +3,7 @@ namespace Spatie\Translatable; use Illuminate\Support\Str; +use Illuminate\Support\Facades\Config; use Spatie\Translatable\Events\TranslationHasBeenSet; use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; @@ -166,7 +167,7 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - if (! is_null($fallbackLocale = config('app.fallback_locale'))) { + if (! is_null($fallbackLocale = Config::get('app.fallback_locale'))) { return $fallbackLocale; } @@ -175,7 +176,7 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac protected function getLocale() : string { - return config('app.locale'); + return Config::get('app.locale'); } public function getTranslatableAttributes() : array From 153027c574a430a81f31e8384a3a19baea5885e8 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Tue, 16 Jul 2019 22:46:04 +0200 Subject: [PATCH 006/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09fda87..3cb55ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.1.3 - 2019-06-16 + +- improve dependencies + ## 4.1.2 - 2019-06-06 - allow false and true values in translations From 5913ec555db8457652db04263b542b85de962172 Mon Sep 17 00:00:00 2001 From: Roy Duineveld Date: Thu, 29 Aug 2019 08:18:19 +0200 Subject: [PATCH 007/229] Re-added the translatable.fallback_locale config (#171) * Re-added the translatable.fallback_locale config * Changelog --- CHANGELOG.md | 4 ++++ README.md | 12 ++++++++++++ composer.json | 7 +++++++ config/translatable.php | 9 +++++++++ src/HasTranslations.php | 4 ++++ src/TranslatableServiceProvider.php | 20 ++++++++++++++++++++ tests/TestCase.php | 6 ++++++ tests/TranslatableTest.php | 16 +++++++++++++++- 8 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 config/translatable.php create mode 100644 src/TranslatableServiceProvider.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cb55ef..f47d384 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.1.4 - 2019-08-28 + +- re-added the `translatable.fallback_local` config which overrule `app.fallback_local` (see https://github.com/spatie/laravel-translatable/issues/170) + ## 4.1.3 - 2019-06-16 - improve dependencies diff --git a/README.md b/README.md index 9b61b03..ca84905 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,18 @@ You can install the package via composer: composer require spatie/laravel-translatable ``` +If you want to have another fallback_locale then the app fallback locale (see `config/app.php`), you could publish the config file: +``` +php artisan vendor:publish --provider="Spatie\Translatable\TranslatableServiceProvider" +``` + +This is the contents of the published file: +```php +return [ + 'fallback_locale' => 'en', +]; +``` + ## Making a model translatable The required steps to make a model translatable are: diff --git a/composer.json b/composer.json index 722b4fb..7f9d614 100644 --- a/composer.json +++ b/composer.json @@ -56,5 +56,12 @@ }, "config": { "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "Spatie\\Translatable\\TranslatableServiceProvider" + ] + } } } diff --git a/config/translatable.php b/config/translatable.php new file mode 100644 index 0000000..699bea1 --- /dev/null +++ b/config/translatable.php @@ -0,0 +1,9 @@ + 'en', +]; diff --git a/src/HasTranslations.php b/src/HasTranslations.php index c90b040..5cd0ed7 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -167,6 +167,10 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } + if (! is_null($fallbackLocale = Config::get('translatable.fallback_locale'))) { + return $fallbackLocale; + } + if (! is_null($fallbackLocale = Config::get('app.fallback_locale'))) { return $fallbackLocale; } diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php new file mode 100644 index 0000000..2efff53 --- /dev/null +++ b/src/TranslatableServiceProvider.php @@ -0,0 +1,20 @@ +publishes([ + __DIR__.'/../config/translatable.php' => config_path('translatable.php'), + ], 'config'); + } + + public function register() + { + $this->mergeConfigFrom(__DIR__.'/../config/translatable.php', 'translatable'); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 54a4d28..6d9adea 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Orchestra\Testbench\TestCase as Orchestra; +use Spatie\Translatable\TranslatableServiceProvider; abstract class TestCase extends Orchestra { @@ -15,6 +16,11 @@ public function setUp(): void $this->setUpDatabase(); } + protected function getPackageProviders($app) + { + return [TranslatableServiceProvider::class]; + } + protected function setUpDatabase() { Schema::create('test_models', function (Blueprint $table) { diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 885282a..ce4935d 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -17,7 +17,19 @@ public function setUp(): void } /** @test */ - public function it_will_return_fallback_locale_translation_when_getting_an_unknown_locale() + public function it_will_return_package_fallback_locale_translation_when_getting_an_unknown_locale() + { + $this->app['config']->set('app.fallback_locale', 'nl'); + $this->app['config']->set('translatable.fallback_locale', 'en'); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); + } + + /** @test */ + public function it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale() { $this->app['config']->set('app.fallback_locale', 'en'); @@ -53,6 +65,7 @@ public function it_will_return_fallback_locale_translation_when_getting_an_unkno public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_not_set() { $this->app['config']->set('app.fallback_locale', ''); + $this->app['config']->set('translatable.fallback_locale', ''); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -64,6 +77,7 @@ public function it_will_return_an_empty_string_when_getting_an_unknown_locale_an public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_empty() { $this->app['config']->set('app.fallback_locale', ''); + $this->app['config']->set('translatable.fallback_locale', ''); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); From 3a68f11783b06e9738bdc85e40d213149b38bbdb Mon Sep 17 00:00:00 2001 From: Nemrut Creative Studio <46459858+nemrutco@users.noreply.github.com> Date: Wed, 4 Sep 2019 15:09:15 +0800 Subject: [PATCH 008/229] Version support for Laravel 6.0 (#173) --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 7f9d614..d44501a 100644 --- a/composer.json +++ b/composer.json @@ -33,8 +33,8 @@ ], "require": { "php" : "^7.2", - "illuminate/database": "~5.8.0", - "illuminate/support": "~5.8.0" + "illuminate/database": "~5.8.0|^6.0", + "illuminate/support": "~5.8.0|^6.0" }, "require-dev": { "phpunit/phpunit": "^8.0", From 734bd735dc41cf745c3c6f3fb32b8364c918fe34 Mon Sep 17 00:00:00 2001 From: freek Date: Wed, 4 Sep 2019 09:42:04 +0200 Subject: [PATCH 009/229] make compatible with Laravel 6 --- .travis.yml | 45 ++++++++++++++++++++++++++++++++------------- CHANGELOG.md | 4 ++++ composer.json | 2 +- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index bd1d94e..ce6530a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,39 @@ -language: php +cache: + directories: + - $HOME/.composer/cache -php: - - 7.2 - - 7.3 +language: php env: - matrix: - - COMPOSER_FLAGS="--prefer-lowest" - - COMPOSER_FLAGS="" + global: + - COVERAGE=0 + +matrix: + include: + - php: 7.2 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.2 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' + fast_finish: true before_script: - - travis_retry composer self-update - - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source + - composer config discard-changes true -script: - - phpunit --coverage-text --coverage-clover=coverage.clover +before_install: + - travis_retry composer self-update + - travis_retry composer require "laravel/framework:${LARAVEL}" "orchestra/testbench:${TESTBENCH}" --no-interaction --no-update -after_script: - - php vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover +install: + - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction --no-suggest diff --git a/CHANGELOG.md b/CHANGELOG.md index f47d384..2b95d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.2.0 - 2019-09-04 + +- make compatible with Laravel 6 + ## 4.1.4 - 2019-08-28 - re-added the `translatable.fallback_local` config which overrule `app.fallback_local` (see https://github.com/spatie/laravel-translatable/issues/170) diff --git a/composer.json b/composer.json index d44501a..2116e9a 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ }, "require-dev": { "phpunit/phpunit": "^8.0", - "orchestra/testbench": "~3.8.0", + "orchestra/testbench": "~3.8.0|^4.0", "mockery/mockery": "^1.0" }, "autoload": { From 7976aa03d1383d599d9a2da80bd679b080b192e0 Mon Sep 17 00:00:00 2001 From: Briareos17 Date: Thu, 3 Oct 2019 14:04:26 +0300 Subject: [PATCH 010/229] add third param to translate method (#177) --- src/HasTranslations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 5cd0ed7..47eaf9f 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -30,9 +30,9 @@ public function setAttribute($key, $value) return $this->setTranslation($key, $this->getLocale(), $value); } - public function translate(string $key, string $locale = ''): string + public function translate(string $key, string $locale = '', bool $useFallbackLocale = true): string { - return $this->getTranslation($key, $locale); + return $this->getTranslation($key, $locale, $useFallbackLocale); } public function getTranslation(string $key, string $locale, bool $useFallbackLocale = true) From 3a07be9e1e3cc9566c6d7274b613552d5cbf4b1a Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 3 Oct 2019 13:05:01 +0200 Subject: [PATCH 011/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b95d1e..3ba7f7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.2.1 - 2019-10-03 + +- add third param to translate method (#177) + ## 4.2.0 - 2019-09-04 - make compatible with Laravel 6 From 5bc3501dcbcd1d6ea22bce368f0791bc8c06fab7 Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 20 Jan 2020 08:52:04 +0100 Subject: [PATCH 012/229] wip --- .github/workflows/run-tests.yml | 46 +++++++++++++++++++++++++++++++++ .travis.yml | 39 ---------------------------- README.md | 2 +- 3 files changed, 47 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/run-tests.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..86c131e --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,46 @@ +name: run-tests + +on: [push, pull_request] + +jobs: + test: + + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + php: [7.4] + laravel: [5.8.*, 6.*] + dependency-version: [prefer-lowest, prefer-stable] + include: + - laravel: 6.* + testbench: 4.* + - laravel: 5.8.* + testbench: 3.8.* + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} + + steps: + - name: Checkout code + uses: actions/checkout@v1 + + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ~/.composer/cache/files + key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} + + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick + coverage: none + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest + + - name: Execute tests + run: vendor/bin/phpunit diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ce6530a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -cache: - directories: - - $HOME/.composer/cache - -language: php - -env: - global: - - COVERAGE=0 - -matrix: - include: - - php: 7.2 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.2 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.3 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.3 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.2 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.2 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.3 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.3 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' - fast_finish: true - -before_script: - - composer config discard-changes true - -before_install: - - travis_retry composer self-update - - travis_retry composer require "laravel/framework:${LARAVEL}" "orchestra/testbench:${TESTBENCH}" --no-interaction --no-update - -install: - - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction --no-suggest diff --git a/README.md b/README.md index ca84905..31b8040 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Build Status](https://img.shields.io/travis/spatie/laravel-translatable/master.svg?style=flat-square)](https://travis-ci.org/spatie/laravel-translatable) +![GitHub Workflow Status](https://img.shields.io/github/workflow/status/spatie/laravel-translatable/run-tests?label=tests) [![Quality Score](https://img.shields.io/scrutinizer/g/spatie/laravel-translatable.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie/laravel-translatable) [![StyleCI](https://styleci.io/repos/55690447/shield?branch=master)](https://styleci.io/repos/55690447) [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) From bc4b85efb56e997118095790d2c4b3948524ff30 Mon Sep 17 00:00:00 2001 From: Moshe Revah Date: Mon, 20 Jan 2020 09:52:25 +0200 Subject: [PATCH 013/229] Support HasAttributes, not Model (#186) * Update AttributeIsNotTranslatable.php * Update TranslationHasBeenSet.php * Removed unused import * Removed unused import --- src/Events/TranslationHasBeenSet.php | 4 +--- src/Exceptions/AttributeIsNotTranslatable.php | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Events/TranslationHasBeenSet.php b/src/Events/TranslationHasBeenSet.php index 5dfaf50..a3ad310 100644 --- a/src/Events/TranslationHasBeenSet.php +++ b/src/Events/TranslationHasBeenSet.php @@ -2,8 +2,6 @@ namespace Spatie\Translatable\Events; -use Illuminate\Database\Eloquent\Model; - class TranslationHasBeenSet { /** @var \Spatie\Translatable\Translatable */ @@ -18,7 +16,7 @@ class TranslationHasBeenSet public $oldValue; public $newValue; - public function __construct(Model $model, string $key, string $locale, $oldValue, $newValue) + public function __construct($model, string $key, string $locale, $oldValue, $newValue) { $this->model = $model; diff --git a/src/Exceptions/AttributeIsNotTranslatable.php b/src/Exceptions/AttributeIsNotTranslatable.php index dcfc5ca..431dfb6 100644 --- a/src/Exceptions/AttributeIsNotTranslatable.php +++ b/src/Exceptions/AttributeIsNotTranslatable.php @@ -3,11 +3,10 @@ namespace Spatie\Translatable\Exceptions; use Exception; -use Illuminate\Database\Eloquent\Model; class AttributeIsNotTranslatable extends Exception { - public static function make(string $key, Model $model) + public static function make(string $key, $model) { $translatableAttributes = implode(', ', $model->getTranslatableAttributes()); From 71a8ba458dabd8bbe417fa65fd21468175ec22cb Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 20 Jan 2020 08:53:37 +0100 Subject: [PATCH 014/229] wip --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ba7f7a..1a9295d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.2.2 - 2019-01-20 + +- open up for non-model objects (#186) + ## 4.2.1 - 2019-10-03 - add third param to translate method (#177) From 117392f7ead22c19ebbb8f3ad0e051c13a57aea3 Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 20 Jan 2020 08:56:08 +0100 Subject: [PATCH 015/229] wip --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2116e9a..9d1eca4 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "require-dev": { "phpunit/phpunit": "^8.0", "orchestra/testbench": "~3.8.0|^4.0", - "mockery/mockery": "^1.0" + "mockery/mockery": "^1.3" }, "autoload": { "psr-4": { From f6d4dfa3f2b3cf1e6f282b1af23fabed39122baf Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 20 Jan 2020 08:57:30 +0100 Subject: [PATCH 016/229] wip --- .github/workflows/run-tests.yml | 92 ++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 86c131e..2939858 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -3,44 +3,54 @@ name: run-tests on: [push, pull_request] jobs: - test: - - runs-on: ubuntu-latest - strategy: - fail-fast: true - matrix: - php: [7.4] - laravel: [5.8.*, 6.*] - dependency-version: [prefer-lowest, prefer-stable] - include: - - laravel: 6.* - testbench: 4.* - - laravel: 5.8.* - testbench: 3.8.* - - name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - - steps: - - name: Checkout code - uses: actions/checkout@v1 - - - name: Cache dependencies - uses: actions/cache@v1 - with: - path: ~/.composer/cache/files - key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} - - - name: Setup PHP - uses: shivammathur/setup-php@v1 - with: - php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick - coverage: none - - - name: Install dependencies - run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update - composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest - - - name: Execute tests - run: vendor/bin/phpunit + test: + + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + php: [7.4] + laravel: [5.8.*, 6.*] + dependency-version: [prefer-lowest, prefer-stable] + include: + - laravel: 6.* + testbench: 4.* + - laravel: 5.8.* + testbench: 3.8.* + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} + + steps: + - name: Checkout code + uses: actions/checkout@v1 + + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ~/.composer/cache/files + key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} + + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick + coverage: none + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest + + - name: Execute tests + run: vendor/bin/phpunit + + - name: Send Slack notification + uses: 8398a7/action-slack@v2 + if: failure() + with: + status: ${{ job.status }} + author_name: ${{ github.actor }} + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 52fd596756ae4595e958f3e5ce3674510f7bdec7 Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 20 Jan 2020 08:59:27 +0100 Subject: [PATCH 017/229] wip --- .github/workflows/run-tests.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 2939858..ef08b14 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -46,11 +46,11 @@ jobs: run: vendor/bin/phpunit - name: Send Slack notification - uses: 8398a7/action-slack@v2 - if: failure() - with: - status: ${{ job.status }} - author_name: ${{ github.actor }} - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: 8398a7/action-slack@v2 + if: failure() + with: + status: ${{ job.status }} + author_name: ${{ github.actor }} + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 0b8de146195d815d84fcf5b08ea5674839f1a2a0 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 20 Jan 2020 08:59:54 +0100 Subject: [PATCH 018/229] Apply fixes from StyleCI (#191) --- src/HasTranslations.php | 16 ++++++++-------- tests/TestCase.php | 2 +- tests/TranslatableTest.php | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 47eaf9f..c53f47a 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -2,8 +2,8 @@ namespace Spatie\Translatable; -use Illuminate\Support\Str; use Illuminate\Support\Facades\Config; +use Illuminate\Support\Str; use Spatie\Translatable\Events\TranslationHasBeenSet; use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; @@ -60,7 +60,7 @@ public function getTranslationWithoutFallback(string $key, string $locale) return $this->getTranslation($key, $locale, false); } - public function getTranslations(string $key = null) : array + public function getTranslations(string $key = null): array { if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); @@ -133,12 +133,12 @@ public function forgetAllTranslations(string $locale): self return $this; } - public function getTranslatedLocales(string $key) : array + public function getTranslatedLocales(string $key): array { return array_keys($this->getTranslations($key)); } - public function isTranslatableAttribute(string $key) : bool + public function isTranslatableAttribute(string $key): bool { return in_array($key, $this->getTranslatableAttributes()); } @@ -157,7 +157,7 @@ protected function guardAgainstNonTranslatableAttribute(string $key) } } - protected function normalizeLocale(string $key, string $locale, bool $useFallbackLocale) : string + protected function normalizeLocale(string $key, string $locale, bool $useFallbackLocale): string { if (in_array($locale, $this->getTranslatedLocales($key))) { return $locale; @@ -178,12 +178,12 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function getLocale() : string + protected function getLocale(): string { return Config::get('app.locale'); } - public function getTranslatableAttributes() : array + public function getTranslatableAttributes(): array { return is_array($this->translatable) ? $this->translatable @@ -199,7 +199,7 @@ public function getTranslationsAttribute(): array ->toArray(); } - public function getCasts() : array + public function getCasts(): array { return array_merge( parent::getCasts(), diff --git a/tests/TestCase.php b/tests/TestCase.php index 6d9adea..e948cd7 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,8 +2,8 @@ namespace Spatie\Translatable\Test; -use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; use Orchestra\Testbench\TestCase as Orchestra; use Spatie\Translatable\TranslatableServiceProvider; diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index ce4935d..9c0ebcc 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -234,7 +234,7 @@ public function it_will_throw_an_exception_when_trying_to_translate_an_untransla public function it_is_compatible_with_accessors_on_non_translatable_attributes() { $testModel = new class() extends TestModel { - public function getOtherFieldAttribute() : string + public function getOtherFieldAttribute(): string { return 'accessorName'; } @@ -247,7 +247,7 @@ public function getOtherFieldAttribute() : string public function it_can_use_accessors_on_translated_attributes() { $testModel = new class() extends TestModel { - public function getNameAttribute($value) : string + public function getNameAttribute($value): string { return "I just accessed {$value}"; } @@ -426,8 +426,8 @@ public function it_can_get_all_translations() $this->testModel->save(); $this->assertEquals([ - 'name' => ['nl' => 'hallo', 'en' => 'hello'], - 'other_field' => [], + 'name' => ['nl' => 'hallo', 'en' => 'hello'], + 'other_field' => [], ], $this->testModel->translations); } From 45375a7d61303f8455a1169806ce7e2d71092179 Mon Sep 17 00:00:00 2001 From: Victor Guerrero Date: Wed, 29 Jan 2020 16:42:12 +0100 Subject: [PATCH 019/229] Update README.md (#194) Document getTranslation third argument $useFallbackLocale --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31b8040..3cff636 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ $newsItem->name; You can also use this method: ```php -public function getTranslation(string $attributeName, string $locale) : string +public function getTranslation(string $attributeName, string $locale, bool $useFallbackLocale = true) : string ``` This function has an alias named `translate`. From f267e89b4ede23a41fd2f5eba7da13f781af4f5d Mon Sep 17 00:00:00 2001 From: freek Date: Wed, 5 Feb 2020 12:47:21 +0100 Subject: [PATCH 020/229] wip --- .github/FUNDING.yml | 2 +- README.md | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2bec409..636ef53 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -patreon: spatie +custom: https://spatie.be/open-source/support-us diff --git a/README.md b/README.md index 3cff636..3e8307f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,12 @@ app()->setLocale('nl'); $newsItem->name; // Returns 'Naam in het Nederlands' ``` +## Support us + +We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). + +We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). + ## Installation You can install the package via composer: @@ -243,13 +249,6 @@ We publish all received postcards [on our company website](https://spatie.be/en/ We got the idea to store translations as json in a column from [Mohamed Said](https://github.com/themsaid). Parts of the readme of [his multilingual package](https://github.com/themsaid/laravel-multilingual) were used in this readme. -## Support us - -Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). - -Does your business depend on our contributions? Reach out and support us on [Patreon](https://www.patreon.com/spatie). -All pledges will be dedicated to allocating workforce on maintenance and new awesome stuff. - ## License The MIT License (MIT). Please see [License File](LICENSE.md) for more information. From e5692f4d987a8cc14b1d26f8447c119f8a9727ab Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 2 Mar 2020 20:33:37 +0100 Subject: [PATCH 021/229] wip --- .github/workflows/run-tests.yml | 4 +++- composer.json | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index ef08b14..a0607ce 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,9 +10,11 @@ jobs: fail-fast: true matrix: php: [7.4] - laravel: [5.8.*, 6.*] + laravel: [5.8.*, 6.*, 7.*] dependency-version: [prefer-lowest, prefer-stable] include: + - laravel: 7.* + testbench: 5.* - laravel: 6.* testbench: 4.* - laravel: 5.8.* diff --git a/composer.json b/composer.json index 9d1eca4..38a06b5 100644 --- a/composer.json +++ b/composer.json @@ -33,12 +33,11 @@ ], "require": { "php" : "^7.2", - "illuminate/database": "~5.8.0|^6.0", + "illuminate/database": "~5.8.0|^6.0|^7.0", "illuminate/support": "~5.8.0|^6.0" }, "require-dev": { - "phpunit/phpunit": "^8.0", - "orchestra/testbench": "~3.8.0|^4.0", + "orchestra/testbench": "~3.8.0|^4.0|^5.0", "mockery/mockery": "^1.3" }, "autoload": { @@ -63,5 +62,7 @@ "Spatie\\Translatable\\TranslatableServiceProvider" ] } - } + }, + "minimum-stability": "dev", + "prefer-stable": true } From 452fe81106b5250c92d5c4b4034836159e2a10f0 Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 2 Mar 2020 20:34:42 +0100 Subject: [PATCH 022/229] wip --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a9295d..33167e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ All notable changes to `laravel-translatable` will be documented in this file -## 4.2.2 - 2019-01-20 +## 4.3.0 - 2020-03-02 + +- add support for Laravel 7 + +## 4.2.2 - 2020-01-20 - open up for non-model objects (#186) From 0f69b268257b3f594450712a95cce6178bb0eb13 Mon Sep 17 00:00:00 2001 From: freek Date: Mon, 2 Mar 2020 20:35:51 +0100 Subject: [PATCH 023/229] wip --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 38a06b5..b8812be 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "require": { "php" : "^7.2", "illuminate/database": "~5.8.0|^6.0|^7.0", - "illuminate/support": "~5.8.0|^6.0" + "illuminate/support": "~5.8.0|^6.0|^7.0" }, "require-dev": { "orchestra/testbench": "~3.8.0|^4.0|^5.0", From 0d0aa480162c8ce4de3d9028c109a919bfda75c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borys=20=C5=BBmuda?= Date: Wed, 11 Mar 2020 10:55:55 +0100 Subject: [PATCH 024/229] Lumen Fix (#201) Lumen without Facade will not work. --- src/HasTranslations.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index c53f47a..3f92230 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -167,11 +167,11 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - if (! is_null($fallbackLocale = Config::get('translatable.fallback_locale'))) { + if (! is_null($fallbackLocale = config('translatable.fallback_locale'))) { return $fallbackLocale; } - if (! is_null($fallbackLocale = Config::get('app.fallback_locale'))) { + if (! is_null($fallbackLocale = config('app.fallback_locale'))) { return $fallbackLocale; } @@ -180,7 +180,7 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac protected function getLocale(): string { - return Config::get('app.locale'); + return config('app.locale'); } public function getTranslatableAttributes(): array From 39da2d93138b36e5fe6b1e493cac0d1e6b06e534 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Wed, 11 Mar 2020 10:56:26 +0100 Subject: [PATCH 025/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33167e8..c432678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.3.1 - 2020-03-07 + +- Lumen fix (#201) + ## 4.3.0 - 2020-03-02 - add support for Laravel 7 From 1a88f3493ea7e54edcf0d942c7569625f27e4651 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 30 Apr 2020 14:00:37 +0400 Subject: [PATCH 026/229] Fix forgetTranslation & forgetAllTranslations on fields with mutator (#205) * Add field_with_mutator to test scenario * Fix forgetTranslation & forgetAllTranslations for fields with mutator --- src/HasTranslations.php | 7 +++++-- tests/TestCase.php | 1 + tests/TestModel.php | 7 ++++++- tests/TranslatableTest.php | 40 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 3f92230..6cf2747 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -117,9 +117,12 @@ public function forgetTranslation(string $key, string $locale): self { $translations = $this->getTranslations($key); - unset($translations[$locale]); + unset( + $translations[$locale], + $this->$key + ); - $this->setAttribute($key, $translations); + $this->setTranslations($key, $translations); return $this; } diff --git a/tests/TestCase.php b/tests/TestCase.php index e948cd7..12ca7fc 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -27,6 +27,7 @@ protected function setUpDatabase() $table->increments('id'); $table->text('name')->nullable(); $table->text('other_field')->nullable(); + $table->text('field_with_mutator')->nullable(); }); } } diff --git a/tests/TestModel.php b/tests/TestModel.php index 508cf4f..17c831c 100644 --- a/tests/TestModel.php +++ b/tests/TestModel.php @@ -14,5 +14,10 @@ class TestModel extends Model protected $guarded = []; public $timestamps = false; - public $translatable = ['name', 'other_field']; + public $translatable = ['name', 'other_field', 'field_with_mutator']; + + public function setFieldWithMutatorAttribute($value) + { + $this->attributes['field_with_mutator'] = $value; + } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 9c0ebcc..d07834d 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -148,6 +148,9 @@ public function it_can_get_all_translations_for_all_translatable_attributes_in_o $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); $this->testModel->save(); $this->assertSame([ @@ -159,6 +162,10 @@ public function it_can_get_all_translations_for_all_translatable_attributes_in_o 'en' => 'testValue_en', 'fr' => 'testValue_fr', ], + 'field_with_mutator' => [ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], ], $this->testModel->getTranslations()); } @@ -191,6 +198,25 @@ public function it_can_forget_a_translation() ], $this->testModel->getTranslations('name')); } + /** @test */ + public function it_can_forget_a_field_with_mutator_translation() + { + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); + + $this->testModel->forgetTranslation('field_with_mutator', 'en'); + + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); + } + /** @test */ public function it_can_forget_all_translations() { @@ -199,6 +225,9 @@ public function it_can_forget_all_translations() $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); $this->testModel->save(); $this->assertSame([ @@ -211,6 +240,11 @@ public function it_can_forget_all_translations() 'fr' => 'testValue_fr', ], $this->testModel->getTranslations('other_field')); + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); + $this->testModel->forgetAllTranslations('en'); $this->assertSame([ @@ -220,6 +254,10 @@ public function it_can_forget_all_translations() $this->assertSame([ 'fr' => 'testValue_fr', ], $this->testModel->getTranslations('other_field')); + + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); } /** @test */ @@ -423,11 +461,13 @@ public function it_can_get_all_translations() $translations = ['nl' => 'hallo', 'en' => 'hello']; $this->testModel->setTranslations('name', $translations); + $this->testModel->setTranslations('field_with_mutator', $translations); $this->testModel->save(); $this->assertEquals([ 'name' => ['nl' => 'hallo', 'en' => 'hello'], 'other_field' => [], + 'field_with_mutator' => ['nl' => 'hallo', 'en' => 'hello'], ], $this->testModel->translations); } From c15b457ddce4ccaf174de652780647cb086a77a5 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 30 Apr 2020 12:01:26 +0200 Subject: [PATCH 027/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c432678..2dd0fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.3.2 - 2020-04-30 + +- fix `forgetTranslation` & `forgetAllTranslations` on fields with mutator (#205) + ## 4.3.1 - 2020-03-07 - Lumen fix (#201) From 2d33bc9fb114e4c0675c1d475c10bd4584579a13 Mon Sep 17 00:00:00 2001 From: Yannik <3316758+Yannik-Slym@users.noreply.github.com> Date: Sun, 3 May 2020 22:56:07 +0200 Subject: [PATCH 028/229] FIX - Use app.fallback_locale by default (#206) --- config/translatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/translatable.php b/config/translatable.php index 699bea1..3faf551 100644 --- a/config/translatable.php +++ b/config/translatable.php @@ -5,5 +5,5 @@ /* * If a translation has not been set for a given locale, use this locale instead. */ - 'fallback_locale' => 'en', + 'fallback_locale' => null, ]; From 17f367bfd5a16e2be3bf61ff25ef02265c054ad5 Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Wed, 27 May 2020 15:13:42 +0200 Subject: [PATCH 029/229] Update README with new "Support us" section --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e8307f..c9dfd39 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,11 @@ $newsItem->name; // Returns 'Naam in het Nederlands' ## Support us -We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). +Learn how to create a package like this one, by watching our premium video course: + +[![Laravel Package training](https://spatie.be/github/package-training.jpg)](https://laravelpackage.training) + +We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). From da4ad0ea110902a50a14d688e9e673155acb132e Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Fri, 26 Jun 2020 10:00:56 +0200 Subject: [PATCH 030/229] Update address --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9dfd39..01b4e6d 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,7 @@ If you discover any security related issues, please email freek@spatie.be instea You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. -Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium. +Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium. We publish all received postcards [on our company website](https://spatie.be/en/opensource/postcards). From 494ef7d290b0df481cd7d9c739a65f7b22a5dabd Mon Sep 17 00:00:00 2001 From: Adrian Galicia Benavides Date: Thu, 9 Jul 2020 02:03:39 -0500 Subject: [PATCH 031/229] Fix multiple translations on mutator model field with array (#216) --- README.md | 6 ++++++ src/HasTranslations.php | 4 ++++ tests/TranslatableTest.php | 15 +++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/README.md b/README.md index 01b4e6d..69e5d30 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,12 @@ For example (given that `name` is a translatable attribute): $newsItem->name = 'New translation'; ``` +Also you can set tranlations with + +```php +$newItem->name = ['en' => 'myName', 'nl', 'Naam in het Nederlands']; +``` + To set a translation for a specific locale you can use this method: ``` php diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 6cf2747..135575b 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -20,6 +20,10 @@ public function getAttributeValue($key) public function setAttribute($key, $value) { + if ($this->isTranslatableAttribute($key) && is_array($value)) { + return $this->setTranslations($key, $value); + } + // Pass arrays and untranslatable attributes to the parent method. if (! $this->isTranslatableAttribute($key) || is_array($value)) { return parent::setAttribute($key, $value); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index d07834d..3e931ad 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -409,6 +409,21 @@ public function setNameAttribute($value) $this->assertEquals($expected, $testModel->getTranslations('name')); } + /** @test */ + public function it_can_set_multiple_translations_on_field_when_a_mutator_is_defined() + { + $translations = [ + 'nl' => 'hallo', + 'en' => 'hello', + ]; + + $testModel = $this->testModel; + $testModel->field_with_mutator = $translations; + $testModel->save(); + + $this->assertEquals($translations, $testModel->getTranslations('field_with_mutator')); + } + /** @test */ public function it_can_translate_a_field_based_on_the_translations_of_another_one() { From 7642b38df16a61e5738ed00c912ca522bb32b554 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 9 Jul 2020 09:05:40 +0200 Subject: [PATCH 032/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dd0fd3..4be5bb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.4.0 - 2020-07-09 + +- make possible to set multiple translations on mutator model field with array (#216) + ## 4.3.2 - 2020-04-30 - fix `forgetTranslation` & `forgetAllTranslations` on fields with mutator (#205) From 65988991561a9e4fc5c4f7564b58e3f619e4223b Mon Sep 17 00:00:00 2001 From: Yannik Firre <3316758+YannikFirre@users.noreply.github.com> Date: Thu, 9 Jul 2020 17:28:44 +0200 Subject: [PATCH 033/229] README add where example with json_extract (#217) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 69e5d30..c4e5efb 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,12 @@ This will allow you to query these columns like this: NewsItem::where('name->en', 'Name in English')->get(); ``` +Or if you're using MariaDB 10.2.3 or above : +```php +NewsItem::whereRaw("JSON_EXTRACT(name, '$.en') = 'Name in English'")->get(); +``` + + ## Changelog Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. From ddf7c785dc73b44068474d7f7ef3e6acbd7aa84d Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 10 Jul 2020 12:48:30 +0200 Subject: [PATCH 034/229] Fix Invalid Array Syntax (#218) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4e5efb..906648e 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ $newsItem->name = 'New translation'; Also you can set tranlations with ```php -$newItem->name = ['en' => 'myName', 'nl', 'Naam in het Nederlands']; +$newItem->name = ['en' => 'myName', 'nl' => 'Naam in het Nederlands']; ``` To set a translation for a specific locale you can use this method: From 6809f216f0837fb46b7111a0b6779348a0fd9191 Mon Sep 17 00:00:00 2001 From: Nathan Czachur <31296990+nathanczachur@users.noreply.github.com> Date: Sat, 22 Aug 2020 00:04:31 +0100 Subject: [PATCH 035/229] Fixing typo in README.md (#221) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 906648e..74ce942 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ For example (given that `name` is a translatable attribute): $newsItem->name = 'New translation'; ``` -Also you can set tranlations with +Also you can set translations with ```php $newItem->name = ['en' => 'myName', 'nl' => 'Naam in het Nederlands']; From 2e222de9bf8d0b032da8d8a616b4b74512b2248f Mon Sep 17 00:00:00 2001 From: Nicolas Perraut Date: Fri, 28 Aug 2020 17:07:01 +0200 Subject: [PATCH 036/229] Fix typo in README (#223) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 74ce942..326d111 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ You can install the package via composer: composer require spatie/laravel-translatable ``` -If you want to have another fallback_locale then the app fallback locale (see `config/app.php`), you could publish the config file: +If you want to have another fallback_locale than the app fallback locale (see `config/app.php`), you could publish the config file: ``` php artisan vendor:publish --provider="Spatie\Translatable\TranslatableServiceProvider" ``` From 238bef962fd62f5277f84d2500c66f2be10278fe Mon Sep 17 00:00:00 2001 From: Axel Pardemann Date: Sun, 6 Sep 2020 14:01:36 -0500 Subject: [PATCH 037/229] Add support for Laravel 8 (#226) * Add support for Laravel 8 * Migrate deprecated phpunit schema --- .github/workflows/run-tests.yml | 4 +++- composer.json | 6 +++--- phpunit.xml.dist | 37 +++++++++++++-------------------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a0607ce..5cb5982 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,9 +10,11 @@ jobs: fail-fast: true matrix: php: [7.4] - laravel: [5.8.*, 6.*, 7.*] + laravel: [5.8.*, 6.*, 7.*, 8.*] dependency-version: [prefer-lowest, prefer-stable] include: + - laravel: 8.* + testbench: 6.* - laravel: 7.* testbench: 5.* - laravel: 6.* diff --git a/composer.json b/composer.json index b8812be..4d8ee46 100644 --- a/composer.json +++ b/composer.json @@ -33,11 +33,11 @@ ], "require": { "php" : "^7.2", - "illuminate/database": "~5.8.0|^6.0|^7.0", - "illuminate/support": "~5.8.0|^6.0|^7.0" + "illuminate/database": "~5.8.0|^6.0|^7.0|^8.0", + "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0" }, "require-dev": { - "orchestra/testbench": "~3.8.0|^4.0|^5.0", + "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0", "mockery/mockery": "^1.3" }, "autoload": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bcdc282..ea5583b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,25 +1,16 @@ - - - - tests - - - - - src/ - - - - - + + + + src/ + + + + + tests + + + + + From cc2ce05f2dc9c7eca1ca79613d7dd3026c31e418 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Sun, 6 Sep 2020 21:02:11 +0200 Subject: [PATCH 038/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be5bb2..3bdeb30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.4.1 - 2020-09-06 + +- add support for Laravel 8 (#226) + ## 4.4.0 - 2020-07-09 - make possible to set multiple translations on mutator model field with array (#216) From 2aeb399c8d77a36539ece205a27801a10591bcb9 Mon Sep 17 00:00:00 2001 From: freek Date: Tue, 8 Sep 2020 19:47:11 +0200 Subject: [PATCH 039/229] wip --- .github/workflows/php-cs-fixer.yml | 29 +++++++++++++++++++++++ .gitignore | 1 + .php_cs | 38 ++++++++++++++++++++++++++++++ .scrutinizer.yml | 19 --------------- .styleci.yml | 1 - README.md | 2 -- composer.json | 6 +++-- 7 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/php-cs-fixer.yml create mode 100644 .php_cs delete mode 100644 .scrutinizer.yml delete mode 100644 .styleci.yml diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml new file mode 100644 index 0000000..5cb3a86 --- /dev/null +++ b/.github/workflows/php-cs-fixer.yml @@ -0,0 +1,29 @@ +name: Check & fix styling + +on: [push] + +jobs: + style: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v1 + + - name: Fix style + uses: docker://oskarstark/php-cs-fixer-ga + with: + args: --config=.php_cs --allow-risky=yes + + - name: Extract branch name + shell: bash + run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" + id: extract_branch + + - name: Commit changes + uses: stefanzweifel/git-auto-commit-action@v2.3.0 + with: + commit_message: Fix styling + branch: ${{ steps.extract_branch.outputs.branch }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index b6285d6..5096dd7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ composer.lock docs vendor .phpunit.result.cache +.php_cs.cache diff --git a/.php_cs b/.php_cs new file mode 100644 index 0000000..6b6c913 --- /dev/null +++ b/.php_cs @@ -0,0 +1,38 @@ +notPath('bootstrap/*') + ->notPath('storage/*') + ->notPath('storage/*') + ->notPath('resources/view/mail/*') + ->in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->name('*.php') + ->notName('*.blade.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => ['sortAlgorithm' => 'alpha'], + 'no_unused_imports' => true, + 'not_operator_with_successor_space' => true, + 'trailing_comma_in_multiline_array' => true, + 'phpdoc_scalar' => true, + 'unary_operator_spaces' => true, + 'binary_operator_spaces' => true, + 'blank_line_before_statement' => [ + 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], + ], + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_var_without_name' => true, + 'method_argument_space' => [ + 'on_multiline' => 'ensure_fully_multiline', + 'keep_multiple_spaces_after_comma' => true, + ] + ]) + ->setFinder($finder); diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index df16b68..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,19 +0,0 @@ -filter: - excluded_paths: [tests/*] - -checks: - php: - remove_extra_empty_lines: true - remove_php_closing_tag: true - remove_trailing_whitespace: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: true - order_alphabetically: true - fix_php_opening_tag: true - fix_linefeed: true - fix_line_ending: true - fix_identation_4spaces: true - fix_doc_comments: true - diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 0285f17..0000000 --- a/.styleci.yml +++ /dev/null @@ -1 +0,0 @@ -preset: laravel diff --git a/README.md b/README.md index 326d111..5d3fa76 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/spatie/laravel-translatable/run-tests?label=tests) -[![Quality Score](https://img.shields.io/scrutinizer/g/spatie/laravel-translatable.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie/laravel-translatable) -[![StyleCI](https://styleci.io/repos/55690447/shield?branch=master)](https://styleci.io/repos/55690447) [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. diff --git a/composer.json b/composer.json index 4d8ee46..8e731c3 100644 --- a/composer.json +++ b/composer.json @@ -37,8 +37,9 @@ "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0" }, "require-dev": { - "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0", - "mockery/mockery": "^1.3" + "friendsofphp/php-cs-fixer": "^2.16", + "mockery/mockery": "^1.3", + "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0" }, "autoload": { "psr-4": { @@ -51,6 +52,7 @@ } }, "scripts": { + "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes", "test": "vendor/bin/phpunit" }, "config": { From d2650550364d3b5db730cd89010100ae89110dd9 Mon Sep 17 00:00:00 2001 From: Antoine Gaubert Date: Fri, 2 Oct 2020 17:27:24 +0200 Subject: [PATCH 040/229] [feature] elegant syntax update (#229) * Update getLocale, Add withLocale * Add tests Code style Update README * Update README * Update property name to avoid collisions --- README.md | 21 +++++++++++++++++++++ src/HasTranslations.php | 18 ++++++++++++++++-- tests/TranslatableTest.php | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 326d111..9051be6 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,27 @@ $translations = [ $newsItem->setTranslations('name', $translations); ``` +#### Setting the model locale +The default locale used to translate models is the application locale, +however it can sometimes be handy to use a custom locale. + +To do so, you can use `setLocale` on a model instance. +``` php +$newsItem = NewsItem::firstOrFail()->setLocale('fr'); + +// Any properties on this model will automaticly be translated in French +$newsItem->name; // Will return `fr` translation +$newsItem->name = 'Actualité'; // Will set the `fr` translation +``` + +Alternatively, you can use `withLocale` static method: +``` php +// Will automatically set the `fr` translation +$newsItem = NewsItem::withLocale('fr')->create([ + 'name' => 'Actualité', +]); +``` + ### Events #### TranslationHasBeenSet diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 135575b..426ee17 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -9,6 +9,13 @@ trait HasTranslations { + protected $translationLocale = null; + + public static function withLocale(string $locale): self + { + return (new self())->setLocale($locale); + } + public function getAttributeValue($key) { if (! $this->isTranslatableAttribute($key)) { @@ -185,9 +192,16 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function getLocale(): string + public function setLocale(string $locale): self + { + $this->translationLocale = $locale; + + return $this; + } + + public function getLocale(): string { - return config('app.locale'); + return $this->translationLocale ?: config('app.locale'); } public function getTranslatableAttributes(): array diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 3e931ad..4c57ccb 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -530,4 +530,36 @@ public function it_will_not_remove_zero_value_of_other_locale_in_database() $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); } + + /** @test */ + public function it_can_be_translated_based_on_given_locale() + { + $value = 'World'; + + $this->testModel = TestModel::withLocale('en')->fill([ + 'name' => $value, + ]); + $this->testModel->save(); + + $this->assertSame($value, $this->testModel->getTranslation('name', 'en')); + } + + /** @test */ + public function it_can_set_and_fetch_attributes_based_on_set_locale() + { + $en = 'World'; + $fr = 'Monde'; + + $this->testModel->setLocale('en'); + $this->testModel->name = $en; + $this->testModel->setLocale('fr'); + $this->testModel->name = $fr; + + $this->testModel->save(); + + $this->testModel->setLocale('en'); + $this->assertSame($en, $this->testModel->name); + $this->testModel->setLocale('fr'); + $this->assertSame($fr, $this->testModel->name); + } } From 8b7eea6a79e3e15bb38377d67d147ddae9b0c48b Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Fri, 2 Oct 2020 17:27:53 +0200 Subject: [PATCH 041/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bdeb30..e76dbec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.4.2 - 2020-10-02 + +- elegant syntax update (#229) + ## 4.4.1 - 2020-09-06 - add support for Laravel 8 (#226) From 865b47c1705bda6b950ba060663f80d22b51a787 Mon Sep 17 00:00:00 2001 From: freek Date: Fri, 2 Oct 2020 22:55:46 +0200 Subject: [PATCH 042/229] wip --- CHANGELOG.md | 4 ++++ README.md | 4 ++-- src/HasTranslations.php | 2 +- tests/TranslatableTest.php | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e76dbec..c0a32f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.4.3 - 2020-10-2 + +- rename `withLocale` to `usingLocale` + ## 4.4.2 - 2020-10-02 - elegant syntax update (#229) diff --git a/README.md b/README.md index 6c8881e..29b83a3 100644 --- a/README.md +++ b/README.md @@ -189,10 +189,10 @@ $newsItem->name; // Will return `fr` translation $newsItem->name = 'Actualité'; // Will set the `fr` translation ``` -Alternatively, you can use `withLocale` static method: +Alternatively, you can use `usingLocale` static method: ``` php // Will automatically set the `fr` translation -$newsItem = NewsItem::withLocale('fr')->create([ +$newsItem = NewsItem::usingLocale('fr')->create([ 'name' => 'Actualité', ]); ``` diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 426ee17..94eebff 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -11,7 +11,7 @@ trait HasTranslations { protected $translationLocale = null; - public static function withLocale(string $locale): self + public static function usingLocale(string $locale): self { return (new self())->setLocale($locale); } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 4c57ccb..bba7d68 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -536,7 +536,7 @@ public function it_can_be_translated_based_on_given_locale() { $value = 'World'; - $this->testModel = TestModel::withLocale('en')->fill([ + $this->testModel = TestModel::usingLocale('en')->fill([ 'name' => $value, ]); $this->testModel->save(); From 37ab2c73871ca79e0e1c22709ffc99731bc37900 Mon Sep 17 00:00:00 2001 From: Javier Ledezma Date: Sat, 3 Oct 2020 05:58:53 -0500 Subject: [PATCH 043/229] [Feature] add replaceTranslations method which allows to replace all the translatios for a single key (#231) Co-authored-by: Javier Ledezma --- README.md | 22 ++++++++++++++++++++++ src/HasTranslations.php | 11 +++++++++++ tests/TranslatableTest.php | 14 ++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/README.md b/README.md index 29b83a3..9ddf62e 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,28 @@ $translations = [ $newsItem->setTranslations('name', $translations); ``` +#### Replace translations in one go + +You can replace all the translations for a single key using this method: + +```php +public function replaceTranslations(string $key, array $translations) +``` + +Here's an example: + +```php +$translations = ['en' => 'hello', 'es' => 'hola']; + +$newsItem->setTranslations('hello', $translations); +$newsItem->getTranslations(); // ['en' => 'hello', 'es' => 'hola'] + +$newTranslations = ['en' => 'hello']; + +$newsItem->replaceTranslations('hello', $newTranslations); +$newsItem->getTranslations(); // ['en' => 'hello'] +``` + #### Setting the model locale The default locale used to translate models is the application locale, however it can sometimes be handy to use a custom locale. diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 94eebff..edbd7b4 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -164,6 +164,17 @@ public function hasTranslation(string $key, string $locale = null): bool return isset($this->getTranslations($key)[$locale]); } + public function replaceTranslations(string $key, array $translations): self + { + foreach ($this->getTranslatedLocales($key) as $locale) { + $this->forgetTranslation($key, $locale); + } + + $this->setTranslations($key, $translations); + + return $this; + } + protected function guardAgainstNonTranslatableAttribute(string $key) { if (! $this->isTranslatableAttribute($key)) { diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index bba7d68..a5109e2 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -562,4 +562,18 @@ public function it_can_set_and_fetch_attributes_based_on_set_locale() $this->testModel->setLocale('fr'); $this->assertSame($fr, $this->testModel->name); } + + /** @test */ + public function it_can_replace_translations() + { + $translations = ['nl' => 'hallo', 'en' => 'hello', 'kh' => 'សួរស្តី']; + + $this->testModel->setTranslations('name', $translations); + $this->testModel->save(); + + $newTranslations = ['es' => 'hola']; + $this->testModel->replaceTranslations('name', $newTranslations); + + $this->assertEquals($newTranslations, $this->testModel->getTranslations('name')); + } } From 3af4a717bfcc836201461209c4344b8b98811701 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Sat, 3 Oct 2020 13:00:18 +0200 Subject: [PATCH 044/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0a32f6..98be0b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.5.0 2020-10-03 + +- add replaceTranslations method (#231) + ## 4.4.3 - 2020-10-2 - rename `withLocale` to `usingLocale` From c554d0fdf971442bb954cec453e4b78fa9d2263e Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Wed, 7 Oct 2020 10:50:46 +0200 Subject: [PATCH 045/229] Update README with new "Support us" section --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 9ddf62e..7370ec3 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,7 @@ $newsItem->name; // Returns 'Naam in het Nederlands' ## Support us -Learn how to create a package like this one, by watching our premium video course: - -[![Laravel Package training](https://spatie.be/github/package-training.jpg)](https://laravelpackage.training) +[![Image](https://github-ads.s3.eu-central-1.amazonaws.com/laravel-translatable.jpg)](https://spatie.be/github-ad-click/laravel-translatable) We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). @@ -265,7 +263,6 @@ Or if you're using MariaDB 10.2.3 or above : NewsItem::whereRaw("JSON_EXTRACT(name, '$.en') = 'Name in English'")->get(); ``` - ## Changelog Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. From b402293d34965e58ef8f38a8434a752196a45f6e Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Mon, 12 Oct 2020 11:01:26 +0200 Subject: [PATCH 046/229] Update README img tag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7370ec3..bdd4c6f 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ $newsItem->name; // Returns 'Naam in het Nederlands' ## Support us -[![Image](https://github-ads.s3.eu-central-1.amazonaws.com/laravel-translatable.jpg)](https://spatie.be/github-ad-click/laravel-translatable) +[](https://spatie.be/github-ad-click/laravel-translatable) We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). From c25505a41026a677f555ce5fa216c1b66a70f881 Mon Sep 17 00:00:00 2001 From: Guido Hendriks Date: Thu, 22 Oct 2020 13:42:19 +0200 Subject: [PATCH 047/229] Set casts to string (#235) --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index edbd7b4..2cd4433 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -235,7 +235,7 @@ public function getCasts(): array { return array_merge( parent::getCasts(), - array_fill_keys($this->getTranslatableAttributes(), 'array') + array_fill_keys($this->getTranslatableAttributes(), 'string') ); } } From 6a9dc2478eb61c0af4cced721653d6442916cf33 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 22 Oct 2020 13:42:56 +0200 Subject: [PATCH 048/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98be0b5..eb032dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.5.1 - 2020-10-22 + +- use string casting for translatable columns (#235) + ## 4.5.0 2020-10-03 - add replaceTranslations method (#231) From f5cd1a6de1cc4b8ce7daaf809d9156f70cdd97f6 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 22 Oct 2020 15:52:01 +0200 Subject: [PATCH 049/229] Update HasTranslations.php --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 2cd4433..edbd7b4 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -235,7 +235,7 @@ public function getCasts(): array { return array_merge( parent::getCasts(), - array_fill_keys($this->getTranslatableAttributes(), 'string') + array_fill_keys($this->getTranslatableAttributes(), 'array') ); } } From 73e5c922a0004967e6be2bf73e36780af4090155 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 22 Oct 2020 15:52:25 +0200 Subject: [PATCH 050/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb032dc..3f9d575 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.5.2 - 2020-10-22 + +- revert #235 + ## 4.5.1 - 2020-10-22 - use string casting for translatable columns (#235) From 65a29d2f1a899f42100a22621b806115951a4ead Mon Sep 17 00:00:00 2001 From: mohamed-3ly <50369434+mohamed-3ly@users.noreply.github.com> Date: Tue, 27 Oct 2020 20:35:04 +0200 Subject: [PATCH 051/229] Update README.md (#238) --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index bdd4c6f..5dd0d13 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,35 @@ Or if you're using MariaDB 10.2.3 or above : NewsItem::whereRaw("JSON_EXTRACT(name, '$.en') = 'Name in English'")->get(); ``` +### Automatically display the right translation when displaying model + +Many times models using `HasTranslation` trait may be directly returned as response content. +In this scenario, and similar ones, the `toArray()` method on `Model` class is called under the hood to serialize your model; it accesses directly the $attributes field to perform the serialization, bypassing the translatable feature (which is based on accessors and mutators) and returning the text representation of the stored JSON instead of the translated value. + +The best way to make your model automatically return translated fields is to wrap `Spatie\Translatable\HasTranslations` trait into a custom trait which overrides the `toArray()` method to automatically replace all translatable fields content with their translated value, like in the following example, and use it instead of the default one. + +``` php +namespace App\Traits; +use Spatie\Translatable\HasTranslations as BaseHasTranslations; +trait HasTranslations +{ + use BaseHasTranslations; + /** + * Convert the model instance to an array. + * + * @return array + */ + public function toArray() + { + $attributes = parent::toArray(); + foreach ($this->getTranslatableAttributes() as $field) { + $attributes[$field] = $this->getTranslation($field, \App::getLocale()); + } + return $attributes; + } +} +``` + ## Changelog Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. From 75e3399709c43a7594b89e725229ebbf45bca68e Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 19 Nov 2020 14:46:24 +0100 Subject: [PATCH 052/229] allow php 8 --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 0 .github/workflows/php-cs-fixer.yml | 16 ++++-------- .github/workflows/run-tests.yml | 29 +++++++++++----------- README.md | 2 +- composer.json | 2 +- 5 files changed, 21 insertions(+), 28 deletions(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%) diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 5cb3a86..c402e34 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -8,22 +8,16 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v1 + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} - - name: Fix style + - name: Run PHP CS Fixer uses: docker://oskarstark/php-cs-fixer-ga with: args: --config=.php_cs --allow-risky=yes - - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - id: extract_branch - - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v2.3.0 + uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: Fix styling - branch: ${{ steps.extract_branch.outputs.branch }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 5cb5982..e239614 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -4,14 +4,14 @@ on: [push, pull_request] jobs: test: - - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: true matrix: - php: [7.4] - laravel: [5.8.*, 6.*, 7.*, 8.*] - dependency-version: [prefer-lowest, prefer-stable] + os: [ubuntu-latest] + php: [8.0, 7.4] + laravel: [8.*, 7.*, 6.*, 5.8.*] + stability: [prefer-lowest, prefer-stable] include: - laravel: 8.* testbench: 6.* @@ -22,29 +22,28 @@ jobs: - laravel: 5.8.* testbench: 3.8.* - name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v1 - - - name: Cache dependencies - uses: actions/cache@v1 - with: - path: ~/.composer/cache/files - key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} + uses: actions/checkout@v2 - name: Setup PHP - uses: shivammathur/setup-php@v1 + uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick coverage: none + - name: Setup problem matchers + run: | + echo "::add-matcher::${{ runner.tool_cache }}/php.json" + echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Install dependencies run: | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update - composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest + composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests run: vendor/bin/phpunit diff --git a/README.md b/README.md index 5dd0d13..da31111 100644 --- a/README.md +++ b/README.md @@ -310,7 +310,7 @@ composer test ## Contributing -Please see [CONTRIBUTING](CONTRIBUTING.md) for details. +Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. ## Security diff --git a/composer.json b/composer.json index 8e731c3..9158183 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ } ], "require": { - "php" : "^7.2", + "php" : "^7.2|^8.0", "illuminate/database": "~5.8.0|^6.0|^7.0|^8.0", "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0" }, From 3ea783245e17a7fbb58fc98d4aeb3778daf1ce65 Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 19 Nov 2020 14:51:08 +0100 Subject: [PATCH 053/229] remove php_cs from require dev --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9158183..fa46c77 100644 --- a/composer.json +++ b/composer.json @@ -37,8 +37,7 @@ "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "mockery/mockery": "^1.3", + "mockery/mockery": "^1.4", "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0" }, "autoload": { From 1296bddf3943c17b5112f2aca36b077434453577 Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 19 Nov 2020 14:53:49 +0100 Subject: [PATCH 054/229] remove support on L5.8 --- .github/workflows/run-tests.yml | 4 +--- composer.json | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index e239614..7a23cc3 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,7 +10,7 @@ jobs: matrix: os: [ubuntu-latest] php: [8.0, 7.4] - laravel: [8.*, 7.*, 6.*, 5.8.*] + laravel: [8.*, 7.*, 6.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 8.* @@ -19,8 +19,6 @@ jobs: testbench: 5.* - laravel: 6.* testbench: 4.* - - laravel: 5.8.* - testbench: 3.8.* name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/composer.json b/composer.json index fa46c77..5250a8b 100644 --- a/composer.json +++ b/composer.json @@ -33,12 +33,12 @@ ], "require": { "php" : "^7.2|^8.0", - "illuminate/database": "~5.8.0|^6.0|^7.0|^8.0", - "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0" + "illuminate/database": "^6.0|^7.0|^8.0", + "illuminate/support": "^6.0|^7.0|^8.0" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0" + "orchestra/testbench": "^4.0|^5.0|^6.0" }, "autoload": { "psr-4": { From cc10294b665a570456aeb552fe42b5ac6fbadcdb Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 19 Nov 2020 14:57:55 +0100 Subject: [PATCH 055/229] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f9d575..e4b3da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to `laravel-translatable` will be documented in this file +## 4.6.0 - 2020-11-19 + +- add support for PHP 8.0 (#241) +- drop support for Laravel 5.8 (#241) + ## 4.5.2 - 2020-10-22 - revert #235 From d69b213b46d26b9537c69bb1f41b93876d4ec346 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 26 Mar 2021 12:54:17 -0400 Subject: [PATCH 056/229] Add PHP 8-only Support (v5) (#269) * drop support for PHP 7, Laravel 6 * implement laravel-package-tools * convert to PHP 8 syntax * drop support for PHP 7, Laravel 6.x * minor fixes * update changelog * Fix styling --- .github/workflows/run-tests.yml | 6 ++-- CHANGELOG.md | 8 +++++ README.md | 6 ++-- composer.json | 9 +++--- src/Events/TranslationHasBeenSet.php | 30 +++++-------------- src/Exceptions/AttributeIsNotTranslatable.php | 2 +- src/HasTranslations.php | 17 ++++++----- src/TranslatableServiceProvider.php | 18 +++++------ 8 files changed, 43 insertions(+), 53 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 7a23cc3..216156e 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,16 +9,14 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.0, 7.4] - laravel: [8.*, 7.*, 6.*] + php: [8.0] + laravel: [8.*, 7.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 8.* testbench: 6.* - laravel: 7.* testbench: 5.* - - laravel: 6.* - testbench: 4.* name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/CHANGELOG.md b/CHANGELOG.md index e4b3da5..bc9b81f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `laravel-translatable` will be documented in this file +## 5.0.0 - unreleased + +- require PHP 8+ +- convert syntax to PHP 8 +- drop support for PHP 7.x +- drop support for Laravel 6.x +- implement `spatie/laravel-package-tools` + ## 4.6.0 - 2020-11-19 - add support for PHP 8.0 (#241) diff --git a/README.md b/README.md index da31111..56efab5 100644 --- a/README.md +++ b/README.md @@ -36,12 +36,12 @@ We highly appreciate you sending us a postcard from your hometown, mentioning wh You can install the package via composer: -``` bash +```bash composer require spatie/laravel-translatable ``` If you want to have another fallback_locale than the app fallback locale (see `config/app.php`), you could publish the config file: -``` +```bash php artisan vendor:publish --provider="Spatie\Translatable\TranslatableServiceProvider" ``` @@ -62,7 +62,7 @@ The required steps to make a model translatable are: Here's an example of a prepared model: -``` php +```php use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; diff --git a/composer.json b/composer.json index 5250a8b..031072c 100644 --- a/composer.json +++ b/composer.json @@ -32,13 +32,14 @@ } ], "require": { - "php" : "^7.2|^8.0", - "illuminate/database": "^6.0|^7.0|^8.0", - "illuminate/support": "^6.0|^7.0|^8.0" + "php": "^8.0", + "illuminate/database": "^7.0|^8.0", + "illuminate/support": "^7.0|^8.0", + "spatie/laravel-package-tools": "^1.6" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^4.0|^5.0|^6.0" + "orchestra/testbench": "^5.0|^6.0" }, "autoload": { "psr-4": { diff --git a/src/Events/TranslationHasBeenSet.php b/src/Events/TranslationHasBeenSet.php index a3ad310..5051043 100644 --- a/src/Events/TranslationHasBeenSet.php +++ b/src/Events/TranslationHasBeenSet.php @@ -4,27 +4,13 @@ class TranslationHasBeenSet { - /** @var \Spatie\Translatable\Translatable */ - public $model; - - /** @var string */ - public $key; - - /** @var string */ - public $locale; - - public $oldValue; - public $newValue; - - public function __construct($model, string $key, string $locale, $oldValue, $newValue) - { - $this->model = $model; - - $this->key = $key; - - $this->locale = $locale; - - $this->oldValue = $oldValue; - $this->newValue = $newValue; + public function __construct( + public mixed $model, + public string $key, + public string $locale, + public mixed $oldValue, + public mixed $newValue, + ) { + // } } diff --git a/src/Exceptions/AttributeIsNotTranslatable.php b/src/Exceptions/AttributeIsNotTranslatable.php index 431dfb6..a898e2c 100644 --- a/src/Exceptions/AttributeIsNotTranslatable.php +++ b/src/Exceptions/AttributeIsNotTranslatable.php @@ -6,7 +6,7 @@ class AttributeIsNotTranslatable extends Exception { - public static function make(string $key, $model) + public static function make(string $key, $model): static { $translatableAttributes = implode(', ', $model->getTranslatableAttributes()); diff --git a/src/HasTranslations.php b/src/HasTranslations.php index edbd7b4..081b02f 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -9,14 +9,14 @@ trait HasTranslations { - protected $translationLocale = null; + protected string | null $translationLocale = null; public static function usingLocale(string $locale): self { return (new self())->setLocale($locale); } - public function getAttributeValue($key) + public function getAttributeValue($key): mixed { if (! $this->isTranslatableAttribute($key)) { return parent::getAttributeValue($key); @@ -46,7 +46,7 @@ public function translate(string $key, string $locale = '', bool $useFallbackLoc return $this->getTranslation($key, $locale, $useFallbackLocale); } - public function getTranslation(string $key, string $locale, bool $useFallbackLocale = true) + public function getTranslation(string $key, string $locale, bool $useFallbackLocale = true): mixed { $locale = $this->normalizeLocale($key, $locale, $useFallbackLocale); @@ -66,7 +66,7 @@ public function getTranslationWithFallback(string $key, string $locale): string return $this->getTranslation($key, $locale, true); } - public function getTranslationWithoutFallback(string $key, string $locale) + public function getTranslationWithoutFallback(string $key, string $locale): mixed { return $this->getTranslation($key, $locale, false); } @@ -76,9 +76,10 @@ public function getTranslations(string $key = null): array if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); - return array_filter(json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], function ($value) { - return $value !== null && $value !== ''; - }); + return array_filter( + json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], + fn ($value) => $value !== null && $value !== '' + ); } return array_reduce($this->getTranslatableAttributes(), function ($result, $item) { @@ -175,7 +176,7 @@ public function replaceTranslations(string $key, array $translations): self return $this; } - protected function guardAgainstNonTranslatableAttribute(string $key) + protected function guardAgainstNonTranslatableAttribute(string $key): void { if (! $this->isTranslatableAttribute($key)) { throw AttributeIsNotTranslatable::make($key, $this); diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index 2efff53..a289adc 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -2,19 +2,15 @@ namespace Spatie\Translatable; -use Illuminate\Support\ServiceProvider; +use Spatie\LaravelPackageTools\Package; +use Spatie\LaravelPackageTools\PackageServiceProvider; -class TranslatableServiceProvider extends ServiceProvider +class TranslatableServiceProvider extends PackageServiceProvider { - public function boot() + public function configurePackage(Package $package): void { - $this->publishes([ - __DIR__.'/../config/translatable.php' => config_path('translatable.php'), - ], 'config'); - } - - public function register() - { - $this->mergeConfigFrom(__DIR__.'/../config/translatable.php', 'translatable'); + $package + ->name('laravel-translatable') + ->hasConfigFile(); } } From dee1a11a7bff406976337d4cae66f53816637e73 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Fri, 26 Mar 2021 17:54:50 +0100 Subject: [PATCH 057/229] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9b81f..ee030fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to `laravel-translatable` will be documented in this file -## 5.0.0 - unreleased +## 5.0.0 - 2021-03-26 - require PHP 8+ - convert syntax to PHP 8 From d55d766dd732c6077cd1adecd06ada628bd8d127 Mon Sep 17 00:00:00 2001 From: Craig Childs Date: Thu, 15 Jul 2021 11:29:21 +0100 Subject: [PATCH 058/229] fix: return types should match 'mixed' return type of getTranslation (#286) Co-authored-by: Craig Childs --- src/HasTranslations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 081b02f..1bb6367 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -41,7 +41,7 @@ public function setAttribute($key, $value) return $this->setTranslation($key, $this->getLocale(), $value); } - public function translate(string $key, string $locale = '', bool $useFallbackLocale = true): string + public function translate(string $key, string $locale = '', bool $useFallbackLocale = true): mixed { return $this->getTranslation($key, $locale, $useFallbackLocale); } @@ -61,7 +61,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc return $translation; } - public function getTranslationWithFallback(string $key, string $locale): string + public function getTranslationWithFallback(string $key, string $locale): mixed { return $this->getTranslation($key, $locale, true); } From c1c201ff3ddff767ab53da2faf78ba141518ae69 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 15 Jul 2021 12:30:08 +0200 Subject: [PATCH 059/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee030fd..64731a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 5.0.1 - 2021-07-15 + +- fix return types of getTranslation (#286) + ## 5.0.0 - 2021-03-26 - require PHP 8+ From 0d76eda5e1ce96d9d06e4e74fb5f473749fccc25 Mon Sep 17 00:00:00 2001 From: Khalil Laleh Date: Tue, 28 Sep 2021 17:50:38 +0330 Subject: [PATCH 060/229] Feature/specify locales in get translations method (#299) * Add new locales argument to getTranslations method to filter translations * Update the README to include the new argument in the getTranslations method * Create the filterTranslations method with early returns to validate the translations * Add the description and example for the allowedLocales argument in the getTranslations method --- README.md | 29 +++++++++++++++++++++++++---- src/HasTranslations.php | 30 ++++++++++++++++++++++++++---- tests/TranslatableTest.php | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 56efab5..1e1e7af 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ $newsItem ->setTranslation('name', 'en', 'Name in English') ->setTranslation('name', 'nl', 'Naam in het Nederlands') ->save(); - + $newsItem->name; // Returns 'Name in English' given that the current app locale is 'en' $newsItem->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands' @@ -69,7 +69,7 @@ use Spatie\Translatable\HasTranslations; class NewsItem extends Model { use HasTranslations; - + public $translatable = ['name']; } ``` @@ -157,6 +157,27 @@ public function forgetAllTranslations(string $locale) public function getTranslations(string $attributeName): array ``` +#### Getting the specified translations in one go + +You can filter the translations by passing an array of locales: +``` php +public function getTranslations(string $attributeName, array $allowedLocales): array +``` + +Here's an example: + +```php +$translations = [ + 'en' => 'Hello', + 'fr' => 'Bonjour', + 'de' => 'Hallo', +]; + +$newsItem->setTranslations('hello', $translations); +$newsItem->getTranslations('hello', ['en', 'fr']); // returns ['en' => 'Hello', 'fr' => 'Bonjour'] +``` + + #### Setting translations in one go ``` php @@ -198,7 +219,7 @@ $newsItem->getTranslations(); // ['en' => 'hello'] #### Setting the model locale The default locale used to translate models is the application locale, -however it can sometimes be handy to use a custom locale. +however it can sometimes be handy to use a custom locale. To do so, you can use `setLocale` on a model instance. ``` php @@ -296,7 +317,7 @@ trait HasTranslations Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. -## Upgrading +## Upgrading ### From v2 to v3 diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 1bb6367..d7286d6 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -71,19 +71,20 @@ public function getTranslationWithoutFallback(string $key, string $locale): mixe return $this->getTranslation($key, $locale, false); } - public function getTranslations(string $key = null): array + public function getTranslations(string $key = null, array $allowedLocales = null): array { if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); return array_filter( json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], - fn ($value) => $value !== null && $value !== '' + fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales), + ARRAY_FILTER_USE_BOTH ); } - return array_reduce($this->getTranslatableAttributes(), function ($result, $item) { - $result[$item] = $this->getTranslations($item); + return array_reduce($this->getTranslatableAttributes(), function ($result, $item) use ($allowedLocales) { + $result[$item] = $this->getTranslations($item, $allowedLocales); return $result; }); @@ -204,6 +205,27 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } + protected function filterTranslations(string $value = null, string $locale = null, array $allowedLocales = null): bool + { + if ($value === null) { + return false; + } + + if ($value === '') { + return false; + } + + if ($allowedLocales === null) { + return true; + } + + if (! in_array($locale, $allowedLocales)) { + return false; + } + + return true; + } + public function setLocale(string $locale): self { $this->translationLocale = $locale; diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index a5109e2..dd9dc1d 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -140,6 +140,18 @@ public function it_can_get_all_translations_in_one_go() ], $this->testModel->getTranslations('name')); } + /** @test */ + public function it_can_get_specified_translations_in_one_go() + { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + ], $this->testModel->getTranslations('name', ['en'])); + } + /** @test */ public function it_can_get_all_translations_for_all_translatable_attributes_in_one_go() { @@ -169,6 +181,26 @@ public function it_can_get_all_translations_for_all_translatable_attributes_in_o ], $this->testModel->getTranslations()); } + /** @test */ + public function it_can_get_specified_translations_for_all_translatable_attributes_in_one_go() + { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); + $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'name' => ['en' => 'testValue_en'], + 'other_field' => ['en' => 'testValue_en'], + 'field_with_mutator' => ['en' => 'testValue_en'], + ], $this->testModel->getTranslations(null, ['en'])); + } + /** @test */ public function it_can_get_the_locales_which_have_a_translation() { From 7ea25cf24754b4f55fd3efa3c10ef2b39755a385 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Tue, 28 Sep 2021 16:21:12 +0200 Subject: [PATCH 061/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64731a2..9172669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 5.0.2 - 2021-09-28 + +- specify locales in get translations method (#299) + ## 5.0.1 - 2021-07-15 - fix return types of getTranslation (#286) From 5837ee7fb5996fe3e4278673c685fe9611f5ad04 Mon Sep 17 00:00:00 2001 From: Khalil Laleh Date: Mon, 4 Oct 2021 18:29:21 +0330 Subject: [PATCH 062/229] Solve the string value issue in filterTranslations method (#300) --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index d7286d6..b94b1db 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -205,7 +205,7 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function filterTranslations(string $value = null, string $locale = null, array $allowedLocales = null): bool + protected function filterTranslations(mixed $value = null, string $locale = null, array $allowedLocales = null): bool { if ($value === null) { return false; From 06aa692efc2eed838ac47a6324dc179167a97b0b Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 4 Oct 2021 16:59:49 +0200 Subject: [PATCH 063/229] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9172669..3eb91ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 5.0.3 - 2021-10-04 + +- solve the string value issue in filterTranslations method (#300) + ## 5.0.2 - 2021-09-28 - specify locales in get translations method (#299) From 0ec27ab8ce05230d3288f87e4f5e0c2c52cdc24d Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Wed, 17 Nov 2021 15:13:42 +0100 Subject: [PATCH 064/229] Update composer.json --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 031072c..54bcf53 100644 --- a/composer.json +++ b/composer.json @@ -33,13 +33,13 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^7.0|^8.0", - "illuminate/support": "^7.0|^8.0", - "spatie/laravel-package-tools": "^1.6" + "illuminate/database": "^8.0", + "illuminate/support": "^8.0", + "spatie/laravel-package-tools": "^1.9" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^5.0|^6.0" + "orchestra/testbench": "^6.23" }, "autoload": { "psr-4": { From 24e01b3823dd10e516cea8bd7b4506ca4881486c Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Wed, 17 Nov 2021 15:14:11 +0100 Subject: [PATCH 065/229] Update run-tests.yml --- .github/workflows/run-tests.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 216156e..9cd0e4e 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,14 +9,12 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.0] - laravel: [8.*, 7.*] + php: [8.1 8.0] + laravel: [8.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 8.* - testbench: 6.* - - laravel: 7.* - testbench: 5.* + testbench: 6.23 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} From 0e0bca41f4e8ecc6cec90aab7c5e03789253ba00 Mon Sep 17 00:00:00 2001 From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com> Date: Thu, 16 Dec 2021 09:41:16 +0100 Subject: [PATCH 066/229] Return any translation if neither preferred locale nor fallback locale found (#312) * Add option to fall back to fist translation available * Update README --- README.md | 5 ++- config/translatable.php | 6 ++++ src/HasTranslations.php | 11 +++--- tests/TranslatableTest.php | 71 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1e1e7af..f15b832 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,13 @@ php artisan vendor:publish --provider="Spatie\Translatable\TranslatableServicePr This is the contents of the published file: ```php return [ - 'fallback_locale' => 'en', + 'fallback_locale' => null, + 'fallback_any' => false, ]; ``` +Sometimes it is favored to return any translation if neigher the translation for the prefered locale nor the fallbacl locale are set. To do so, set fallback_any in the config to true. + ## Making a model translatable The required steps to make a model translatable are: diff --git a/config/translatable.php b/config/translatable.php index 3faf551..02ec12c 100644 --- a/config/translatable.php +++ b/config/translatable.php @@ -6,4 +6,10 @@ * If a translation has not been set for a given locale, use this locale instead. */ 'fallback_locale' => null, + + /* + * If a translation has not been set for a given locale and the fallback locale, + * any other locale will be chosen instead. + */ + 'fallback_any' => false, ]; diff --git a/src/HasTranslations.php b/src/HasTranslations.php index b94b1db..2b83936 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -186,7 +186,9 @@ protected function guardAgainstNonTranslatableAttribute(string $key): void protected function normalizeLocale(string $key, string $locale, bool $useFallbackLocale): string { - if (in_array($locale, $this->getTranslatedLocales($key))) { + $translatedLocales = $this->getTranslatedLocales($key); + + if (in_array($locale, $translatedLocales)) { return $locale; } @@ -194,12 +196,13 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - if (! is_null($fallbackLocale = config('translatable.fallback_locale'))) { + $fallbackLocale = config('translatable.fallback_locale') ?? config('app.fallback_locale'); + if (! is_null($fallbackLocale) && in_array($fallbackLocale, $translatedLocales)) { return $fallbackLocale; } - if (! is_null($fallbackLocale = config('app.fallback_locale'))) { - return $fallbackLocale; + if (! empty($translatedLocales) && config('translatable.fallback_any')) { + return $translatedLocales[0]; } return $locale; diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index dd9dc1d..6dd9512 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -608,4 +608,75 @@ public function it_can_replace_translations() $this->assertEquals($newTranslations, $this->testModel->getTranslations('name')); } + + /** @test */ + public function it_can_use_any_locale_if_given_locale_not_set() + { + config()->set('app.fallback_locale', 'en'); + config()->set('translatable.fallback_any', true); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'de', 'testValue_de'); + $this->testModel->save(); + + $this->testModel->setLocale('it'); + $this->assertSame('testValue_fr', $this->testModel->name); + } + + /** @test */ + public function it_will_return_set_translation_when_fallback_any_set() + { + config()->set('app.fallback_locale', 'en'); + config()->set('translatable.fallback_any', true); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'de', 'testValue_de'); + $this->testModel->save(); + + $this->testModel->setLocale('de'); + $this->assertSame('testValue_de', $this->testModel->name); + } + + /** @test */ + public function it_will_return_fallback_translation_when_fallback_any_set() + { + config()->set('app.fallback_locale', 'en'); + config()->set('translatable.fallback_any', true); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->testModel->setLocale('de'); + $this->assertSame('testValue_en', $this->testModel->name); + } + + /** @test */ + public function it_provides_a_flog_to_not_return_any_translation_when_getting_an_unknown_locale() + { + config()->set('app.fallback_locale', 'en'); + config()->set('translatable.fallback_any', true); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'de', 'testValue_de'); + $this->testModel->save(); + + $this->testModel->setLocale('it'); + $this->assertSame('', $this->testModel->getTranslation('name', 'it', false)); + } + + /** @test */ + public function it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale_with_fallback_any() + { + config()->set('app.fallback_locale', 'en'); + config()->set('translatable.fallback_any', true); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); + } + + + } From 02ba5da0587df044ca57f37f19ca6112a02e3a8a Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 12 Jan 2022 16:03:26 +0100 Subject: [PATCH 067/229] Update README.md (#317) fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f15b832..d5125b8 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ return [ ]; ``` -Sometimes it is favored to return any translation if neigher the translation for the prefered locale nor the fallbacl locale are set. To do so, set fallback_any in the config to true. +Sometimes it is favored to return any translation if neigher the translation for the prefered locale nor the fallback locale are set. To do so, set fallback_any in the config to true. ## Making a model translatable From 41f09d516e74e4408796e67f9eaccce4bf1e6288 Mon Sep 17 00:00:00 2001 From: freek Date: Thu, 13 Jan 2022 12:10:47 +0100 Subject: [PATCH 068/229] wip --- .github/workflows/php-cs-fixer.yml | 26 ++++++++++++------------ .github/workflows/run-tests.yml | 14 +++---------- .github/workflows/update-changelog.yml | 28 ++++++++++++++++++++++++++ .gitignore | 3 ++- .php_cs => .php_cs.dist.php | 20 +++++++++--------- composer.json | 6 +++--- 6 files changed, 60 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/update-changelog.yml rename .php_cs => .php_cs.dist.php (71%) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index c402e34..62f6106 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -3,21 +3,21 @@ name: Check & fix styling on: [push] jobs: - style: + php-cs-fixer: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} - - name: Run PHP CS Fixer - uses: docker://oskarstark/php-cs-fixer-ga - with: - args: --config=.php_cs --allow-risky=yes + - name: Run PHP CS Fixer + uses: docker://oskarstark/php-cs-fixer-ga + with: + args: --config=.php_cs.dist.php --allow-risky=yes - - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: Fix styling + - name: Commit changes + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Fix styling diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 9cd0e4e..f52c5a3 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,9 +10,11 @@ jobs: matrix: os: [ubuntu-latest] php: [8.1 8.0] - laravel: [8.*] + laravel: [9.*, 8.*] stability: [prefer-lowest, prefer-stable] include: + - laravel: 9.* + testbench: 7.* - laravel: 8.* testbench: 6.23 @@ -41,13 +43,3 @@ jobs: - name: Execute tests run: vendor/bin/phpunit - - - name: Send Slack notification - uses: 8398a7/action-slack@v2 - if: failure() - with: - status: ${{ job.status }} - author_name: ${{ github.actor }} - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml new file mode 100644 index 0000000..fa56639 --- /dev/null +++ b/.github/workflows/update-changelog.yml @@ -0,0 +1,28 @@ +name: "Update Changelog" + +on: + release: + types: [released] + +jobs: + update: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: main + + - name: Update Changelog + uses: stefanzweifel/changelog-updater-action@v1 + with: + latest-version: ${{ github.event.release.name }} + release-notes: ${{ github.event.release.body }} + + - name: Commit updated CHANGELOG + uses: stefanzweifel/git-auto-commit-action@v4 + with: + branch: main + commit_message: Update CHANGELOG + file_pattern: CHANGELOG.md diff --git a/.gitignore b/.gitignore index 5096dd7..8d8e31e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ composer.lock docs vendor .phpunit.result.cache -.php_cs.cache +.php-cs-fixer.cache + diff --git a/.php_cs b/.php_cs.dist.php similarity index 71% rename from .php_cs rename to .php_cs.dist.php index 6b6c913..8d8a790 100644 --- a/.php_cs +++ b/.php_cs.dist.php @@ -1,10 +1,6 @@ notPath('bootstrap/*') - ->notPath('storage/*') - ->notPath('storage/*') - ->notPath('resources/view/mail/*') ->in([ __DIR__ . '/src', __DIR__ . '/tests', @@ -14,14 +10,14 @@ ->ignoreDotFiles(true) ->ignoreVCS(true); -return PhpCsFixer\Config::create() +return (new PhpCsFixer\Config()) ->setRules([ - '@PSR2' => true, + '@PSR12' => true, 'array_syntax' => ['syntax' => 'short'], - 'ordered_imports' => ['sortAlgorithm' => 'alpha'], + 'ordered_imports' => ['sort_algorithm' => 'alpha'], 'no_unused_imports' => true, 'not_operator_with_successor_space' => true, - 'trailing_comma_in_multiline_array' => true, + 'trailing_comma_in_multiline' => true, 'phpdoc_scalar' => true, 'unary_operator_spaces' => true, 'binary_operator_spaces' => true, @@ -30,9 +26,15 @@ ], 'phpdoc_single_line_var_spacing' => true, 'phpdoc_var_without_name' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'method' => 'one', + ], + ], 'method_argument_space' => [ 'on_multiline' => 'ensure_fully_multiline', 'keep_multiple_spaces_after_comma' => true, - ] + ], + 'single_trait_insert_per_statement' => true, ]) ->setFinder($finder); diff --git a/composer.json b/composer.json index 54bcf53..c324b14 100644 --- a/composer.json +++ b/composer.json @@ -33,13 +33,13 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^8.0", - "illuminate/support": "^8.0", + "illuminate/database": "^8.0|^9.0", + "illuminate/support": "^8.0|^9.0", "spatie/laravel-package-tools": "^1.9" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^6.23" + "orchestra/testbench": "^6.23|^7.0" }, "autoload": { "psr-4": { From bdfcd5514823a28cee3468938b20c33c1026f858 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Thu, 13 Jan 2022 11:11:20 +0000 Subject: [PATCH 069/229] Fix styling --- src/HasTranslations.php | 1 - tests/TranslatableTest.php | 17 +++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 2b83936..12967a0 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -2,7 +2,6 @@ namespace Spatie\Translatable; -use Illuminate\Support\Facades\Config; use Illuminate\Support\Str; use Spatie\Translatable\Events\TranslationHasBeenSet; use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 6dd9512..24621d1 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -303,7 +303,7 @@ public function it_will_throw_an_exception_when_trying_to_translate_an_untransla /** @test */ public function it_is_compatible_with_accessors_on_non_translatable_attributes() { - $testModel = new class() extends TestModel { + $testModel = new class () extends TestModel { public function getOtherFieldAttribute(): string { return 'accessorName'; @@ -316,7 +316,7 @@ public function getOtherFieldAttribute(): string /** @test */ public function it_can_use_accessors_on_translated_attributes() { - $testModel = new class() extends TestModel { + $testModel = new class () extends TestModel { public function getNameAttribute($value): string { return "I just accessed {$value}"; @@ -331,7 +331,7 @@ public function getNameAttribute($value): string /** @test */ public function it_can_use_mutators_on_translated_attributes() { - $testModel = new class() extends TestModel { + $testModel = new class () extends TestModel { public function setNameAttribute($value) { $this->attributes['name'] = "I just mutated {$value}"; @@ -399,7 +399,7 @@ public function it_can_check_if_an_attribute_has_translation() /** @test */ public function it_can_correctly_set_a_field_when_a_mutator_is_defined() { - $testModel = (new class() extends TestModel { + $testModel = (new class () extends TestModel { public function setNameAttribute($value) { $this->attributes['name'] = "I just mutated {$value}"; @@ -415,7 +415,7 @@ public function setNameAttribute($value) /** @test */ public function it_can_set_multiple_translations_when_a_mutator_is_defined() { - $testModel = (new class() extends TestModel { + $testModel = (new class () extends TestModel { public function setNameAttribute($value) { $this->attributes['name'] = "I just mutated {$value}"; @@ -459,7 +459,7 @@ public function it_can_set_multiple_translations_on_field_when_a_mutator_is_defi /** @test */ public function it_can_translate_a_field_based_on_the_translations_of_another_one() { - $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); @@ -489,7 +489,7 @@ public function setOtherFieldAttribute($value, $locale = 'en') /** @test */ public function it_handle_null_value_from_database() { - $testModel = (new class() extends TestModel { + $testModel = (new class () extends TestModel { public function setAttributesExternally(array $attributes) { $this->attributes = $attributes; @@ -676,7 +676,4 @@ public function it_will_return_default_fallback_locale_translation_when_getting_ $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); } - - - } From b5fc9bc5cc0dedb931fb75521786f0e99495f4dc Mon Sep 17 00:00:00 2001 From: freek Date: Thu, 13 Jan 2022 12:13:49 +0100 Subject: [PATCH 070/229] wip --- composer.json | 2 +- tests/EventTest.php | 10 ++++++---- tests/TranslatableTest.php | 27 +++++++++++++-------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index c324b14..294a66d 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^8.0|^9.0", + "illuminate/database": "^9.0", "illuminate/support": "^8.0|^9.0", "spatie/laravel-package-tools": "^1.9" }, diff --git a/tests/EventTest.php b/tests/EventTest.php index 91e385d..20fe606 100644 --- a/tests/EventTest.php +++ b/tests/EventTest.php @@ -2,25 +2,27 @@ namespace Spatie\Translatable\Test; +use Illuminate\Support\Facades\Event; use Spatie\Translatable\Events\TranslationHasBeenSet; class EventTest extends TestCase { - /** @var \Spatie\Translatable\Test\TestModel */ - protected $testModel; + protected TestModel $testModel; public function setUp(): void { parent::setUp(); + Event::fake(); + $this->testModel = new TestModel(); } /** @test */ public function it_will_fire_an_event_when_a_translation_has_been_set() { - $this->expectsEvents(TranslationHasBeenSet::class); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); + + Event::assertDispatched(TranslationHasBeenSet::class); } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 6dd9512..8113d12 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -6,8 +6,7 @@ class TranslatableTest extends TestCase { - /** @var \Spatie\Translatable\Test\TestModel */ - protected $testModel; + protected TestModel $testModel; public function setUp(): void { @@ -19,8 +18,8 @@ public function setUp(): void /** @test */ public function it_will_return_package_fallback_locale_translation_when_getting_an_unknown_locale() { - $this->app['config']->set('app.fallback_locale', 'nl'); - $this->app['config']->set('translatable.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'nl'); + config()->set('translatable.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -31,7 +30,7 @@ public function it_will_return_package_fallback_locale_translation_when_getting_ /** @test */ public function it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale() { - $this->app['config']->set('app.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -42,7 +41,7 @@ public function it_will_return_default_fallback_locale_translation_when_getting_ /** @test */ public function it_provides_a_flog_to_not_return_fallback_locale_translation_when_getting_an_unknown_locale() { - $this->app['config']->set('app.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -53,7 +52,7 @@ public function it_provides_a_flog_to_not_return_fallback_locale_translation_whe /** @test */ public function it_will_return_fallback_locale_translation_when_getting_an_unknown_locale_and_fallback_is_true() { - $this->app['config']->set('app.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -64,8 +63,8 @@ public function it_will_return_fallback_locale_translation_when_getting_an_unkno /** @test */ public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_not_set() { - $this->app['config']->set('app.fallback_locale', ''); - $this->app['config']->set('translatable.fallback_locale', ''); + config()->set('app.fallback_locale', ''); + config()->set('translatable.fallback_locale', ''); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -76,8 +75,8 @@ public function it_will_return_an_empty_string_when_getting_an_unknown_locale_an /** @test */ public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_empty() { - $this->app['config']->set('app.fallback_locale', ''); - $this->app['config']->set('translatable.fallback_locale', ''); + config()->set('app.fallback_locale', ''); + config()->set('translatable.fallback_locale', ''); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -521,7 +520,7 @@ public function it_can_get_all_translations() /** @test */ public function it_will_return_fallback_locale_translation_when_getting_an_empty_translation_from_the_locale() { - $this->app['config']->set('app.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->setTranslation('name', 'nl', null); @@ -542,7 +541,7 @@ public function it_will_return_correct_translation_value_if_value_is_set_to_zero /** @test */ public function it_will_not_return_fallback_value_if_value_is_set_to_zero() { - $this->app['config']->set('app.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'en', '1'); $this->testModel->setTranslation('name', 'nl', '0'); @@ -554,7 +553,7 @@ public function it_will_not_return_fallback_value_if_value_is_set_to_zero() /** @test */ public function it_will_not_remove_zero_value_of_other_locale_in_database() { - $this->app['config']->set('app.fallback_locale', 'en'); + config()->set('app.fallback_locale', 'en'); $this->testModel->setTranslation('name', 'nl', '0'); $this->testModel->setTranslation('name', 'en', '1'); From 4567de39c483f7e43dddab9b8cb657796b139fd2 Mon Sep 17 00:00:00 2001 From: freek Date: Thu, 13 Jan 2022 12:15:07 +0100 Subject: [PATCH 071/229] wip --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 294a66d..c324b14 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^9.0", + "illuminate/database": "^8.0|^9.0", "illuminate/support": "^8.0|^9.0", "spatie/laravel-package-tools": "^1.9" }, From a90b57cb9781bbe4c7982d6d2d0cca1d5cd965f1 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Thu, 13 Jan 2022 11:17:24 +0000 Subject: [PATCH 072/229] Update CHANGELOG --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eb91ce..ee36669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 5.2.0 - 2022-01-13 + +- support Laravel 9 + ## 5.0.3 - 2021-10-04 - solve the string value issue in filterTranslations method (#300) @@ -134,51 +138,67 @@ All notable changes to `laravel-translatable` will be documented in this file - add support for Laravel 5.7 ## 2.2.0 - 2018-03-09 + - made it possible to get all translations in one go ## 2.1.5 - 2018-02-28 + - better handling of `null` values ## 2.1.4 - 2018-02-08 + - add support for L5.6 ## 2.1.3 - 2018-01-24 + - make locale handling more flexible ## 2.1.2 - 2017-12-24 + - fix for using translations within translations ## 2.1.1 - 2017-12-20 + - fix event `key` attribute - fix support for mutators ## 2.1.0 - 2017-09-21 + - added support for setting a translation directly through the property ## 2.0.0 - 2017-08-30 + - added support for Laravel 5.5, dropped support for all older versions - rename config file from `laravel-translatable` to `translatable` ## 1.3.0 - 2017-06-12 + - add `forgetAllTranslations` ## 1.2.2 - 2016-01-27 + - improve support for fallback locale ## 1.2.1 - 2016-01-23 + - improve compatibility for Laravel 5.4 ## 1.2.0 - 2016-01-23 + - add compatibility for Laravel 5.4 ## 1.1.2 - 2016-10-02 + - made `isTranslatableAttribute` public ## 1.1.1 - 2016-08-24 + - add L5.3 compatibility ## 1.1.0 - 2016-05-02 + - added support for a fallback locale ## 1.0.0 - 2016-04-10 + - initial release From 7ef50bfd67ed3cd50c26d94c49e0bad234046168 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 14:44:32 +0100 Subject: [PATCH 073/229] V6 (#334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Find missing translation keys with fallback callback system (#328) * init fallback callback * add tests based on mockery * quick rephrasing * better hint * quickfix * switch from handler class to facade that user has to customize in a provider * let the fallback callback returns a string that will be used as the translation * quickfix import * Replace phpunit assertions with Laravel Storage Fake proper API * make fallback setup easier by removing config and add facade parameters instead * drop unused interface * Fix styling * wip * Fix styling * wip * Fix styling * Changing the way to populate setTranslation (#313) When model hasSetMutator, repopulating $value at setTranslation will not work with json encoded value, as it will treat the value as a string value. force the value to be retrieved via getTranslations method again to force convert json string into valid arrays. * Add 'forgetTranslations' method (#302) * Fix styling * wip * wip Co-authored-by: Arnaud Becher Co-authored-by: freekmurze Co-authored-by: Jason Xie Co-authored-by: Günther Debrauwer --- .gitattributes | 4 +- .github/workflows/run-tests.yml | 6 +- .gitignore | 1 - README.md | 294 +----------------- composer.json | 16 +- config/translatable.php | 15 - docs/_index.md | 6 + docs/about-us.md | 10 + docs/avanced-usage/_index.md | 6 + docs/avanced-usage/available-events.md | 25 ++ .../customize-the-toarray-method.md | 27 ++ docs/basic-usage/_index.md | 6 + .../getting-and-settings-translations.md | 111 +++++++ .../handling-missing-translations.md | 98 ++++++ docs/basic-usage/querying-translations.md | 4 + docs/basic-usage/removing-translations.md | 28 ++ docs/basic-usage/replacing-translations.md | 24 ++ docs/basic-usage/validating-translations.md | 7 + docs/changelog.md | 6 + docs/installation-setup.md | 31 ++ docs/introduction.md | 19 ++ docs/questions-issues.md | 8 + docs/requirements.md | 8 + docs/support-us.md | 8 + docs/upgrading.md | 15 + ...Set.php => TranslationHasBeenSetEvent.php} | 2 +- src/Facades/Translatable.php | 16 + src/HasTranslations.php | 75 ++++- src/Translatable.php | 33 ++ src/TranslatableServiceProvider.php | 9 +- tests/EventTest.php | 4 +- tests/TranslatableTest.php | 162 +++++++++- 32 files changed, 731 insertions(+), 353 deletions(-) delete mode 100644 config/translatable.php create mode 100644 docs/_index.md create mode 100644 docs/about-us.md create mode 100644 docs/avanced-usage/_index.md create mode 100644 docs/avanced-usage/available-events.md create mode 100644 docs/avanced-usage/customize-the-toarray-method.md create mode 100644 docs/basic-usage/_index.md create mode 100644 docs/basic-usage/getting-and-settings-translations.md create mode 100644 docs/basic-usage/handling-missing-translations.md create mode 100644 docs/basic-usage/querying-translations.md create mode 100644 docs/basic-usage/removing-translations.md create mode 100644 docs/basic-usage/replacing-translations.md create mode 100644 docs/basic-usage/validating-translations.md create mode 100644 docs/changelog.md create mode 100644 docs/installation-setup.md create mode 100644 docs/introduction.md create mode 100644 docs/questions-issues.md create mode 100644 docs/requirements.md create mode 100644 docs/support-us.md create mode 100644 docs/upgrading.md rename src/Events/{TranslationHasBeenSet.php => TranslationHasBeenSetEvent.php} (88%) create mode 100644 src/Facades/Translatable.php create mode 100644 src/Translatable.php diff --git a/.gitattributes b/.gitattributes index b263871..1c2fc12 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,7 +4,7 @@ # Ignore all test and documentation with "export-ignore". /.gitattributes export-ignore /.gitignore export-ignore -/.travis.yml export-ignore /phpunit.xml.dist export-ignore -/.scrutinizer.yml export-ignore /tests export-ignore +/docs export-ignore +php_cs.dist.php export-ignore diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f52c5a3..8eb2671 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,14 +9,12 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.1 8.0] - laravel: [9.*, 8.*] + php: [8.1, 8.0] + laravel: [9.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 9.* testbench: 7.* - - laravel: 8.* - testbench: 6.23 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/.gitignore b/.gitignore index 8d8e31e..93febc6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build composer.lock -docs vendor .phpunit.result.cache .php-cs-fixer.cache diff --git a/README.md b/README.md index d5125b8..8e3d02c 100644 --- a/README.md +++ b/README.md @@ -32,299 +32,9 @@ We invest a lot of resources into creating [best in class open source packages]( We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). -## Installation +## Documentation -You can install the package via composer: - -```bash -composer require spatie/laravel-translatable -``` - -If you want to have another fallback_locale than the app fallback locale (see `config/app.php`), you could publish the config file: -```bash -php artisan vendor:publish --provider="Spatie\Translatable\TranslatableServiceProvider" -``` - -This is the contents of the published file: -```php -return [ - 'fallback_locale' => null, - 'fallback_any' => false, -]; -``` - -Sometimes it is favored to return any translation if neigher the translation for the prefered locale nor the fallback locale are set. To do so, set fallback_any in the config to true. - -## Making a model translatable - -The required steps to make a model translatable are: - -- First, you need to add the `Spatie\Translatable\HasTranslations`-trait. -- Next, you should create a public property `$translatable` which holds an array with all the names of attributes you wish to make translatable. -- Finally, you should make sure that all translatable attributes are set to the `text`-datatype in your database. If your database supports `json`-columns, use that. - -Here's an example of a prepared model: - -```php -use Illuminate\Database\Eloquent\Model; -use Spatie\Translatable\HasTranslations; - -class NewsItem extends Model -{ - use HasTranslations; - - public $translatable = ['name']; -} -``` - -### Available methods - -#### Getting a translation - -The easiest way to get a translation for the current locale is to just get the property for the translated attribute. -For example (given that `name` is a translatable attribute): - -```php -$newsItem->name; -``` - -You can also use this method: - -```php -public function getTranslation(string $attributeName, string $locale, bool $useFallbackLocale = true) : string -``` - -This function has an alias named `translate`. - -#### Getting all translations - -You can get all translations by calling `getTranslations()` without an argument: - -```php -$newsItem->getTranslations(); -``` - -Or you can use the accessor - -```php -$yourModel->translations -``` - -#### Setting a translation -The easiest way to set a translation for the current locale is to just set the property for a translatable attribute. -For example (given that `name` is a translatable attribute): - -```php -$newsItem->name = 'New translation'; -``` - -Also you can set translations with - -```php -$newItem->name = ['en' => 'myName', 'nl' => 'Naam in het Nederlands']; -``` - -To set a translation for a specific locale you can use this method: - -``` php -public function setTranslation(string $attributeName, string $locale, string $value) -``` - -To actually save the translation, don't forget to save your model. - -```php -$newsItem->setTranslation('name', 'en', 'Updated name in English'); - -$newsItem->save(); -``` - -#### Validation - -- if you want to validate an attribute for uniqueness before saving/updating the db, you might want to have a look at [laravel-unique-translation](https://github.com/codezero-be/laravel-unique-translation) which is made specifically for *laravel-translatable*. - -#### Forgetting a translation - -You can forget a translation for a specific field: -``` php -public function forgetTranslation(string $attributeName, string $locale) -``` - -You can forget all translations for a specific locale: -``` php -public function forgetAllTranslations(string $locale) -``` - -#### Getting all translations in one go - -``` php -public function getTranslations(string $attributeName): array -``` - -#### Getting the specified translations in one go - -You can filter the translations by passing an array of locales: -``` php -public function getTranslations(string $attributeName, array $allowedLocales): array -``` - -Here's an example: - -```php -$translations = [ - 'en' => 'Hello', - 'fr' => 'Bonjour', - 'de' => 'Hallo', -]; - -$newsItem->setTranslations('hello', $translations); -$newsItem->getTranslations('hello', ['en', 'fr']); // returns ['en' => 'Hello', 'fr' => 'Bonjour'] -``` - - -#### Setting translations in one go - -``` php -public function setTranslations(string $attributeName, array $translations) -``` - -Here's an example: - -``` php -$translations = [ - 'en' => 'Name in English', - 'nl' => 'Naam in het Nederlands' -]; - -$newsItem->setTranslations('name', $translations); -``` - -#### Replace translations in one go - -You can replace all the translations for a single key using this method: - -```php -public function replaceTranslations(string $key, array $translations) -``` - -Here's an example: - -```php -$translations = ['en' => 'hello', 'es' => 'hola']; - -$newsItem->setTranslations('hello', $translations); -$newsItem->getTranslations(); // ['en' => 'hello', 'es' => 'hola'] - -$newTranslations = ['en' => 'hello']; - -$newsItem->replaceTranslations('hello', $newTranslations); -$newsItem->getTranslations(); // ['en' => 'hello'] -``` - -#### Setting the model locale -The default locale used to translate models is the application locale, -however it can sometimes be handy to use a custom locale. - -To do so, you can use `setLocale` on a model instance. -``` php -$newsItem = NewsItem::firstOrFail()->setLocale('fr'); - -// Any properties on this model will automaticly be translated in French -$newsItem->name; // Will return `fr` translation -$newsItem->name = 'Actualité'; // Will set the `fr` translation -``` - -Alternatively, you can use `usingLocale` static method: -``` php -// Will automatically set the `fr` translation -$newsItem = NewsItem::usingLocale('fr')->create([ - 'name' => 'Actualité', -]); -``` - -### Events - -#### TranslationHasBeenSet -Right after calling `setTranslation` the `Spatie\Translatable\Events\TranslationHasBeenSet`-event will be fired. - -It has these properties: -```php -/** @var \Illuminate\Database\Eloquent\Model */ -public $model; - -/** @var string */ -public $attributeName; - -/** @var string */ -public $locale; - -public $oldValue; -public $newValue; -``` - -### Creating models - -You can immediately set translations when creating a model. Here's an example: -```php -NewsItem::create([ - 'name' => [ - 'en' => 'Name in English', - 'nl' => 'Naam in het Nederlands' - ], -]); -``` - -### Querying translatable attributes - -If you're using MySQL 5.7 or above, it's recommended that you use the json data type for housing translations in the db. -This will allow you to query these columns like this: - -```php -NewsItem::where('name->en', 'Name in English')->get(); -``` - -Or if you're using MariaDB 10.2.3 or above : -```php -NewsItem::whereRaw("JSON_EXTRACT(name, '$.en') = 'Name in English'")->get(); -``` - -### Automatically display the right translation when displaying model - -Many times models using `HasTranslation` trait may be directly returned as response content. -In this scenario, and similar ones, the `toArray()` method on `Model` class is called under the hood to serialize your model; it accesses directly the $attributes field to perform the serialization, bypassing the translatable feature (which is based on accessors and mutators) and returning the text representation of the stored JSON instead of the translated value. - -The best way to make your model automatically return translated fields is to wrap `Spatie\Translatable\HasTranslations` trait into a custom trait which overrides the `toArray()` method to automatically replace all translatable fields content with their translated value, like in the following example, and use it instead of the default one. - -``` php -namespace App\Traits; -use Spatie\Translatable\HasTranslations as BaseHasTranslations; -trait HasTranslations -{ - use BaseHasTranslations; - /** - * Convert the model instance to an array. - * - * @return array - */ - public function toArray() - { - $attributes = parent::toArray(); - foreach ($this->getTranslatableAttributes() as $field) { - $attributes[$field] = $this->getTranslation($field, \App::getLocale()); - } - return $attributes; - } -} -``` - -## Changelog - -Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. - -## Upgrading - -### From v2 to v3 - -In most cases you can upgrade without making any changes to your codebase at all. `v3` introduced a `translations` accessor on your models. If you already had one defined on your model, you'll need to rename it. +All documentation is available [on our documentation site](https://spatie.be/docs/laravel-translatable). ## Testing diff --git a/composer.json b/composer.json index c324b14..16a6f48 100644 --- a/composer.json +++ b/composer.json @@ -24,22 +24,17 @@ "email": "sebastian@spatie.be", "homepage": "https://spatie.be/", "role": "Developer" - }, - { - "name": "Mohamed Said", - "email": "theMohamedSaid@gmail.com", - "role": "Original idea" } ], "require": { "php": "^8.0", - "illuminate/database": "^8.0|^9.0", - "illuminate/support": "^8.0|^9.0", - "spatie/laravel-package-tools": "^1.9" + "illuminate/database": "^9.0", + "illuminate/support": "^9.0", + "spatie/laravel-package-tools": "^1.11" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^6.23|^7.0" + "orchestra/testbench": "^7.0" }, "autoload": { "psr-4": { @@ -63,6 +58,9 @@ "providers": [ "Spatie\\Translatable\\TranslatableServiceProvider" ] + }, + "aliases": { + "Translatable": "Spatie\\Translatable\\Facades\\Translatable" } }, "minimum-stability": "dev", diff --git a/config/translatable.php b/config/translatable.php deleted file mode 100644 index 02ec12c..0000000 --- a/config/translatable.php +++ /dev/null @@ -1,15 +0,0 @@ - null, - - /* - * If a translation has not been set for a given locale and the fallback locale, - * any other locale will be chosen instead. - */ - 'fallback_any' => false, -]; diff --git a/docs/_index.md b/docs/_index.md new file mode 100644 index 0000000..617010b --- /dev/null +++ b/docs/_index.md @@ -0,0 +1,6 @@ +--- +title: v1 +slogan: Translatable Eloquent Models +githubUrl: https://github.com/spatie/laravel-translatable +branch: main +--- diff --git a/docs/about-us.md b/docs/about-us.md new file mode 100644 index 0000000..4589e99 --- /dev/null +++ b/docs/about-us.md @@ -0,0 +1,10 @@ +--- +title: About us +--- + +[Spatie](https://spatie.be) is a webdesign agency based in Antwerp, Belgium. + +Open source software is used in all projects we deliver. Laravel, Nginx, Ubuntu are just a few +of the free pieces of software we use every single day. For this, we are very grateful. +When we feel we have solved a problem in a way that can help other developers, +we release our code as open source software [on GitHub](https://spatie.be/open-source). diff --git a/docs/avanced-usage/_index.md b/docs/avanced-usage/_index.md new file mode 100644 index 0000000..8395637 --- /dev/null +++ b/docs/avanced-usage/_index.md @@ -0,0 +1,6 @@ +--- +title: Advanced usage +weight: 2 +--- + + diff --git a/docs/avanced-usage/available-events.md b/docs/avanced-usage/available-events.md new file mode 100644 index 0000000..3dc0839 --- /dev/null +++ b/docs/avanced-usage/available-events.md @@ -0,0 +1,25 @@ +--- +title: Available events +weight: 1 +--- + +Right after calling `setTranslation` the `Spatie\Translatable\Events\TranslationHasBeenSetEvent`-event will be fired. + +This is how that event looks like: + +```php +namespace Spatie\Translatable\Events; + +class TranslationHasBeenSetEvent +{ + public function __construct( + public mixed $model, + public string $key, + public string $locale, + public mixed $oldValue, + public mixed $newValue, + ) { + // + } +} +``` diff --git a/docs/avanced-usage/customize-the-toarray-method.md b/docs/avanced-usage/customize-the-toarray-method.md new file mode 100644 index 0000000..0b50843 --- /dev/null +++ b/docs/avanced-usage/customize-the-toarray-method.md @@ -0,0 +1,27 @@ +--- +title: Customize the toArray method +weight: 1 +--- + +In many cases, the `toArray()` method on `Model` the class is called under the hood to serialize your model. + +To customize for all your models what should get returned for the translatable attributes you could wrap the`Spatie\Translatable\HasTranslations` trait into a custom trait and overrides the `toArray()` method. + +```php +namespace App\Traits; +use Spatie\Translatable\HasTranslations as BaseHasTranslations; + +trait HasTranslations +{ + use BaseHasTranslations; + + public function toArray() + { + $attributes = parent::toArray(); + foreach ($this->getTranslatableAttributes() as $field) { + $attributes[$field] = $this->getTranslation($field, \App::getLocale()); + } + return $attributes; + } +} +``` diff --git a/docs/basic-usage/_index.md b/docs/basic-usage/_index.md new file mode 100644 index 0000000..8885cab --- /dev/null +++ b/docs/basic-usage/_index.md @@ -0,0 +1,6 @@ +--- +title: Basic usage +weight: 1 +--- + + diff --git a/docs/basic-usage/getting-and-settings-translations.md b/docs/basic-usage/getting-and-settings-translations.md new file mode 100644 index 0000000..d132757 --- /dev/null +++ b/docs/basic-usage/getting-and-settings-translations.md @@ -0,0 +1,111 @@ +--- +title: Getting and setting translations +weight: 1 +--- + +First, you must prepare your model as instructed in [the installation instructions](/docs/laravel-translatable/v6/installation-setup). + +## Setting a translation + +The easiest way to set a translation for the current locale is to just set the property for a translatable attribute. + +Here's an example, given that `name` is a translatable attribute: + +```php +$newsItem->name = 'New translation'; +``` + +To actually save the translation, don't forget to save your model. + +```php +$newsItem->name = 'New translation' +$newsItem->save(); +``` + +You can immediately set translations when creating a model. + +```php +NewsItem::create([ + 'name' => [ + 'en' => 'Name in English', + 'nl' => 'Naam in het Nederlands' + ], +]); +``` + +To set a translation for a specific locale you can use this method: + +```php +public function setTranslation(string $attributeName, string $locale, string $value) +``` + +You can set translations for multiple languages with + +```php +$translations = ['en' => 'hello', 'es' => 'hola']; +$newItem->name = $translations; + +// alternatively, use the `setTranslations` method + +$newsItem->setTranslations('hello', $translations); + +$newItem->save(); +``` + +## Getting a translation + +The easiest way to get a translation for the current locale is to just get the property for the translated attribute. +For example (given that `name` is a translatable attribute): + +```php +$newsItem->name; +``` + +You can also use this method: + +```php +public function getTranslation(string $attributeName, string $locale, bool $useFallbackLocale = true) : string +``` + +This function has an alias named `translate`. + + +### Getting all translations + +You can get all translations by calling `getTranslations()` without an argument: + +```php +$newsItem->getTranslations(); +``` + +Or you can use the accessor: + +```php +$yourModel->translations +``` + +The methods above will give you back an array that holds all translations, for example: + +```php +$newsItem->getTranslations('name'); +// returns ['en' => 'Name in English', 'nl' => 'Naam in het Nederlands'] +``` + +The method above returns, all locales. If you only want specific locales, pass that to the second argument of `getTranslations`. + +```php +public function getTranslations(string $attributeName, array $allowedLocales): array +``` + +Here's an example: + +```php +$translations = [ + 'en' => 'Hello', + 'fr' => 'Bonjour', + 'de' => 'Hallo', +]; + +$newsItem->setTranslations('hello', $translations); +$newsItem->getTranslations('hello', ['en', 'fr']); // returns ['en' => 'Hello', 'fr' => 'Bonjour'] +``` diff --git a/docs/basic-usage/handling-missing-translations.md b/docs/basic-usage/handling-missing-translations.md new file mode 100644 index 0000000..98359bb --- /dev/null +++ b/docs/basic-usage/handling-missing-translations.md @@ -0,0 +1,98 @@ +--- +title: Handling missing translations weight: 7 +--- + +Sometimes your model doesn't have a requested translation. Using the fallback functionality, you can decide what should +happen. + +To set up fallback you need to call static method on the facade `Spatie\Translatable\Facades\Translatable`. Typically, +you would put this +in [a service provider of your own](https://laravel.com/docs/8.x/providers#writing-service-providers): + +```php + // typically, in a service provider + + use Spatie\Translatable\Facades\Translatable; + + Translatable::fallback( + ... + ); +``` + +### Falling back to a specific locale + +If you want to have another `fallback_locale` than the app fallback locale (see `config/app.php`), you should pass it +as `$fallbackLocale` parameter: + +```php + use Spatie\Translatable\Facades\Translatable; + + Translatable::fallback( + fallbackLocale: 'fr', + ); +``` + +### Falling back to any locale + +Sometimes it is favored to return any translation if neither the translation for the preferred locale nor the fallback +locale are set. To do so, just pass `$fallbackAny` to true: + +```php + use Spatie\Translatable\Facades\Translatable; + + Translatable::fallback( + fallbackAny: true, + ); +``` + +### Customize fallbacks + +You can set up a fallback callback that is called when a translation key is missing/not found. It just lets you execute +some custom code like logging something or contact a remote service for example. + +You have to register some code you want to run, by passing a closure to `$missingKeyCallback`. + +Here's an example with a closure that logs a warning with some info about the missing translation key: + +```php +use Spatie\Translatable\Facades\Translatable; +use Illuminate\Support\Facades\Log; + +Translatable::fallback(missingKeyCallback: function ( + Model $model, + string $translationKey, + string $locale, + string $fallbackTranslation, + string $fallbackLocale, +) { + + // do something (ex: logging, alerting, etc) + + Log::warning('Some translation key is missing from an eloquent model', [ + 'key' => $translationKey, + 'locale' => $locale, + 'fallback_locale' => $fallbackLocale, + 'fallback_translation' => $fallbackTranslation, + 'model_id' => $model->id, + 'model_class' => get_class($model), + ]); +}); +``` + +If the closure returns a string, it will be used as the fallback translation: + +```php +use Spatie\Translatable\Facades\Translatable; +use App\Service\MyRemoteTranslationService; + +Translatable::fallback(missingKeyCallback: function ( + Model $model, + string $translationKey, + string $locale, + string $fallbackTranslation, + string $fallbackLocale + ) { + + return MyRemoteTranslationService::getAutomaticTranslation($fallbackTranslation, $fallbackLocale, $locale); +}); +``` diff --git a/docs/basic-usage/querying-translations.md b/docs/basic-usage/querying-translations.md new file mode 100644 index 0000000..44aa012 --- /dev/null +++ b/docs/basic-usage/querying-translations.md @@ -0,0 +1,4 @@ +--- +title: Querying translations +weight: 5 +--- diff --git a/docs/basic-usage/removing-translations.md b/docs/basic-usage/removing-translations.md new file mode 100644 index 0000000..3e205c2 --- /dev/null +++ b/docs/basic-usage/removing-translations.md @@ -0,0 +1,28 @@ +--- +title: Removing translations +weight: 2 +--- + +You can forget a translation for a specific field using the `forgetTranslation` function: + +```php +public function forgetTranslation(string $attributeName, string $locale) +``` + +Here's an example: + +```php +$newsItem->forgetTranslation('name', 'nl'); +``` + +You can forget all translations for a specific locale: + +```php +public function forgetAllTranslations(string $locale) +``` + +Here's an example: + +```php +$newsItem->forgetTranslation('name'); +``` diff --git a/docs/basic-usage/replacing-translations.md b/docs/basic-usage/replacing-translations.md new file mode 100644 index 0000000..273e5ed --- /dev/null +++ b/docs/basic-usage/replacing-translations.md @@ -0,0 +1,24 @@ +--- +title: Replacing translations +weight: 3 +--- + +You can replace all the translations for a single key using this method: + +```php +public function replaceTranslations(string $key, array $translations) +``` + +Here's an example: + +```php +$translations = ['en' => 'hello', 'es' => 'hola']; + +$newsItem->setTranslations('hello', $translations); +$newsItem->getTranslations(); // ['en' => 'hello', 'es' => 'hola'] + +$newTranslations = ['en' => 'hello']; + +$newsItem->replaceTranslations('hello', $newTranslations); +$newsItem->getTranslations(); // ['en' => 'hello'] +``` diff --git a/docs/basic-usage/validating-translations.md b/docs/basic-usage/validating-translations.md new file mode 100644 index 0000000..6afd4b6 --- /dev/null +++ b/docs/basic-usage/validating-translations.md @@ -0,0 +1,7 @@ +--- +title: Validation translations +weight: 6 +--- + +If you want to validate an attribute for uniqueness before saving/updating the db, you might want to have a look at [laravel-unique-translation](https://github.com/codezero-be/laravel-unique-translation) which is made specifically for laravel-translatable. + diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..bd03745 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,6 @@ +--- +title: Changelog +weight: 6 +--- + +All notable changes to laravel-translatable are documented [on GitHub](https://github.com/spatie/laravel-translatable/blob/main/CHANGELOG.md) diff --git a/docs/installation-setup.md b/docs/installation-setup.md new file mode 100644 index 0000000..0434a55 --- /dev/null +++ b/docs/installation-setup.md @@ -0,0 +1,31 @@ +--- +title: Installation & setup +weight: 4 +--- + +You can install the package via composer: + +```bash +composer require spatie/laravel-translatable +``` + +## Making a model translatable + +The required steps to make a model translatable are: + +- First, you need to add the `Spatie\Translatable\HasTranslations`-trait. +- Next, you should create a public property `$translatable` which holds an array with all the names of attributes you wish to make translatable. +- Finally, you should make sure that all translatable attributes are set to the `json`-datatype in your database. If your database doesn't support `json`-columns, use `text`. + +Here's an example of a prepared model: + +```php +use Illuminate\Database\Eloquent\Model; +use Spatie\Translatable\HasTranslations; + +class NewsItem extends Model +{ + use HasTranslations; + + public $translatable = ['name']; +} diff --git a/docs/introduction.md b/docs/introduction.md new file mode 100644 index 0000000..2f1edca --- /dev/null +++ b/docs/introduction.md @@ -0,0 +1,19 @@ +This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. + +Once the trait is installed on the model you can do these things: + +```php +$newsItem = new NewsItem; // This is an Eloquent model +$newsItem + ->setTranslation('name', 'en', 'Name in English') + ->setTranslation('name', 'nl', 'Naam in het Nederlands') + ->save(); + +$newsItem->name; // Returns 'Name in English' given that the current app locale is 'en' +$newsItem->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands' + +app()->setLocale('nl'); + +$newsItem->name; // Returns 'Naam in het Nederlands' +``` + diff --git a/docs/questions-issues.md b/docs/questions-issues.md new file mode 100644 index 0000000..bcbfda1 --- /dev/null +++ b/docs/questions-issues.md @@ -0,0 +1,8 @@ +--- +title: Questions and issues +weight: 5 +--- + +Find yourself stuck using the package? Found a bug? Do you have general questions or suggestions for improving the health library? Feel free to [create an issue on GitHub](https://github.com/spatie/laravel-translatable/issues), we'll try to address it as soon as possible. + +If you've found a bug regarding security please mail [freek@spatie.be](mailto:freek@spatie.be) instead of using the issue tracker. diff --git a/docs/requirements.md b/docs/requirements.md new file mode 100644 index 0000000..f88dc0e --- /dev/null +++ b/docs/requirements.md @@ -0,0 +1,8 @@ +--- +title: Requirements +weight: 3 +--- + +The laravel-translatable package requires **PHP 8.0+**, **Laravel 9+**. + +This package uses `json` columns. MySQL 5.7 or higher is required. diff --git a/docs/support-us.md b/docs/support-us.md new file mode 100644 index 0000000..90f5c27 --- /dev/null +++ b/docs/support-us.md @@ -0,0 +1,8 @@ +--- +title: Support us +weight: 2 +--- + +We invest a lot of resources into creating our [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). + +We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). diff --git a/docs/upgrading.md b/docs/upgrading.md new file mode 100644 index 0000000..665a6a5 --- /dev/null +++ b/docs/upgrading.md @@ -0,0 +1,15 @@ +--- +title: Upgrading +weight: 3 +--- + +### From v5 to v6 + +The config file has been removed. You can now define a fallback locale, set `fallBackAny` and handle custom behaviour for missing translations, via `Translatable::fallback()`. Take a look in the readme to learn how to specify the fallback behaviour you want. + +The `TranslationHasBeenSet` event has been renamed to `TranslationHasBeenSetEvent`. + +### From v2 to v3 + +In most cases you can upgrade without making any changes to your codebase at all. `v3` introduced a `translations` accessor on your models. If you already had one defined on your model, you'll need to rename it. + diff --git a/src/Events/TranslationHasBeenSet.php b/src/Events/TranslationHasBeenSetEvent.php similarity index 88% rename from src/Events/TranslationHasBeenSet.php rename to src/Events/TranslationHasBeenSetEvent.php index 5051043..4fa350d 100644 --- a/src/Events/TranslationHasBeenSet.php +++ b/src/Events/TranslationHasBeenSetEvent.php @@ -2,7 +2,7 @@ namespace Spatie\Translatable\Events; -class TranslationHasBeenSet +class TranslationHasBeenSetEvent { public function __construct( public mixed $model, diff --git a/src/Facades/Translatable.php b/src/Facades/Translatable.php new file mode 100644 index 0000000..992c3bf --- /dev/null +++ b/src/Facades/Translatable.php @@ -0,0 +1,16 @@ +normalizeLocale($key, $locale, $useFallbackLocale); + $normalizedLocale = $this->normalizeLocale($key, $locale, $useFallbackLocale); + + $isKeyMissingFromLocale = ($locale !== $normalizedLocale); $translations = $this->getTranslations($key); - $translation = $translations[$locale] ?? ''; + $translation = $translations[$normalizedLocale] ?? ''; + + $translatableConfig = app(Translatable::class); + + if ($isKeyMissingFromLocale && $translatableConfig->missingKeyCallback) { + try { + $callbackReturnValue = (app(Translatable::class)->missingKeyCallback)($this, $key, $locale, $translation, $normalizedLocale); + if (is_string($callbackReturnValue)) { + $translation = $callbackReturnValue; + } + } catch (Exception) { + //prevent the fallback to crash + } + } if ($this->hasGetMutator($key)) { return $this->mutateAttribute($key, $translation); @@ -78,7 +95,7 @@ public function getTranslations(string $key = null, array $allowedLocales = null return array_filter( json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales), - ARRAY_FILTER_USE_BOTH + ARRAY_FILTER_USE_BOTH, ); } @@ -109,7 +126,7 @@ public function setTranslation(string $key, string $locale, $value): self $this->attributes[$key] = $this->asJson($translations); - event(new TranslationHasBeenSet($this, $key, $locale, $oldValue, $value)); + event(new TranslationHasBeenSetEvent($this, $key, $locale, $oldValue, $value)); return $this; } @@ -118,8 +135,12 @@ public function setTranslations(string $key, array $translations): self { $this->guardAgainstNonTranslatableAttribute($key); - foreach ($translations as $locale => $translation) { - $this->setTranslation($key, $locale, $translation); + if (! empty($translations)) { + foreach ($translations as $locale => $translation) { + $this->setTranslation($key, $locale, $translation); + } + } else { + $this->attributes[$key] = $this->asJson([]); } return $this; @@ -139,6 +160,21 @@ public function forgetTranslation(string $key, string $locale): self return $this; } + public function forgetTranslations(string $key, bool $asNull = false): self + { + $this->guardAgainstNonTranslatableAttribute($key); + + collect($this->getTranslatedLocales($key))->each(function (string $locale) use ($key) { + $this->forgetTranslation($key, $locale); + }); + + if ($asNull) { + $this->attributes[$key] = null; + } + + return $this; + } + public function forgetAllTranslations(string $locale): self { collect($this->getTranslatableAttributes())->each(function (string $attribute) use ($locale) { @@ -195,12 +231,15 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - $fallbackLocale = config('translatable.fallback_locale') ?? config('app.fallback_locale'); + $fallbackConfig = app(Translatable::class); + + $fallbackLocale = $fallbackConfig->fallbackLocale ?? config('app.fallback_locale'); + if (! is_null($fallbackLocale) && in_array($fallbackLocale, $translatedLocales)) { return $fallbackLocale; } - if (! empty($translatedLocales) && config('translatable.fallback_any')) { + if (! empty($translatedLocales) && $fallbackConfig->fallbackAny) { return $translatedLocales[0]; } @@ -247,20 +286,22 @@ public function getTranslatableAttributes(): array : []; } - public function getTranslationsAttribute(): array + public function translations(): Attribute { - return collect($this->getTranslatableAttributes()) - ->mapWithKeys(function (string $key) { - return [$key => $this->getTranslations($key)]; - }) - ->toArray(); + return Attribute::get(function () { + return collect($this->getTranslatableAttributes()) + ->mapWithKeys(function (string $key) { + return [$key => $this->getTranslations($key)]; + }) + ->toArray(); + }); } public function getCasts(): array { return array_merge( parent::getCasts(), - array_fill_keys($this->getTranslatableAttributes(), 'array') + array_fill_keys($this->getTranslatableAttributes(), 'array'), ); } } diff --git a/src/Translatable.php b/src/Translatable.php new file mode 100644 index 0000000..18df5d8 --- /dev/null +++ b/src/Translatable.php @@ -0,0 +1,33 @@ +fallbackLocale = $fallbackLocale; + $this->fallbackAny = $fallbackAny; + $this->missingKeyCallback = $missingKeyCallback; + + return $this; + } +} diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index a289adc..ef8bd33 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -10,7 +10,12 @@ class TranslatableServiceProvider extends PackageServiceProvider public function configurePackage(Package $package): void { $package - ->name('laravel-translatable') - ->hasConfigFile(); + ->name('laravel-translatable'); + } + + public function packageRegistered(): void + { + $this->app->singleton(Translatable::class, fn () => new Translatable()); + $this->app->bind('translatable', Translatable::class); } } diff --git a/tests/EventTest.php b/tests/EventTest.php index 20fe606..79c9213 100644 --- a/tests/EventTest.php +++ b/tests/EventTest.php @@ -3,7 +3,7 @@ namespace Spatie\Translatable\Test; use Illuminate\Support\Facades\Event; -use Spatie\Translatable\Events\TranslationHasBeenSet; +use Spatie\Translatable\Events\TranslationHasBeenSetEvent; class EventTest extends TestCase { @@ -23,6 +23,6 @@ public function it_will_fire_an_event_when_a_translation_has_been_set() { $this->testModel->setTranslation('name', 'en', 'testValue_en'); - Event::assertDispatched(TranslationHasBeenSet::class); + Event::assertDispatched(TranslationHasBeenSetEvent::class); } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index fde9434..9ae470c 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -2,7 +2,9 @@ namespace Spatie\Translatable\Test; +use Illuminate\Support\Facades\Storage; use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; +use Spatie\Translatable\Facades\Translatable; class TranslatableTest extends TestCase { @@ -19,7 +21,9 @@ public function setUp(): void public function it_will_return_package_fallback_locale_translation_when_getting_an_unknown_locale() { config()->set('app.fallback_locale', 'nl'); - config()->set('translatable.fallback_locale', 'en'); + Translatable::fallback( + fallbackLocale: 'en', + ); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -60,11 +64,89 @@ public function it_will_return_fallback_locale_translation_when_getting_an_unkno $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); } + /** @test */ + public function it_will_execute_callback_fallback_when_getting_an_unknown_locale_and_fallback_callback_is_enabled() + { + Storage::fake(); + + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + //something assertable outside the closure + Storage::put("test.txt", "test"); + }); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + + Storage::assertExists("test.txt"); + } + + /** @test */ + public function it_will_use_callback_fallback_return_value_as_translation() + { + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + return "testValue_fallback_callback"; + }); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_fallback_callback', $this->testModel->getTranslationWithFallback('name', 'fr')); + } + + /** @test */ + public function it_wont_use_callback_fallback_return_value_as_translation_if_it_is_not_a_string() + { + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + return 123456; + }); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + } + + /** @test */ + public function it_wont_execute_callback_fallback_when_getting_an_existing_translation() + { + Storage::fake(); + + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + //something assertable outside the closure + Storage::put("test.txt", "test"); + }); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'en')); + + Storage::assertMissing("test.txt"); + } + + /** @test */ + public function it_wont_fail_if_callback_fallback_throw_exception() + { + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + throw new \Exception(); + }); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + } + /** @test */ public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_not_set() { config()->set('app.fallback_locale', ''); - config()->set('translatable.fallback_locale', ''); + + Translatable::fallback( + fallbackLocale: '', + ); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -76,7 +158,10 @@ public function it_will_return_an_empty_string_when_getting_an_unknown_locale_an public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_empty() { config()->set('app.fallback_locale', ''); - config()->set('translatable.fallback_locale', ''); + + Translatable::fallback( + fallbackLocale: '', + ); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); @@ -229,6 +314,52 @@ public function it_can_forget_a_translation() ], $this->testModel->getTranslations('name')); } + /** @test */ + public function it_can_forget_all_translations_of_field() + { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); + + $this->testModel->forgetTranslations('name'); + + $this->assertSame('[]', $this->testModel->getAttributes()['name']); + $this->assertSame([], $this->testModel->getTranslations('name')); + + $this->testModel->save(); + + $this->assertSame('[]', $this->testModel->fresh()->getAttributes()['name']); + $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); + } + + /** @test */ + public function it_can_forget_all_translations_of_field_and_make_field_null() + { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); + + $this->testModel->forgetTranslations('name', true); + + $this->assertNull($this->testModel->getAttributes()['name']); + $this->assertSame([], $this->testModel->getTranslations('name')); + + $this->testModel->save(); + + $this->assertNull($this->testModel->fresh()->getAttributes()['name']); + $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); + } + /** @test */ public function it_can_forget_a_field_with_mutator_translation() { @@ -612,7 +743,10 @@ public function it_can_replace_translations() public function it_can_use_any_locale_if_given_locale_not_set() { config()->set('app.fallback_locale', 'en'); - config()->set('translatable.fallback_any', true); + + Translatable::fallback( + fallbackAny: true, + ); $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); $this->testModel->setTranslation('name', 'de', 'testValue_de'); @@ -626,7 +760,10 @@ public function it_can_use_any_locale_if_given_locale_not_set() public function it_will_return_set_translation_when_fallback_any_set() { config()->set('app.fallback_locale', 'en'); - config()->set('translatable.fallback_any', true); + + Translatable::fallback( + fallbackAny: true, + ); $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); $this->testModel->setTranslation('name', 'de', 'testValue_de'); @@ -640,7 +777,10 @@ public function it_will_return_set_translation_when_fallback_any_set() public function it_will_return_fallback_translation_when_fallback_any_set() { config()->set('app.fallback_locale', 'en'); - config()->set('translatable.fallback_any', true); + + Translatable::fallback( + fallbackAny: true, + ); $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); $this->testModel->setTranslation('name', 'en', 'testValue_en'); @@ -654,7 +794,10 @@ public function it_will_return_fallback_translation_when_fallback_any_set() public function it_provides_a_flog_to_not_return_any_translation_when_getting_an_unknown_locale() { config()->set('app.fallback_locale', 'en'); - config()->set('translatable.fallback_any', true); + + Translatable::fallback( + fallbackAny: true, + ); $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); $this->testModel->setTranslation('name', 'de', 'testValue_de'); @@ -668,7 +811,10 @@ public function it_provides_a_flog_to_not_return_any_translation_when_getting_an public function it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale_with_fallback_any() { config()->set('app.fallback_locale', 'en'); - config()->set('translatable.fallback_any', true); + + Translatable::fallback( + fallbackAny: true, + ); $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); From 0883e920a266d4bd63078e4422714c725ea55c4a Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 14:45:23 +0100 Subject: [PATCH 074/229] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 636ef53..5ccc87c 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -custom: https://spatie.be/open-source/support-us +github: spatie From edcf0c07766ced5a7f8c8246fe071a1dda5cced9 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 14:47:51 +0100 Subject: [PATCH 075/229] wip --- docs/basic-usage/handling-missing-translations.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/basic-usage/handling-missing-translations.md b/docs/basic-usage/handling-missing-translations.md index 98359bb..2a146e4 100644 --- a/docs/basic-usage/handling-missing-translations.md +++ b/docs/basic-usage/handling-missing-translations.md @@ -1,5 +1,6 @@ --- -title: Handling missing translations weight: 7 +title: Handling missing translations +weight: 7 --- Sometimes your model doesn't have a requested translation. Using the fallback functionality, you can decide what should From b4d77917edd126fa7087b55789f3a866401a3664 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 14:49:38 +0100 Subject: [PATCH 076/229] wip --- docs/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_index.md b/docs/_index.md index 617010b..e08acf5 100644 --- a/docs/_index.md +++ b/docs/_index.md @@ -1,5 +1,5 @@ --- -title: v1 +title: v6 slogan: Translatable Eloquent Models githubUrl: https://github.com/spatie/laravel-translatable branch: main From c4c2bef702738f26562b6dc37b66bdac545610e1 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 14:50:51 +0100 Subject: [PATCH 077/229] wip --- docs/introduction.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/introduction.md b/docs/introduction.md index 2f1edca..556000a 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,3 +1,8 @@ +--- +title: Introduction +weight: 1 +--- + This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. Once the trait is installed on the model you can do these things: From 35751b4e68b4e9adb6f0125292331b06bbc5954a Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 7 Mar 2022 13:53:27 +0000 Subject: [PATCH 078/229] Update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee36669..2b0e9be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.0.0 - 2022-03-07 + +- improved fallback customisations +- modernized code base +- drop support for Laravel 8 + ## 5.2.0 - 2022-01-13 - support Laravel 9 From 9ff4e4a87a8eb62042b5e7794fe64974acb3c150 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 14:53:48 +0100 Subject: [PATCH 079/229] wip --- docs/basic-usage/querying-translations.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/basic-usage/querying-translations.md b/docs/basic-usage/querying-translations.md index 44aa012..ed990ea 100644 --- a/docs/basic-usage/querying-translations.md +++ b/docs/basic-usage/querying-translations.md @@ -2,3 +2,15 @@ title: Querying translations weight: 5 --- + +If you're using MySQL 5.7 or above, it's recommended that you use the JSON data type for housing translations in the db. +This will allow you to query these columns like this: + +```php +NewsItem::where('name->en', 'Name in English')->get(); +``` + +Or if you're using MariaDB 10.2.3 or above : +```php +NewsItem::whereRaw("JSON_EXTRACT(name, '$.en') = 'Name in English'")->get(); +``` From d1524d62578b571aee4520d349937f5b0cbe2768 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 15:05:05 +0100 Subject: [PATCH 080/229] Update introduction.md --- docs/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/introduction.md b/docs/introduction.md index 556000a..0ef0ec9 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -8,7 +8,7 @@ This package contains a trait to make Eloquent models translatable. Translations Once the trait is installed on the model you can do these things: ```php -$newsItem = new NewsItem; // This is an Eloquent model +$newsItem = new NewsItem(); // This is an Eloquent model $newsItem ->setTranslation('name', 'en', 'Name in English') ->setTranslation('name', 'nl', 'Naam in het Nederlands') From 2a0bae4bf76c7b490a10a128c863717a59921ca0 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 16:01:56 +0100 Subject: [PATCH 081/229] wip --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 16a6f48..7b8aa38 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^7.0" + "orchestra/testbench": "^7.0", + "phpunit/phpunit": "^9.5" }, "autoload": { "psr-4": { From f825cd2ae036d1105c06ba6f91a382de01f06217 Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 7 Mar 2022 15:17:12 +0000 Subject: [PATCH 082/229] Add Pest dependencies --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7b8aa38..d56f7db 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "require-dev": { "mockery/mockery": "^1.4", "orchestra/testbench": "^7.0", - "phpunit/phpunit": "^9.5" + "pestphp/pest": "^1.20" }, "autoload": { "psr-4": { From f3746dc73d9d45ffee1a9a0d15cf0083f7932fdf Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 7 Mar 2022 15:17:12 +0000 Subject: [PATCH 083/229] Add base Pest file --- tests/Pest.php | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/Pest.php diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..95bd699 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,40 @@ + Date: Mon, 7 Mar 2022 15:17:12 +0000 Subject: [PATCH 084/229] Convert test cases --- tests/EventTest.php | 28 +- tests/TranslatableTest.php | 1379 +++++++++++++++++------------------- 2 files changed, 641 insertions(+), 766 deletions(-) diff --git a/tests/EventTest.php b/tests/EventTest.php index 79c9213..ff6a341 100644 --- a/tests/EventTest.php +++ b/tests/EventTest.php @@ -1,28 +1,18 @@ testModel = new TestModel(); - } + $this->testModel = new TestModel(); +}); - /** @test */ - public function it_will_fire_an_event_when_a_translation_has_been_set() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); +it('will fire an event when a translation has been set', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); - Event::assertDispatched(TranslationHasBeenSetEvent::class); - } -} + Event::assertDispatched(TranslationHasBeenSetEvent::class); +}); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 9ae470c..7aac087 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1,824 +1,709 @@ testModel = new TestModel(); +}); - $this->testModel = new TestModel(); - } +it('will return package fallback locale translation when getting an unknown locale', function () { + config()->set('app.fallback_locale', 'nl'); + Translatable::fallback( + fallbackLocale: 'en', + ); - /** @test */ - public function it_will_return_package_fallback_locale_translation_when_getting_an_unknown_locale() - { - config()->set('app.fallback_locale', 'nl'); - Translatable::fallback( - fallbackLocale: 'en', - ); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); +}); - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); - } +it('will return default fallback locale translation when getting an unknown locale', function () { + config()->set('app.fallback_locale', 'en'); - /** @test */ - public function it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale() - { - config()->set('app.fallback_locale', 'en'); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); +}); - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); - } +it('provides a flog to not return fallback locale translation when getting an unknown locale', function () { + config()->set('app.fallback_locale', 'en'); - /** @test */ - public function it_provides_a_flog_to_not_return_fallback_locale_translation_when_getting_an_unknown_locale() - { - config()->set('app.fallback_locale', 'en'); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + $this->assertSame('', $this->testModel->getTranslation('name', 'fr', false)); +}); - $this->assertSame('', $this->testModel->getTranslation('name', 'fr', false)); - } +it('will return fallback locale translation when getting an unknown locale and fallback is true', function () { + config()->set('app.fallback_locale', 'en'); - /** @test */ - public function it_will_return_fallback_locale_translation_when_getting_an_unknown_locale_and_fallback_is_true() - { - config()->set('app.fallback_locale', 'en'); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); +}); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); - } +it('will execute callback fallback when getting an unknown locale and fallback callback is enabled', function () { + Storage::fake(); - /** @test */ - public function it_will_execute_callback_fallback_when_getting_an_unknown_locale_and_fallback_callback_is_enabled() - { - Storage::fake(); + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + //something assertable outside the closure + Storage::put("test.txt", "test"); + }); - Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { - //something assertable outside the closure - Storage::put("test.txt", "test"); - }); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + 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"; + }); - /** @test */ - public function it_will_use_callback_fallback_return_value_as_translation() - { - Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { - return "testValue_fallback_callback"; - }); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + $this->assertSame('testValue_fallback_callback', $this->testModel->getTranslationWithFallback('name', 'fr')); +}); - $this->assertSame('testValue_fallback_callback', $this->testModel->getTranslationWithFallback('name', 'fr')); - } +it('wont use callback fallback return value as translation if it is not a string', function () { + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + return 123456; + }); - /** @test */ - public function it_wont_use_callback_fallback_return_value_as_translation_if_it_is_not_a_string() - { - Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { - return 123456; - }); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); - - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); - } + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); +}); - /** @test */ - public function it_wont_execute_callback_fallback_when_getting_an_existing_translation() - { - Storage::fake(); +it('wont execute callback fallback when getting an existing translation', function () { + Storage::fake(); - Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { - //something assertable outside the closure - Storage::put("test.txt", "test"); - }); - - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + //something assertable outside the closure + Storage::put("test.txt", "test"); + }); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'en')); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - Storage::assertMissing("test.txt"); - } + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'en')); - /** @test */ - public function it_wont_fail_if_callback_fallback_throw_exception() - { - Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { - throw new \Exception(); - }); + Storage::assertMissing("test.txt"); +}); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); +it('wont fail if callback fallback throw exception', function () { + Translatable::fallback(missingKeyCallback: function ($model, string $translationKey, string $locale) { + throw new \Exception(); + }); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); - } + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - /** @test */ - public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_not_set() - { - config()->set('app.fallback_locale', ''); - - Translatable::fallback( - fallbackLocale: '', - ); - - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); - - $this->assertSame('', $this->testModel->getTranslationWithoutFallback('name', 'fr')); - } - - /** @test */ - public function it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_empty() - { - config()->set('app.fallback_locale', ''); - - Translatable::fallback( - fallbackLocale: '', - ); - - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); - - $this->assertSame('', $this->testModel->getTranslation('name', 'fr')); - } + $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); +}); - /** @test */ - public function it_can_save_a_translated_attribute() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); - - $this->assertSame('testValue_en', $this->testModel->name); - } - - /** @test */ - public function it_can_set_translated_values_when_creating_a_model() - { - $model = TestModel::create([ - 'name' => ['en' => 'testValue_en'], - ]); - - $this->assertSame('testValue_en', $model->name); - } - - /** @test */ - public function it_can_save_multiple_translations() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); - - $this->assertSame('testValue_en', $this->testModel->name); - $this->assertSame('testValue_fr', $this->testModel->getTranslation('name', 'fr')); - } - - /** @test */ - public function it_will_return_the_value_of_the_current_locale_when_using_the_property() - { - $this->testModel->setTranslation('name', 'en', 'testValue'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); - - app()->setLocale('fr'); - - $this->assertSame('testValue_fr', $this->testModel->name); - } - - /** @test */ - public function it_can_get_all_translations_in_one_go() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); +it('will return an empty string when getting an unknown locale and fallback is not set', function () { + config()->set('app.fallback_locale', ''); - $this->assertSame([ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); - } + Translatable::fallback( + fallbackLocale: '', + ); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('', $this->testModel->getTranslationWithoutFallback('name', 'fr')); +}); + +it('will return an empty string when getting an unknown locale and fallback is empty', function () { + config()->set('app.fallback_locale', ''); + + Translatable::fallback( + fallbackLocale: '', + ); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('', $this->testModel->getTranslation('name', 'fr')); +}); + +it('can save a translated attribute', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->name); +}); + +it('can set translated values when creating a model', function () { + $model = TestModel::create([ + 'name' => ['en' => 'testValue_en'], + ]); + + $this->assertSame('testValue_en', $model->name); +}); + +it('can save multiple translations', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->name); + $this->assertSame('testValue_fr', $this->testModel->getTranslation('name', 'fr')); +}); + +it('will return the value of the current locale when using the property', function () { + $this->testModel->setTranslation('name', 'en', 'testValue'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); - /** @test */ - public function it_can_get_specified_translations_in_one_go() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); + app()->setLocale('fr'); - $this->assertSame([ + $this->assertSame('testValue_fr', $this->testModel->name); +}); + +it('can get all translations in one go', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); +}); + +it('can get specified translations in one go', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + ], $this->testModel->getTranslations('name', ['en'])); +}); + +it('can get all translations for all translatable attributes in one go', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); + $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'name' => [ 'en' => 'testValue_en', - ], $this->testModel->getTranslations('name', ['en'])); - } - - /** @test */ - public function it_can_get_all_translations_for_all_translatable_attributes_in_one_go() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - - $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); - $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); - - $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); - $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); - $this->testModel->save(); - - $this->assertSame([ - 'name' => [ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], - 'other_field' => [ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], - 'field_with_mutator' => [ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], - ], $this->testModel->getTranslations()); - } - - /** @test */ - public function it_can_get_specified_translations_for_all_translatable_attributes_in_one_go() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - - $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); - $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); - - $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); - $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); - $this->testModel->save(); - - $this->assertSame([ - 'name' => ['en' => 'testValue_en'], - 'other_field' => ['en' => 'testValue_en'], - 'field_with_mutator' => ['en' => 'testValue_en'], - ], $this->testModel->getTranslations(null, ['en'])); - } - - /** @test */ - public function it_can_get_the_locales_which_have_a_translation() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); - - $this->assertSame(['en', 'fr'], $this->testModel->getTranslatedLocales('name')); - } - - /** @test */ - public function it_can_forget_a_translation() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); - - $this->assertSame([ + 'fr' => 'testValue_fr', + ], + 'other_field' => [ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], + 'field_with_mutator' => [ 'en' => 'testValue_en', 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); + ], + ], $this->testModel->getTranslations()); +}); - $this->testModel->forgetTranslation('name', 'en'); +it('can get specified translations for all translatable attributes in one go', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->assertSame([ - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); - } + $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); + $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); - /** @test */ - public function it_can_forget_all_translations_of_field() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); + $this->testModel->save(); - $this->assertSame([ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); + $this->assertSame([ + 'name' => ['en' => 'testValue_en'], + 'other_field' => ['en' => 'testValue_en'], + 'field_with_mutator' => ['en' => 'testValue_en'], + ], $this->testModel->getTranslations(null, ['en'])); +}); - $this->testModel->forgetTranslations('name'); +it('can get the locales which have a translation', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); - $this->assertSame('[]', $this->testModel->getAttributes()['name']); - $this->assertSame([], $this->testModel->getTranslations('name')); + $this->assertSame(['en', 'fr'], $this->testModel->getTranslatedLocales('name')); +}); - $this->testModel->save(); +it('can forget a translation', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); - $this->assertSame('[]', $this->testModel->fresh()->getAttributes()['name']); - $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); - } + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); - /** @test */ - public function it_can_forget_all_translations_of_field_and_make_field_null() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->save(); + $this->testModel->forgetTranslation('name', 'en'); - $this->assertSame([ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); +}); - $this->testModel->forgetTranslations('name', true); +it('can forget all translations of field', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); - $this->assertNull($this->testModel->getAttributes()['name']); - $this->assertSame([], $this->testModel->getTranslations('name')); + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); - $this->testModel->save(); + $this->testModel->forgetTranslations('name'); - $this->assertNull($this->testModel->fresh()->getAttributes()['name']); - $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); - } + $this->assertSame('[]', $this->testModel->getAttributes()['name']); + $this->assertSame([], $this->testModel->getTranslations('name')); - /** @test */ - public function it_can_forget_a_field_with_mutator_translation() - { - $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); - $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); - $this->testModel->save(); + $this->testModel->save(); - $this->assertSame([ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('field_with_mutator')); + $this->assertSame('[]', $this->testModel->fresh()->getAttributes()['name']); + $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); +}); + +it('can forget all translations of field and make field null', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); - $this->testModel->forgetTranslation('field_with_mutator', 'en'); + $this->testModel->forgetTranslations('name', true); + + $this->assertNull($this->testModel->getAttributes()['name']); + $this->assertSame([], $this->testModel->getTranslations('name')); + + $this->testModel->save(); + + $this->assertNull($this->testModel->fresh()->getAttributes()['name']); + $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); +}); - $this->assertSame([ - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('field_with_mutator')); - } +it('can forget a field with mutator translation', function () { + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); + + $this->testModel->forgetTranslation('field_with_mutator', 'en'); + + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); +}); - /** @test */ - public function it_can_forget_all_translations() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); +it('can forget all translations', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); - $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('other_field', 'en', 'testValue_en'); + $this->testModel->setTranslation('other_field', 'fr', 'testValue_fr'); + + $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); + $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); + $this->testModel->save(); + + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); - $this->testModel->setTranslation('field_with_mutator', 'en', 'testValue_en'); - $this->testModel->setTranslation('field_with_mutator', 'fr', 'testValue_fr'); - $this->testModel->save(); + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('other_field')); - $this->assertSame([ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); + $this->assertSame([ + 'en' => 'testValue_en', + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); - $this->assertSame([ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('other_field')); + $this->testModel->forgetAllTranslations('en'); + + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('name')); + + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('other_field')); + + $this->assertSame([ + 'fr' => 'testValue_fr', + ], $this->testModel->getTranslations('field_with_mutator')); +}); + +it('will throw an exception when trying to translate an untranslatable attribute', function () { + $this->expectException(AttributeIsNotTranslatable::class); + + $this->testModel->setTranslation('untranslated', 'en', 'value'); +}); + +it('is compatible with accessors on non translatable attributes', function () { + $testModel = new class () extends TestModel { + public function getOtherFieldAttribute(): string + { + return 'accessorName'; + } + }; + + $this->assertEquals((new $testModel())->otherField, 'accessorName'); +}); - $this->assertSame([ +it('can use accessors on translated attributes', function () { + $testModel = new class () extends TestModel { + public function getNameAttribute($value): string + { + return "I just accessed {$value}"; + } + }; + + $testModel->setTranslation('name', 'en', 'testValue_en'); + + $this->assertEquals($testModel->name, 'I just accessed testValue_en'); +}); + +it('can use mutators on translated attributes', function () { + $testModel = new class () extends TestModel { + public function setNameAttribute($value) { + $this->attributes['name'] = "I just mutated {$value}"; + } + }; + + $testModel->setTranslation('name', 'en', 'testValue_en'); + + $this->assertEquals($testModel->name, 'I just mutated testValue_en'); +}); + +it('can set translations for default language', function () { + $model = TestModel::create([ + 'name' => [ 'en' => 'testValue_en', 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('field_with_mutator')); + ], + ]); - $this->testModel->forgetAllTranslations('en'); + app()->setLocale('en'); - $this->assertSame([ - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('name')); + $model->name = 'updated_en'; + $this->assertEquals('updated_en', $model->name); + $this->assertEquals('testValue_fr', $model->getTranslation('name', 'fr')); - $this->assertSame([ - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('other_field')); + app()->setLocale('fr'); + $model->name = 'updated_fr'; + $this->assertEquals('updated_fr', $model->name); + $this->assertEquals('updated_en', $model->getTranslation('name', 'en')); +}); - $this->assertSame([ - 'fr' => 'testValue_fr', - ], $this->testModel->getTranslations('field_with_mutator')); - } - - /** @test */ - public function it_will_throw_an_exception_when_trying_to_translate_an_untranslatable_attribute() - { - $this->expectException(AttributeIsNotTranslatable::class); - - $this->testModel->setTranslation('untranslated', 'en', 'value'); - } - - /** @test */ - public function it_is_compatible_with_accessors_on_non_translatable_attributes() - { - $testModel = new class () extends TestModel { - public function getOtherFieldAttribute(): string - { - return 'accessorName'; - } - }; - - $this->assertEquals((new $testModel())->otherField, 'accessorName'); - } - - /** @test */ - public function it_can_use_accessors_on_translated_attributes() - { - $testModel = new class () extends TestModel { - public function getNameAttribute($value): string - { - return "I just accessed {$value}"; - } - }; - - $testModel->setTranslation('name', 'en', 'testValue_en'); - - $this->assertEquals($testModel->name, 'I just accessed testValue_en'); - } - - /** @test */ - public function it_can_use_mutators_on_translated_attributes() - { - $testModel = new class () extends TestModel { - public function setNameAttribute($value) - { - $this->attributes['name'] = "I just mutated {$value}"; - } - }; - - $testModel->setTranslation('name', 'en', 'testValue_en'); - - $this->assertEquals($testModel->name, 'I just mutated testValue_en'); - } - - /** @test */ - public function it_can_set_translations_for_default_language() - { - $model = TestModel::create([ - 'name' => [ - 'en' => 'testValue_en', - 'fr' => 'testValue_fr', - ], - ]); - - app()->setLocale('en'); - - $model->name = 'updated_en'; - $this->assertEquals('updated_en', $model->name); - $this->assertEquals('testValue_fr', $model->getTranslation('name', 'fr')); - - app()->setLocale('fr'); - $model->name = 'updated_fr'; - $this->assertEquals('updated_fr', $model->name); - $this->assertEquals('updated_en', $model->getTranslation('name', 'en')); - } - - /** @test */ - public function it_can_set_multiple_translations_at_once() - { - $translations = ['nl' => 'hallo', 'en' => 'hello', 'kh' => 'សួរស្តី']; - - $this->testModel->setTranslations('name', $translations); - $this->testModel->save(); - - $this->assertEquals($translations, $this->testModel->getTranslations('name')); - } - - /** @test */ - public function it_can_check_if_an_attribute_is_translatable() - { - $this->assertTrue($this->testModel->isTranslatableAttribute('name')); - - $this->assertFalse($this->testModel->isTranslatableAttribute('other')); - } - - /** @test */ - public function it_can_check_if_an_attribute_has_translation() - { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'nl', null); - $this->testModel->save(); - - $this->assertTrue($this->testModel->hasTranslation('name', 'en')); - - $this->assertFalse($this->testModel->hasTranslation('name', 'pt')); - } - - /** @test */ - public function it_can_correctly_set_a_field_when_a_mutator_is_defined() - { - $testModel = (new class () extends TestModel { - public function setNameAttribute($value) - { - $this->attributes['name'] = "I just mutated {$value}"; - } - }); - - $testModel->name = 'hello'; - - $expected = ['en' => 'I just mutated hello']; - $this->assertEquals($expected, $testModel->getTranslations('name')); - } - - /** @test */ - public function it_can_set_multiple_translations_when_a_mutator_is_defined() - { - $testModel = (new class () extends TestModel { - public function setNameAttribute($value) - { - $this->attributes['name'] = "I just mutated {$value}"; - } - }); - - $translations = [ - 'nl' => 'hallo', - 'en' => 'hello', - 'kh' => 'សួរស្តី', - ]; - - $testModel->setTranslations('name', $translations); - - $testModel->save(); - - $expected = [ - 'nl' => 'I just mutated hallo', - 'en' => 'I just mutated hello', - 'kh' => 'I just mutated សួរស្តី', - ]; - - $this->assertEquals($expected, $testModel->getTranslations('name')); - } - - /** @test */ - public function it_can_set_multiple_translations_on_field_when_a_mutator_is_defined() - { - $translations = [ - 'nl' => 'hallo', - 'en' => 'hello', - ]; - - $testModel = $this->testModel; - $testModel->field_with_mutator = $translations; - $testModel->save(); - - $this->assertEquals($translations, $testModel->getTranslations('field_with_mutator')); - } - - /** @test */ - public function it_can_translate_a_field_based_on_the_translations_of_another_one() - { - $testModel = (new class () extends TestModel { - public function setOtherFieldAttribute($value, $locale = 'en') - { - $this->attributes['other_field'] = $value.' '.$this->getTranslation('name', $locale); - } - }); - - $testModel->setTranslations('name', [ - 'nl' => 'wereld', - 'en' => 'world', - ]); - - $testModel->setTranslations('other_field', [ - 'nl' => 'hallo', - 'en' => 'hello', - ]); - - $testModel->save(); - - $expected = [ - 'nl' => 'hallo wereld', - 'en' => 'hello world', - ]; - - $this->assertEquals($expected, $testModel->getTranslations('other_field')); - } - - /** @test */ - public function it_handle_null_value_from_database() - { - $testModel = (new class () extends TestModel { - public function setAttributesExternally(array $attributes) - { - $this->attributes = $attributes; - } - }); - - $testModel->setAttributesExternally(['name' => json_encode(null), 'other_field' => null]); - - $this->assertEquals('', $testModel->name); - $this->assertEquals('', $testModel->other_field); - } - - /** @test */ - public function it_can_get_all_translations() - { - $translations = ['nl' => 'hallo', 'en' => 'hello']; - - $this->testModel->setTranslations('name', $translations); - $this->testModel->setTranslations('field_with_mutator', $translations); - $this->testModel->save(); - - $this->assertEquals([ - 'name' => ['nl' => 'hallo', 'en' => 'hello'], - 'other_field' => [], - 'field_with_mutator' => ['nl' => 'hallo', 'en' => 'hello'], - ], $this->testModel->translations); - } - - /** @test */ - public function it_will_return_fallback_locale_translation_when_getting_an_empty_translation_from_the_locale() - { - config()->set('app.fallback_locale', 'en'); - - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'nl', null); - $this->testModel->save(); - - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'nl')); - } - - /** @test */ - public function it_will_return_correct_translation_value_if_value_is_set_to_zero() - { - $this->testModel->setTranslation('name', 'nl', '0'); - $this->testModel->save(); - - $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); - } - - /** @test */ - public function it_will_not_return_fallback_value_if_value_is_set_to_zero() - { - config()->set('app.fallback_locale', 'en'); - - $this->testModel->setTranslation('name', 'en', '1'); - $this->testModel->setTranslation('name', 'nl', '0'); - $this->testModel->save(); - - $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); - } - - /** @test */ - public function it_will_not_remove_zero_value_of_other_locale_in_database() - { - config()->set('app.fallback_locale', 'en'); - - $this->testModel->setTranslation('name', 'nl', '0'); - $this->testModel->setTranslation('name', 'en', '1'); - $this->testModel->save(); - - $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); - } - - /** @test */ - public function it_can_be_translated_based_on_given_locale() - { - $value = 'World'; - - $this->testModel = TestModel::usingLocale('en')->fill([ - 'name' => $value, - ]); - $this->testModel->save(); - - $this->assertSame($value, $this->testModel->getTranslation('name', 'en')); - } - - /** @test */ - public function it_can_set_and_fetch_attributes_based_on_set_locale() - { - $en = 'World'; - $fr = 'Monde'; - - $this->testModel->setLocale('en'); - $this->testModel->name = $en; - $this->testModel->setLocale('fr'); - $this->testModel->name = $fr; - - $this->testModel->save(); - - $this->testModel->setLocale('en'); - $this->assertSame($en, $this->testModel->name); - $this->testModel->setLocale('fr'); - $this->assertSame($fr, $this->testModel->name); - } - - /** @test */ - public function it_can_replace_translations() - { - $translations = ['nl' => 'hallo', 'en' => 'hello', 'kh' => 'សួរស្តី']; - - $this->testModel->setTranslations('name', $translations); - $this->testModel->save(); - - $newTranslations = ['es' => 'hola']; - $this->testModel->replaceTranslations('name', $newTranslations); - - $this->assertEquals($newTranslations, $this->testModel->getTranslations('name')); - } - - /** @test */ - public function it_can_use_any_locale_if_given_locale_not_set() - { - config()->set('app.fallback_locale', 'en'); - - Translatable::fallback( - fallbackAny: true, - ); - - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->setTranslation('name', 'de', 'testValue_de'); - $this->testModel->save(); - - $this->testModel->setLocale('it'); - $this->assertSame('testValue_fr', $this->testModel->name); - } - - /** @test */ - public function it_will_return_set_translation_when_fallback_any_set() - { - config()->set('app.fallback_locale', 'en'); - - Translatable::fallback( - fallbackAny: true, - ); - - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->setTranslation('name', 'de', 'testValue_de'); - $this->testModel->save(); - - $this->testModel->setLocale('de'); - $this->assertSame('testValue_de', $this->testModel->name); - } - - /** @test */ - public function it_will_return_fallback_translation_when_fallback_any_set() - { - config()->set('app.fallback_locale', 'en'); - - Translatable::fallback( - fallbackAny: true, - ); - - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); - - $this->testModel->setLocale('de'); - $this->assertSame('testValue_en', $this->testModel->name); - } - - /** @test */ - public function it_provides_a_flog_to_not_return_any_translation_when_getting_an_unknown_locale() - { - config()->set('app.fallback_locale', 'en'); - - Translatable::fallback( - fallbackAny: true, - ); - - $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); - $this->testModel->setTranslation('name', 'de', 'testValue_de'); - $this->testModel->save(); - - $this->testModel->setLocale('it'); - $this->assertSame('', $this->testModel->getTranslation('name', 'it', false)); - } - - /** @test */ - public function it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale_with_fallback_any() - { - config()->set('app.fallback_locale', 'en'); +it('can set multiple translations at once', function () { + $translations = ['nl' => 'hallo', 'en' => 'hello', 'kh' => 'សួរស្តី']; + + $this->testModel->setTranslations('name', $translations); + $this->testModel->save(); + + $this->assertEquals($translations, $this->testModel->getTranslations('name')); +}); + +it('can check if an attribute is translatable', function () { + $this->assertTrue($this->testModel->isTranslatableAttribute('name')); + + $this->assertFalse($this->testModel->isTranslatableAttribute('other')); +}); + +it('can check if an attribute has translation', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'nl', null); + $this->testModel->save(); + + $this->assertTrue($this->testModel->hasTranslation('name', 'en')); + + $this->assertFalse($this->testModel->hasTranslation('name', 'pt')); +}); + +it('can correctly set a field when a mutator is defined', function () { + $testModel = (new class () extends TestModel { + public function setNameAttribute($value) { + $this->attributes['name'] = "I just mutated {$value}"; + } + }); + + $testModel->name = 'hello'; + + $expected = ['en' => 'I just mutated hello']; + $this->assertEquals($expected, $testModel->getTranslations('name')); +}); + +it('can set multiple translations when a mutator is defined', function () { + $testModel = (new class () extends TestModel { + public function setNameAttribute($value) { + $this->attributes['name'] = "I just mutated {$value}"; + } + }); + + $translations = [ + 'nl' => 'hallo', + 'en' => 'hello', + 'kh' => 'សួរស្តី', + ]; + + $testModel->setTranslations('name', $translations); + + $testModel->save(); + + $expected = [ + 'nl' => 'I just mutated hallo', + 'en' => 'I just mutated hello', + 'kh' => 'I just mutated សួរស្តី', + ]; + + $this->assertEquals($expected, $testModel->getTranslations('name')); +}); + +it('can set multiple translations on field when a mutator is defined', function () { + $translations = [ + 'nl' => 'hallo', + 'en' => 'hello', + ]; + + $testModel = $this->testModel; + $testModel->field_with_mutator = $translations; + $testModel->save(); + + $this->assertEquals($translations, $testModel->getTranslations('field_with_mutator')); +}); + +it('can translate a field based on the translations of another one', function () { + $testModel = (new class () extends TestModel { + public function setOtherFieldAttribute($value, $locale = 'en') { + $this->attributes['other_field'] = $value.' '.$this->getTranslation('name', $locale); + } + }); + + $testModel->setTranslations('name', [ + 'nl' => 'wereld', + 'en' => 'world', + ]); + + $testModel->setTranslations('other_field', [ + 'nl' => 'hallo', + 'en' => 'hello', + ]); + + $testModel->save(); + + $expected = [ + 'nl' => 'hallo wereld', + 'en' => 'hello world', + ]; + + $this->assertEquals($expected, $testModel->getTranslations('other_field')); +}); + +it('handle null value from database', function () { + $testModel = (new class () extends TestModel { + public function setAttributesExternally(array $attributes) { + $this->attributes = $attributes; + } + }); + + $testModel->setAttributesExternally(['name' => json_encode(null), 'other_field' => null]); + + $this->assertEquals('', $testModel->name); + $this->assertEquals('', $testModel->other_field); +}); + +it('can get all translations', function () { + $translations = ['nl' => 'hallo', 'en' => 'hello']; + + $this->testModel->setTranslations('name', $translations); + $this->testModel->setTranslations('field_with_mutator', $translations); + $this->testModel->save(); + + $this->assertEquals([ + 'name' => ['nl' => 'hallo', 'en' => 'hello'], + 'other_field' => [], + 'field_with_mutator' => ['nl' => 'hallo', 'en' => 'hello'], + ], $this->testModel->translations); +}); + +it('will return fallback locale translation when getting an empty translation from the locale', function () { + config()->set('app.fallback_locale', 'en'); + + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'nl', null); + $this->testModel->save(); + + $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'nl')); +}); + +it('will return correct translation value if value is set to zero', function () { + $this->testModel->setTranslation('name', 'nl', '0'); + $this->testModel->save(); + + $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); +}); + +it('will not return fallback value if value is set to zero', function () { + config()->set('app.fallback_locale', 'en'); + + $this->testModel->setTranslation('name', 'en', '1'); + $this->testModel->setTranslation('name', 'nl', '0'); + $this->testModel->save(); + + $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); +}); + +it('will not remove zero value of other locale in database', function () { + config()->set('app.fallback_locale', 'en'); + + $this->testModel->setTranslation('name', 'nl', '0'); + $this->testModel->setTranslation('name', 'en', '1'); + $this->testModel->save(); + + $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); +}); + +it('can be translated based on given locale', function () { + $value = 'World'; + + $this->testModel = TestModel::usingLocale('en')->fill([ + 'name' => $value, + ]); + $this->testModel->save(); + + $this->assertSame($value, $this->testModel->getTranslation('name', 'en')); +}); + +it('can set and fetch attributes based on set locale', function () { + $en = 'World'; + $fr = 'Monde'; + + $this->testModel->setLocale('en'); + $this->testModel->name = $en; + $this->testModel->setLocale('fr'); + $this->testModel->name = $fr; + + $this->testModel->save(); + + $this->testModel->setLocale('en'); + $this->assertSame($en, $this->testModel->name); + $this->testModel->setLocale('fr'); + $this->assertSame($fr, $this->testModel->name); +}); + +it('can replace translations', function () { + $translations = ['nl' => 'hallo', 'en' => 'hello', 'kh' => 'សួរស្តី']; + + $this->testModel->setTranslations('name', $translations); + $this->testModel->save(); + + $newTranslations = ['es' => 'hola']; + $this->testModel->replaceTranslations('name', $newTranslations); + + $this->assertEquals($newTranslations, $this->testModel->getTranslations('name')); +}); + +it('can use any locale if given locale not set', function () { + config()->set('app.fallback_locale', 'en'); + + Translatable::fallback( + fallbackAny: true, + ); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'de', 'testValue_de'); + $this->testModel->save(); + + $this->testModel->setLocale('it'); + $this->assertSame('testValue_fr', $this->testModel->name); +}); + +it('will return set translation when fallback any set', function () { + config()->set('app.fallback_locale', 'en'); + + Translatable::fallback( + fallbackAny: true, + ); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'de', 'testValue_de'); + $this->testModel->save(); + + $this->testModel->setLocale('de'); + $this->assertSame('testValue_de', $this->testModel->name); +}); + +it('will return fallback translation when fallback any set', function () { + config()->set('app.fallback_locale', 'en'); + + Translatable::fallback( + fallbackAny: true, + ); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); + + $this->testModel->setLocale('de'); + $this->assertSame('testValue_en', $this->testModel->name); +}); + +it('provides a flog to not return any translation when getting an unknown locale', function () { + config()->set('app.fallback_locale', 'en'); + + Translatable::fallback( + fallbackAny: true, + ); + + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'de', 'testValue_de'); + $this->testModel->save(); + + $this->testModel->setLocale('it'); + $this->assertSame('', $this->testModel->getTranslation('name', 'it', false)); +}); + +it('will return default fallback locale translation when getting an unknown locale with fallback any', function () { + config()->set('app.fallback_locale', 'en'); + + Translatable::fallback( + fallbackAny: true, + ); - Translatable::fallback( - fallbackAny: true, - ); + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->save(); - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->save(); - - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); - } -} + $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); +}); From 1af24648d486232c5c22d87187ac1b09929168fd Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 7 Mar 2022 15:17:13 +0000 Subject: [PATCH 085/229] Adopt expectation API --- tests/TranslatableTest.php | 112 ++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 7aac087..9708820 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -19,7 +19,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); + expect($this->testModel->getTranslation('name', 'fr'))->toBe('testValue_en'); }); it('will return default fallback locale translation when getting an unknown locale', function () { @@ -28,7 +28,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); + expect($this->testModel->getTranslation('name', 'fr'))->toBe('testValue_en'); }); it('provides a flog to not return fallback locale translation when getting an unknown locale', function () { @@ -37,7 +37,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('', $this->testModel->getTranslation('name', 'fr', false)); + expect($this->testModel->getTranslation('name', 'fr', false))->toBe(''); }); it('will return fallback locale translation when getting an unknown locale and fallback is true', function () { @@ -46,7 +46,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + expect($this->testModel->getTranslationWithFallback('name', 'fr'))->toBe('testValue_en'); }); it('will execute callback fallback when getting an unknown locale and fallback callback is enabled', function () { @@ -60,7 +60,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + expect($this->testModel->getTranslationWithFallback('name', 'fr'))->toBe('testValue_en'); Storage::assertExists("test.txt"); }); @@ -73,7 +73,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_fallback_callback', $this->testModel->getTranslationWithFallback('name', 'fr')); + expect($this->testModel->getTranslationWithFallback('name', 'fr'))->toBe('testValue_fallback_callback'); }); it('wont use callback fallback return value as translation if it is not a string', function () { @@ -84,7 +84,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + expect($this->testModel->getTranslationWithFallback('name', 'fr'))->toBe('testValue_en'); }); it('wont execute callback fallback when getting an existing translation', function () { @@ -98,7 +98,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'en')); + expect($this->testModel->getTranslationWithFallback('name', 'en'))->toBe('testValue_en'); Storage::assertMissing("test.txt"); }); @@ -111,7 +111,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslationWithFallback('name', 'fr')); + expect($this->testModel->getTranslationWithFallback('name', 'fr'))->toBe('testValue_en'); }); it('will return an empty string when getting an unknown locale and fallback is not set', function () { @@ -124,7 +124,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('', $this->testModel->getTranslationWithoutFallback('name', 'fr')); + expect($this->testModel->getTranslationWithoutFallback('name', 'fr'))->toBe(''); }); it('will return an empty string when getting an unknown locale and fallback is empty', function () { @@ -137,14 +137,14 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('', $this->testModel->getTranslation('name', 'fr')); + expect($this->testModel->getTranslation('name', 'fr'))->toBe(''); }); it('can save a translated attribute', function () { $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->name); + expect($this->testModel->name)->toBe('testValue_en'); }); it('can set translated values when creating a model', function () { @@ -152,7 +152,7 @@ 'name' => ['en' => 'testValue_en'], ]); - $this->assertSame('testValue_en', $model->name); + expect($model->name)->toBe('testValue_en'); }); it('can save multiple translations', function () { @@ -160,8 +160,8 @@ $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->name); - $this->assertSame('testValue_fr', $this->testModel->getTranslation('name', 'fr')); + expect($this->testModel->name)->toBe('testValue_en'); + expect($this->testModel->getTranslation('name', 'fr'))->toBe('testValue_fr'); }); it('will return the value of the current locale when using the property', function () { @@ -171,7 +171,7 @@ app()->setLocale('fr'); - $this->assertSame('testValue_fr', $this->testModel->name); + expect($this->testModel->name)->toBe('testValue_fr'); }); it('can get all translations in one go', function () { @@ -245,7 +245,7 @@ $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); $this->testModel->save(); - $this->assertSame(['en', 'fr'], $this->testModel->getTranslatedLocales('name')); + expect($this->testModel->getTranslatedLocales('name'))->toBe(['en', 'fr']); }); it('can forget a translation', function () { @@ -277,13 +277,13 @@ $this->testModel->forgetTranslations('name'); - $this->assertSame('[]', $this->testModel->getAttributes()['name']); - $this->assertSame([], $this->testModel->getTranslations('name')); + expect($this->testModel->getAttributes()['name'])->toBe('[]'); + expect($this->testModel->getTranslations('name'))->toBe([]); $this->testModel->save(); - $this->assertSame('[]', $this->testModel->fresh()->getAttributes()['name']); - $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); + expect($this->testModel->fresh()->getAttributes()['name'])->toBe('[]'); + expect($this->testModel->fresh()->getTranslations('name'))->toBe([]); }); it('can forget all translations of field and make field null', function () { @@ -298,13 +298,13 @@ $this->testModel->forgetTranslations('name', true); - $this->assertNull($this->testModel->getAttributes()['name']); - $this->assertSame([], $this->testModel->getTranslations('name')); + expect($this->testModel->getAttributes()['name'])->toBeNull(); + expect($this->testModel->getTranslations('name'))->toBe([]); $this->testModel->save(); - $this->assertNull($this->testModel->fresh()->getAttributes()['name']); - $this->assertSame([], $this->testModel->fresh()->getTranslations('name')); + expect($this->testModel->fresh()->getAttributes()['name'])->toBeNull(); + expect($this->testModel->fresh()->getTranslations('name'))->toBe([]); }); it('can forget a field with mutator translation', function () { @@ -379,7 +379,7 @@ public function getOtherFieldAttribute(): string } }; - $this->assertEquals((new $testModel())->otherField, 'accessorName'); + expect('accessorName')->toEqual((new $testModel())->otherField); }); it('can use accessors on translated attributes', function () { @@ -392,7 +392,7 @@ public function getNameAttribute($value): string $testModel->setTranslation('name', 'en', 'testValue_en'); - $this->assertEquals($testModel->name, 'I just accessed testValue_en'); + expect('I just accessed testValue_en')->toEqual($testModel->name); }); it('can use mutators on translated attributes', function () { @@ -404,7 +404,7 @@ public function setNameAttribute($value) { $testModel->setTranslation('name', 'en', 'testValue_en'); - $this->assertEquals($testModel->name, 'I just mutated testValue_en'); + expect('I just mutated testValue_en')->toEqual($testModel->name); }); it('can set translations for default language', function () { @@ -418,13 +418,13 @@ public function setNameAttribute($value) { app()->setLocale('en'); $model->name = 'updated_en'; - $this->assertEquals('updated_en', $model->name); - $this->assertEquals('testValue_fr', $model->getTranslation('name', 'fr')); + expect($model->name)->toEqual('updated_en'); + expect($model->getTranslation('name', 'fr'))->toEqual('testValue_fr'); app()->setLocale('fr'); $model->name = 'updated_fr'; - $this->assertEquals('updated_fr', $model->name); - $this->assertEquals('updated_en', $model->getTranslation('name', 'en')); + expect($model->name)->toEqual('updated_fr'); + expect($model->getTranslation('name', 'en'))->toEqual('updated_en'); }); it('can set multiple translations at once', function () { @@ -433,13 +433,13 @@ public function setNameAttribute($value) { $this->testModel->setTranslations('name', $translations); $this->testModel->save(); - $this->assertEquals($translations, $this->testModel->getTranslations('name')); + expect($this->testModel->getTranslations('name'))->toEqual($translations); }); it('can check if an attribute is translatable', function () { - $this->assertTrue($this->testModel->isTranslatableAttribute('name')); + expect($this->testModel->isTranslatableAttribute('name'))->toBeTrue(); - $this->assertFalse($this->testModel->isTranslatableAttribute('other')); + expect($this->testModel->isTranslatableAttribute('other'))->toBeFalse(); }); it('can check if an attribute has translation', function () { @@ -447,9 +447,9 @@ public function setNameAttribute($value) { $this->testModel->setTranslation('name', 'nl', null); $this->testModel->save(); - $this->assertTrue($this->testModel->hasTranslation('name', 'en')); + expect($this->testModel->hasTranslation('name', 'en'))->toBeTrue(); - $this->assertFalse($this->testModel->hasTranslation('name', 'pt')); + expect($this->testModel->hasTranslation('name', 'pt'))->toBeFalse(); }); it('can correctly set a field when a mutator is defined', function () { @@ -462,7 +462,7 @@ public function setNameAttribute($value) { $testModel->name = 'hello'; $expected = ['en' => 'I just mutated hello']; - $this->assertEquals($expected, $testModel->getTranslations('name')); + expect($testModel->getTranslations('name'))->toEqual($expected); }); it('can set multiple translations when a mutator is defined', function () { @@ -488,7 +488,7 @@ public function setNameAttribute($value) { 'kh' => 'I just mutated សួរស្តី', ]; - $this->assertEquals($expected, $testModel->getTranslations('name')); + expect($testModel->getTranslations('name'))->toEqual($expected); }); it('can set multiple translations on field when a mutator is defined', function () { @@ -501,7 +501,7 @@ public function setNameAttribute($value) { $testModel->field_with_mutator = $translations; $testModel->save(); - $this->assertEquals($translations, $testModel->getTranslations('field_with_mutator')); + expect($testModel->getTranslations('field_with_mutator'))->toEqual($translations); }); it('can translate a field based on the translations of another one', function () { @@ -528,7 +528,7 @@ public function setOtherFieldAttribute($value, $locale = 'en') { 'en' => 'hello world', ]; - $this->assertEquals($expected, $testModel->getTranslations('other_field')); + expect($testModel->getTranslations('other_field'))->toEqual($expected); }); it('handle null value from database', function () { @@ -540,8 +540,8 @@ public function setAttributesExternally(array $attributes) { $testModel->setAttributesExternally(['name' => json_encode(null), 'other_field' => null]); - $this->assertEquals('', $testModel->name); - $this->assertEquals('', $testModel->other_field); + expect($testModel->name)->toEqual(''); + expect($testModel->other_field)->toEqual(''); }); it('can get all translations', function () { @@ -565,14 +565,14 @@ public function setAttributesExternally(array $attributes) { $this->testModel->setTranslation('name', 'nl', null); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'nl')); + expect($this->testModel->getTranslation('name', 'nl'))->toBe('testValue_en'); }); it('will return correct translation value if value is set to zero', function () { $this->testModel->setTranslation('name', 'nl', '0'); $this->testModel->save(); - $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); + expect($this->testModel->getTranslation('name', 'nl'))->toBe('0'); }); it('will not return fallback value if value is set to zero', function () { @@ -582,7 +582,7 @@ public function setAttributesExternally(array $attributes) { $this->testModel->setTranslation('name', 'nl', '0'); $this->testModel->save(); - $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); + expect($this->testModel->getTranslation('name', 'nl'))->toBe('0'); }); it('will not remove zero value of other locale in database', function () { @@ -592,7 +592,7 @@ public function setAttributesExternally(array $attributes) { $this->testModel->setTranslation('name', 'en', '1'); $this->testModel->save(); - $this->assertSame('0', $this->testModel->getTranslation('name', 'nl')); + expect($this->testModel->getTranslation('name', 'nl'))->toBe('0'); }); it('can be translated based on given locale', function () { @@ -603,7 +603,7 @@ public function setAttributesExternally(array $attributes) { ]); $this->testModel->save(); - $this->assertSame($value, $this->testModel->getTranslation('name', 'en')); + expect($this->testModel->getTranslation('name', 'en'))->toBe($value); }); it('can set and fetch attributes based on set locale', function () { @@ -618,9 +618,9 @@ public function setAttributesExternally(array $attributes) { $this->testModel->save(); $this->testModel->setLocale('en'); - $this->assertSame($en, $this->testModel->name); + expect($this->testModel->name)->toBe($en); $this->testModel->setLocale('fr'); - $this->assertSame($fr, $this->testModel->name); + expect($this->testModel->name)->toBe($fr); }); it('can replace translations', function () { @@ -632,7 +632,7 @@ public function setAttributesExternally(array $attributes) { $newTranslations = ['es' => 'hola']; $this->testModel->replaceTranslations('name', $newTranslations); - $this->assertEquals($newTranslations, $this->testModel->getTranslations('name')); + expect($this->testModel->getTranslations('name'))->toEqual($newTranslations); }); it('can use any locale if given locale not set', function () { @@ -647,7 +647,7 @@ public function setAttributesExternally(array $attributes) { $this->testModel->save(); $this->testModel->setLocale('it'); - $this->assertSame('testValue_fr', $this->testModel->name); + expect($this->testModel->name)->toBe('testValue_fr'); }); it('will return set translation when fallback any set', function () { @@ -662,7 +662,7 @@ public function setAttributesExternally(array $attributes) { $this->testModel->save(); $this->testModel->setLocale('de'); - $this->assertSame('testValue_de', $this->testModel->name); + expect($this->testModel->name)->toBe('testValue_de'); }); it('will return fallback translation when fallback any set', function () { @@ -677,7 +677,7 @@ public function setAttributesExternally(array $attributes) { $this->testModel->save(); $this->testModel->setLocale('de'); - $this->assertSame('testValue_en', $this->testModel->name); + expect($this->testModel->name)->toBe('testValue_en'); }); it('provides a flog to not return any translation when getting an unknown locale', function () { @@ -692,7 +692,7 @@ public function setAttributesExternally(array $attributes) { $this->testModel->save(); $this->testModel->setLocale('it'); - $this->assertSame('', $this->testModel->getTranslation('name', 'it', false)); + expect($this->testModel->getTranslation('name', 'it', false))->toBe(''); }); it('will return default fallback locale translation when getting an unknown locale with fallback any', function () { @@ -705,5 +705,5 @@ public function setAttributesExternally(array $attributes) { $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - $this->assertSame('testValue_en', $this->testModel->getTranslation('name', 'fr')); + expect($this->testModel->getTranslation('name', 'fr'))->toBe('testValue_en'); }); From aee2d096ac2e09aa007f0f764699a8a303a9bbc3 Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 7 Mar 2022 15:17:13 +0000 Subject: [PATCH 086/229] Optimize uses --- tests/Pest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Pest.php b/tests/Pest.php index 95bd699..2db4bff 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,7 @@ in('tests'); + /* |-------------------------------------------------------------------------- | Test Case From 9cc89fc53bc8d4c29ce5c4df60bd42baee63aae0 Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 7 Mar 2022 15:17:13 +0000 Subject: [PATCH 087/229] Set return type of base TestCase methods From the [PHPUnit 8 release notes][1], the `TestCase` methods below now declare a `void` return type: - `setUpBeforeClass()` - `setUp()` - `assertPreConditions()` - `assertPostConditions()` - `tearDown()` - `tearDownAfterClass()` - `onNotSuccessfulTest()` [1]: https://phpunit.de/announcements/phpunit-8.html --- tests/TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 12ca7fc..b7e24c4 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,7 +9,7 @@ abstract class TestCase extends Orchestra { - public function setUp(): void + protected function setUp(): void { parent::setUp(); From c8065a4640737102a6eaa0fc7433264e318bd403 Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 7 Mar 2022 15:17:13 +0000 Subject: [PATCH 088/229] Use Pest test runner --- .github/workflows/run-tests.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 8eb2671..a6c038a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -40,4 +40,4 @@ jobs: composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests - run: vendor/bin/phpunit + run: vendor/bin/pest diff --git a/composer.json b/composer.json index d56f7db..16a282c 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ }, "scripts": { "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes", - "test": "vendor/bin/phpunit" + "test": "vendor/bin/pest" }, "config": { "sort-packages": true From 60fffe566a3f362c852e09ce1c339bcf1dab6b1a Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 7 Mar 2022 15:17:38 +0000 Subject: [PATCH 089/229] Fix styling --- tests/TranslatableTest.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 9708820..136341e 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -397,7 +397,8 @@ public function getNameAttribute($value): string it('can use mutators on translated attributes', function () { $testModel = new class () extends TestModel { - public function setNameAttribute($value) { + public function setNameAttribute($value) + { $this->attributes['name'] = "I just mutated {$value}"; } }; @@ -454,7 +455,8 @@ public function setNameAttribute($value) { it('can correctly set a field when a mutator is defined', function () { $testModel = (new class () extends TestModel { - public function setNameAttribute($value) { + public function setNameAttribute($value) + { $this->attributes['name'] = "I just mutated {$value}"; } }); @@ -467,7 +469,8 @@ public function setNameAttribute($value) { it('can set multiple translations when a mutator is defined', function () { $testModel = (new class () extends TestModel { - public function setNameAttribute($value) { + public function setNameAttribute($value) + { $this->attributes['name'] = "I just mutated {$value}"; } }); @@ -506,7 +509,8 @@ public function setNameAttribute($value) { it('can translate a field based on the translations of another one', function () { $testModel = (new class () extends TestModel { - public function setOtherFieldAttribute($value, $locale = 'en') { + public function setOtherFieldAttribute($value, $locale = 'en') + { $this->attributes['other_field'] = $value.' '.$this->getTranslation('name', $locale); } }); @@ -533,7 +537,8 @@ public function setOtherFieldAttribute($value, $locale = 'en') { it('handle null value from database', function () { $testModel = (new class () extends TestModel { - public function setAttributesExternally(array $attributes) { + public function setAttributesExternally(array $attributes) + { $this->attributes = $attributes; } }); From 4369fdeb0245d70c74c296765466e68d1ff2453f Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 7 Mar 2022 18:03:04 +0100 Subject: [PATCH 090/229] fix tests --- tests/EventTest.php | 3 +- tests/Pest.php | 40 ++------------------------- tests/{ => TestSupport}/TestModel.php | 2 +- tests/TranslatableTest.php | 3 +- 4 files changed, 5 insertions(+), 43 deletions(-) rename tests/{ => TestSupport}/TestModel.php (90%) diff --git a/tests/EventTest.php b/tests/EventTest.php index ff6a341..8ca73fa 100644 --- a/tests/EventTest.php +++ b/tests/EventTest.php @@ -2,8 +2,7 @@ use Illuminate\Support\Facades\Event; use Spatie\Translatable\Events\TranslationHasBeenSetEvent; - -uses(TestCase::class); +use Spatie\Translatable\Test\TestSupport\TestModel; beforeEach(function () { Event::fake(); diff --git a/tests/Pest.php b/tests/Pest.php index 2db4bff..305417a 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,42 +1,6 @@ in('tests'); +use Spatie\Translatable\Test\TestCase; -/* -|-------------------------------------------------------------------------- -| Test Case -|-------------------------------------------------------------------------- -| -| The closure you provide to your test functions is always bound to a specific PHPUnit test -| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may -| need to change it using the "uses()" function to bind a different classes or traits. -| -*/ +uses(TestCase::class)->in(__DIR__); -/** @link https://pestphp.com/docs/underlying-test-case */ - -/* -|-------------------------------------------------------------------------- -| Expectations -|-------------------------------------------------------------------------- -| -| When you're writing tests, you often need to check that values meet certain conditions. The -| "expect()" function gives you access to a set of "expectations" methods that you can use -| to assert different things. Of course, you may extend the Expectation API at any time. -| -*/ - -/** @link https://pestphp.com/docs/expectations#custom-expectations */ - -/* -|-------------------------------------------------------------------------- -| Functions -|-------------------------------------------------------------------------- -| -| While Pest is very powerful out-of-the-box, you may have some testing code specific to your -| project that you don't want to repeat in every file. Here you can also expose helpers as -| global functions to help you to reduce the number of lines of code in your test files. -| -*/ - -/** @link https://pestphp.com/docs/helpers */ diff --git a/tests/TestModel.php b/tests/TestSupport/TestModel.php similarity index 90% rename from tests/TestModel.php rename to tests/TestSupport/TestModel.php index 17c831c..f10e18b 100644 --- a/tests/TestModel.php +++ b/tests/TestSupport/TestModel.php @@ -1,6 +1,6 @@ testModel = new TestModel(); From f410ca3434fbc7ebac4a54cc7a9293c65de58104 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 7 Mar 2022 17:03:50 +0000 Subject: [PATCH 091/229] Fix styling --- tests/Pest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 305417a..4bf710e 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -3,4 +3,3 @@ use Spatie\Translatable\Test\TestCase; uses(TestCase::class)->in(__DIR__); - From be3d9c6310c565a9c35035c57703b6ebc511daf6 Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Wed, 9 Mar 2022 17:20:45 +0100 Subject: [PATCH 092/229] Add banner --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8e3d02c..e8f3b0c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ + +[](https://supportukrainenow.org) + # A trait to make Eloquent models translatable [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) From 825e60ac984b95f29dd3e4daa61405330b6cef5a Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Mon, 21 Mar 2022 13:05:31 +0100 Subject: [PATCH 093/229] Change copy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e8f3b0c..afb27cb 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. ## Security -If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker. +If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. ## Postcardware From 4a801c13501716b17c6e5c098d36e6800d170105 Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Mon, 21 Mar 2022 13:36:25 +0100 Subject: [PATCH 094/229] Change copy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afb27cb..51afab4 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ composer test ## Contributing -Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. +Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. ## Security From 706b298a9aab3c5e9cf092f0b3cdef001b2798ac Mon Sep 17 00:00:00 2001 From: Adriaan Marain Date: Mon, 21 Mar 2022 13:51:59 +0100 Subject: [PATCH 095/229] Use organisation-wide community health files --- .github/CONTRIBUTING.md | 55 ----------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 4da74e3..0000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,55 +0,0 @@ -# Contributing - -Contributions are **welcome** and will be fully **credited**. - -Please read and understand the contribution guide before creating an issue or pull request. - -## Etiquette - -This project is open source, and as such, the maintainers give their free time to build and maintain the source code -held within. They make the code freely available in the hope that it will be of use to other developers. It would be -extremely unfair for them to suffer abuse or anger for their hard work. - -Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the -world that developers are civilized and selfless people. - -It's the duty of the maintainer to ensure that all submissions to the project are of sufficient -quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. - -## Viability - -When requesting or submitting new features, first consider whether it might be useful to others. Open -source projects are used by many developers, who may have entirely different needs to your own. Think about -whether or not your feature is likely to be used by other users of the project. - -## Procedure - -Before filing an issue: - -- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. -- Check to make sure your feature suggestion isn't already present within the project. -- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. -- Check the pull requests tab to ensure that the feature isn't already in progress. - -Before submitting a pull request: - -- Check the codebase to ensure that your feature doesn't already exist. -- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. - -## Requirements - -If the project maintainer has any additional requirements, you will find them listed here. - -- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). - -- **Add tests!** - Your patch won't be accepted if it doesn't have tests. - -- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. - -- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. - -- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. - -- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. - -**Happy coding**! From add1605d2d5713e7dd0f7c98ebef92282634295d Mon Sep 17 00:00:00 2001 From: sami-cha <36895290+sami-cha@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:17:08 +0200 Subject: [PATCH 096/229] Fix typo in "Getting and setting translations" There is a typo in documentation example. The attribute name is "name", not "hello". This PR fix it. --- docs/basic-usage/getting-and-settings-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basic-usage/getting-and-settings-translations.md b/docs/basic-usage/getting-and-settings-translations.md index d132757..49a27ed 100644 --- a/docs/basic-usage/getting-and-settings-translations.md +++ b/docs/basic-usage/getting-and-settings-translations.md @@ -47,7 +47,7 @@ $newItem->name = $translations; // alternatively, use the `setTranslations` method -$newsItem->setTranslations('hello', $translations); +$newsItem->setTranslations('name', $translations); $newItem->save(); ``` From f414013c05adb959b98d13de32eecfc080f0e39d Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 28 Apr 2022 11:46:22 -0300 Subject: [PATCH 097/229] Fix typo in advanced usage docs directory name --- docs/{avanced-usage => advanced-usage}/_index.md | 0 docs/{avanced-usage => advanced-usage}/available-events.md | 0 .../customize-the-toarray-method.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename docs/{avanced-usage => advanced-usage}/_index.md (100%) rename docs/{avanced-usage => advanced-usage}/available-events.md (100%) rename docs/{avanced-usage => advanced-usage}/customize-the-toarray-method.md (100%) diff --git a/docs/avanced-usage/_index.md b/docs/advanced-usage/_index.md similarity index 100% rename from docs/avanced-usage/_index.md rename to docs/advanced-usage/_index.md diff --git a/docs/avanced-usage/available-events.md b/docs/advanced-usage/available-events.md similarity index 100% rename from docs/avanced-usage/available-events.md rename to docs/advanced-usage/available-events.md diff --git a/docs/avanced-usage/customize-the-toarray-method.md b/docs/advanced-usage/customize-the-toarray-method.md similarity index 100% rename from docs/avanced-usage/customize-the-toarray-method.md rename to docs/advanced-usage/customize-the-toarray-method.md From 7568d8ec7641c786da37e495bf578405850bc381 Mon Sep 17 00:00:00 2001 From: "Olivier B. Deland" Date: Wed, 11 May 2022 13:58:48 -0400 Subject: [PATCH 098/229] Fixed example The example given did not demonstrate usage of the forgetAllTranslations() method. --- docs/basic-usage/removing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basic-usage/removing-translations.md b/docs/basic-usage/removing-translations.md index 3e205c2..d115e81 100644 --- a/docs/basic-usage/removing-translations.md +++ b/docs/basic-usage/removing-translations.md @@ -24,5 +24,5 @@ public function forgetAllTranslations(string $locale) Here's an example: ```php -$newsItem->forgetTranslation('name'); +$newsItem->forgetAllTranslations('nl'); ``` From b0ee6e06c666dcfb97fb1b4ff141b34e59806f13 Mon Sep 17 00:00:00 2001 From: Ahmet Barut Date: Fri, 21 Oct 2022 11:10:33 +0300 Subject: [PATCH 099/229] added locales method --- src/HasTranslations.php | 9 +++++++++ tests/TranslatableTest.php | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 0f9b141..3054d83 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -304,4 +304,13 @@ public function getCasts(): array array_fill_keys($this->getTranslatableAttributes(), 'array'), ); } + + public function locales(): array + { + return array_unique( + array_reduce($this->getTranslatableAttributes(), function ($result, $item) { + return array_merge($result, $this->getTranslatedLocales($item)); + }, []) + ); + } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 29c09e6..45febe1 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -371,7 +371,8 @@ }); 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'; @@ -382,7 +383,8 @@ public function getOtherFieldAttribute(): string }); 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}"; @@ -395,7 +397,8 @@ public function getNameAttribute($value): string }); 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}"; @@ -453,7 +456,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}"; @@ -467,7 +471,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}"; @@ -507,10 +512,11 @@ public function setNameAttribute($value) }); 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); } }); @@ -535,7 +541,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; @@ -711,3 +718,16 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->getTranslation('name', 'fr'))->toBe('testValue_en'); }); + +it('will return all locales when getting all translations', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'tr', 'testValue_tr'); + $this->testModel->save(); + + expect($this->testModel->locales())->toEqual([ + 'en', + 'fr', + 'tr', + ]); +}); From ea66cd3db8d187e7ceb4324ee0d9dc273cf4d90d Mon Sep 17 00:00:00 2001 From: freekmurze Date: Fri, 21 Oct 2022 08:44:27 +0000 Subject: [PATCH 100/229] Fix styling --- tests/TranslatableTest.php | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 45febe1..ab234d0 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -371,8 +371,7 @@ }); 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'; @@ -383,8 +382,7 @@ public function getOtherFieldAttribute(): string }); 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}"; @@ -397,8 +395,7 @@ public function getNameAttribute($value): string }); 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}"; @@ -456,8 +453,7 @@ 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}"; @@ -471,8 +467,7 @@ 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}"; @@ -512,8 +507,7 @@ public function setNameAttribute($value) }); 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); @@ -541,8 +535,7 @@ 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; From 38b45e6fb134a382c843a68cd7c59b8f4cabf4e2 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Fri, 21 Oct 2022 08:44:44 +0000 Subject: [PATCH 101/229] Update CHANGELOG --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0e9be..893f434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.1.0 - 2022-10-21 + +### What's Changed + +- PHPUnit to Pest Converter by @freekmurze in https://github.com/spatie/laravel-translatable/pull/335 +- Fix typo in "Getting and setting translations" by @sami-cha in https://github.com/spatie/laravel-translatable/pull/346 +- Fix typo in advanced usage docs directory name by @greatislander in https://github.com/spatie/laravel-translatable/pull/347 +- Fixed example for forgetAllTranslations() method. by @odeland in https://github.com/spatie/laravel-translatable/pull/348 +- added locales method by @ahmetbarut in https://github.com/spatie/laravel-translatable/pull/361 + +### New Contributors + +- @sami-cha made their first contribution in https://github.com/spatie/laravel-translatable/pull/346 +- @greatislander made their first contribution in https://github.com/spatie/laravel-translatable/pull/347 +- @odeland made their first contribution in https://github.com/spatie/laravel-translatable/pull/348 +- @ahmetbarut made their first contribution in https://github.com/spatie/laravel-translatable/pull/361 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.0.0...6.1.0 + ## 6.0.0 - 2022-03-07 - improved fallback customisations From d1c49e8bb38fb28ea90a826bda4c2fb1507fab72 Mon Sep 17 00:00:00 2001 From: Patrick Organ Date: Sun, 27 Nov 2022 18:14:06 -0500 Subject: [PATCH 102/229] add dependabot configuration --- .github/dependabot.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a76dd83 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 + +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" From a70f24f21549fc6e7c02fa59014a05b1a3323b13 Mon Sep 17 00:00:00 2001 From: Patrick Organ Date: Sun, 27 Nov 2022 18:14:06 -0500 Subject: [PATCH 103/229] add workflow to auto-merge dependabot PRs --- .github/workflows/dependabot-auto-merge.yml | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/dependabot-auto-merge.yml diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..78e5cd2 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,40 @@ +name: dependabot-auto-merge +on: pull_request_target + +permissions: + pull-requests: write + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.3.5 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + compat-lookup: true + + - name: Auto-merge Dependabot PRs for semver-minor updates + if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Auto-merge Dependabot PRs for semver-patch updates + if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Auto-merge Dependabot PRs for Action major versions when compatibility is higher than 90% + if: ${{steps.metadata.outputs.package-ecosystem == 'github_actions' && steps.metadata.outputs.update-type == 'version-update:semver-major' && steps.metadata.outputs.compatibility-score >= 90}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} From 835097fe515424387d44174ae194a9c1594ca0ed Mon Sep 17 00:00:00 2001 From: Patrick Organ Date: Sun, 27 Nov 2022 18:17:25 -0500 Subject: [PATCH 104/229] allow pest plugin during tests --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 16a282c..8f6ba0a 100644 --- a/composer.json +++ b/composer.json @@ -52,6 +52,9 @@ "test": "vendor/bin/pest" }, "config": { + "allow-plugins": { + "pestphp/pest-plugin": true + }, "sort-packages": true }, "extra": { From 916a03c0cf9ade7f4ff8f277cc98f07bd090ce2e Mon Sep 17 00:00:00 2001 From: Patrick Organ Date: Sun, 27 Nov 2022 23:09:43 -0500 Subject: [PATCH 105/229] add php 8.2 to workflow --- .github/workflows/run-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a6c038a..190cd98 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.1, 8.0] + php: [8.2, 8.1, 8.0] laravel: [9.*] stability: [prefer-lowest, prefer-stable] include: From f8b22d93c74a5de7f34efa1b79bef7ff018fa239 Mon Sep 17 00:00:00 2001 From: Patrick Organ Date: Sun, 27 Nov 2022 23:15:09 -0500 Subject: [PATCH 106/229] use nesbot/carbon 2.63 minimum version --- .github/workflows/run-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 190cd98..2798019 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -15,6 +15,7 @@ jobs: include: - laravel: 9.* testbench: 7.* + carbon: ^2.63 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} @@ -36,7 +37,7 @@ jobs: - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "nesbot/carbon:${{ matrix.carbon }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests From 482985063f5a1ba7fba55d165d9101e1852dbb1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Nov 2022 07:26:43 +0000 Subject: [PATCH 107/229] Bump actions/checkout from 2 to 3 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- .github/workflows/run-tests.yml | 2 +- .github/workflows/update-changelog.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 62f6106..937731b 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -8,7 +8,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 2798019..e50e21a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index fa56639..b20f3b6 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: main From 063588ba7aa7f5a2f18736c9181eba4fe0623d4d Mon Sep 17 00:00:00 2001 From: Ahmet Barut Date: Fri, 21 Oct 2022 11:10:33 +0300 Subject: [PATCH 108/229] added locales method --- tests/TranslatableTest.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index ab234d0..45febe1 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -371,7 +371,8 @@ }); 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'; @@ -382,7 +383,8 @@ public function getOtherFieldAttribute(): string }); 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}"; @@ -395,7 +397,8 @@ public function getNameAttribute($value): string }); 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}"; @@ -453,7 +456,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}"; @@ -467,7 +471,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}"; @@ -507,7 +512,8 @@ public function setNameAttribute($value) }); 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); @@ -535,7 +541,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; From 641fe0c16ae242145f6c72971d1970d60d638525 Mon Sep 17 00:00:00 2001 From: ahmetbarut Date: Thu, 15 Dec 2022 07:52:52 +0000 Subject: [PATCH 109/229] Fix styling --- tests/TranslatableTest.php | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 45febe1..ab234d0 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -371,8 +371,7 @@ }); 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'; @@ -383,8 +382,7 @@ public function getOtherFieldAttribute(): string }); 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}"; @@ -397,8 +395,7 @@ public function getNameAttribute($value): string }); 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}"; @@ -456,8 +453,7 @@ 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}"; @@ -471,8 +467,7 @@ 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}"; @@ -512,8 +507,7 @@ public function setNameAttribute($value) }); 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); @@ -541,8 +535,7 @@ 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; From 2730190005a835be2cd8a3cf5437e2adec795aab Mon Sep 17 00:00:00 2001 From: Ahmet Barut Date: Thu, 15 Dec 2022 11:13:26 +0300 Subject: [PATCH 110/229] added whereLocale and whereLocales methods --- src/HasTranslations.php | 15 +++++++++++++++ tests/TranslatableTest.php | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 3054d83..a25ef79 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -3,6 +3,7 @@ namespace Spatie\Translatable; use Exception; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Str; use Spatie\Translatable\Events\TranslationHasBeenSetEvent; @@ -313,4 +314,18 @@ public function locales(): array }, []) ); } + + public static function whereLocale(string $column, string $locale): Builder + { + return static::query()->whereNotNull("{$column}->{$locale}"); + } + + public static function whereLocales(string $column, array $locales): Builder + { + return static::query()->where(function (Builder $query) use ($column, $locales) { + foreach ($locales as $locale) { + $query->orWhereNotNull("{$column}->{$locale}"); + } + }); + } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index ab234d0..825d544 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -724,3 +724,25 @@ public function setAttributesExternally(array $attributes) 'tr', ]); }); + +it('queries the database whether a locale exists', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'tr', 'testValue_tr'); + $this->testModel->save(); + + expect($this->testModel->whereLocale('name', 'en')->get())->toHaveCount(1); + + expect($this->testModel->whereLocale('name', 'de')->get())->toHaveCount(0); +}); + +it('queries the database for multiple locales', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'tr', 'testValue_tr'); + $this->testModel->save(); + + expect($this->testModel->whereLocales('name', ['en', 'tr'])->get())->toHaveCount(1); + + expect($this->testModel->whereLocales('name', ['de', 'be'])->get())->toHaveCount(0); +}); From e001426def09342dd2723bf28c7a9313621f1d69 Mon Sep 17 00:00:00 2001 From: Ahmet Barut Date: Thu, 15 Dec 2022 12:22:57 +0300 Subject: [PATCH 111/229] added example and docs --- README.md | 6 ++++++ .../basic-usage/getting-and-settings-translations.md | 12 ++++++++++++ docs/basic-usage/querying-translations.md | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 51afab4..6ab158e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,12 @@ $newsItem->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands' app()->setLocale('nl'); $newsItem->name; // Returns 'Naam in het Nederlands' + +// If you want to query records based on locales, you can use the `whereLocale` and `whereLocales` methods. + +NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a name in English + +NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch ``` ## Support us diff --git a/docs/basic-usage/getting-and-settings-translations.md b/docs/basic-usage/getting-and-settings-translations.md index 49a27ed..b352f3d 100644 --- a/docs/basic-usage/getting-and-settings-translations.md +++ b/docs/basic-usage/getting-and-settings-translations.md @@ -109,3 +109,15 @@ $translations = [ $newsItem->setTranslations('hello', $translations); $newsItem->getTranslations('hello', ['en', 'fr']); // returns ['en' => 'Hello', 'fr' => 'Bonjour'] ``` + +### Get locales that a model has + +You can get all locales that a model has by calling `locales()` without an argument: + +```php + $translations = ['en' => 'hello', 'es' => 'hola']; + $newItem->name = $translations; + $newItem->save(); + + $newItem->locales(); // returns ['en', 'es'] +``` diff --git a/docs/basic-usage/querying-translations.md b/docs/basic-usage/querying-translations.md index ed990ea..210c505 100644 --- a/docs/basic-usage/querying-translations.md +++ b/docs/basic-usage/querying-translations.md @@ -14,3 +14,11 @@ Or if you're using MariaDB 10.2.3 or above : ```php NewsItem::whereRaw("JSON_EXTRACT(name, '$.en') = 'Name in English'")->get(); ``` + +If you want to query records based on locales, you can use the `whereLocale` and `whereLocales` methods. + +```php +NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a name in English + +NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch +``` From df9f1f6b7fdcf63be257b33270c756b63aa6499c Mon Sep 17 00:00:00 2001 From: freekmurze Date: Fri, 23 Dec 2022 10:19:32 +0000 Subject: [PATCH 112/229] Update CHANGELOG --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 893f434..4ac870c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.2.0 - 2022-12-23 + +### What's Changed + +- Add Dependabot Automation by @patinthehat in https://github.com/spatie/laravel-translatable/pull/366 +- Add PHP 8.2 Support by @patinthehat in https://github.com/spatie/laravel-translatable/pull/367 +- Bump actions/checkout from 2 to 3 by @dependabot in https://github.com/spatie/laravel-translatable/pull/368 +- Added whereLocale and whereLocales methods by @ahmetbarut in https://github.com/spatie/laravel-translatable/pull/370 + +### New Contributors + +- @dependabot made their first contribution in https://github.com/spatie/laravel-translatable/pull/368 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.1.0...6.2.0 + ## 6.1.0 - 2022-10-21 ### What's Changed From b3f6fa43ce05d7640ca9eacf4fee9c0037fc84d2 Mon Sep 17 00:00:00 2001 From: erikn69 Date: Fri, 13 Jan 2023 17:58:59 -0500 Subject: [PATCH 113/229] Laravel 10.x support --- .github/workflows/run-tests.yml | 8 +++++++- composer.json | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index e50e21a..f98dac1 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,12 +10,18 @@ jobs: matrix: os: [ubuntu-latest] php: [8.2, 8.1, 8.0] - laravel: [9.*] + laravel: [10.*, 9.*] stability: [prefer-lowest, prefer-stable] include: + - laravel: 10.* + testbench: 8.* + carbon: ^2.63 - laravel: 9.* testbench: 7.* carbon: ^2.63 + exclude: + - laravel: 10.* + php: 8.0 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/composer.json b/composer.json index 8f6ba0a..da9d715 100644 --- a/composer.json +++ b/composer.json @@ -28,13 +28,13 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^9.0", - "illuminate/support": "^9.0", + "illuminate/database": "^9.0|^10.0", + "illuminate/support": "^9.0|^10.0", "spatie/laravel-package-tools": "^1.11" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^7.0", + "orchestra/testbench": "^7.0|^8.0", "pestphp/pest": "^1.20" }, "autoload": { From 90f6e005466c952a96439b53d7e28a0f318f29b1 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Sat, 14 Jan 2023 20:58:26 +0000 Subject: [PATCH 114/229] Update CHANGELOG --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ac870c..48d5c64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.3.0 - 2023-01-14 + +### What's Changed + +- Laravel 10.x support by @erikn69 in https://github.com/spatie/laravel-translatable/pull/374 + +### New Contributors + +- @erikn69 made their first contribution in https://github.com/spatie/laravel-translatable/pull/374 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.2.0...6.3.0 + ## 6.2.0 - 2022-12-23 ### What's Changed From 5624552ae6f7a8a58ab3c0dae39087919785e045 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Tue, 24 Jan 2023 08:28:00 +0100 Subject: [PATCH 115/229] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 6ab158e..f845a67 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ - -[](https://supportukrainenow.org) - # A trait to make Eloquent models translatable [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) From 7bfd950ff63b1fc20ccf2bdc5f6e246572767d16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 02:26:26 +0000 Subject: [PATCH 116/229] Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.5 to 1.3.6. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.5...v1.3.6) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 78e5cd2..f2e85e7 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.3.5 + uses: dependabot/fetch-metadata@v1.3.6 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From bb0f3ce109e95586232faa06c9420a13820e9a54 Mon Sep 17 00:00:00 2001 From: Alexander Gomzyakov Date: Mon, 6 Feb 2023 15:50:35 +0500 Subject: [PATCH 117/229] Fix badge with `tests` status in `README.md` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f845a67..9886a0b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -![GitHub Workflow Status](https://img.shields.io/github/workflow/status/spatie/laravel-translatable/run-tests?label=tests) +![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-translatable/run-tests.yml) [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. From e90dbe46c350a3097901d0f112a0058c001055cf Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 17 Mar 2023 22:34:43 +0330 Subject: [PATCH 118/229] Update README.md --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9886a0b..2d6c934 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,24 @@ This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. -Once the trait is installed on the model you can do these things: +## Usage ```php -$newsItem = new NewsItem; // This is an Eloquent model +// apply HasTranslations trait to a model +use Illuminate\Database\Eloquent\Model; +use Spatie\Translatable\HasTranslations; + +class NewsItem extends Model +{ + use HasTranslations; + + // ... +} +``` +After the trait is applied on the model you can do these things: + +```php +$newsItem = new NewsItem; $newsItem ->setTranslation('name', 'en', 'Name in English') ->setTranslation('name', 'nl', 'Naam in het Nederlands') From ad6263fbcceaa7e4ef6dd2b5b5a8348126735577 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Sun, 19 Mar 2023 18:48:56 +0100 Subject: [PATCH 119/229] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2d6c934..5ea2cbd 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,9 @@ ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-translatable/run-tests.yml) [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) -This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. - -## Usage +This package contains a trait `HasTranslations` to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. ```php -// apply HasTranslations trait to a model use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; @@ -21,6 +18,7 @@ class NewsItem extends Model // ... } ``` + After the trait is applied on the model you can do these things: ```php From 281da82bfcff7739cbb31a601f4e76d0c5197295 Mon Sep 17 00:00:00 2001 From: Yoeri Boven Date: Wed, 15 Mar 2023 20:21:09 +0100 Subject: [PATCH 120/229] wip --- src/HasTranslations.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index a25ef79..580d1ca 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -18,13 +18,22 @@ public static function usingLocale(string $locale): self return (new self())->setLocale($locale); } + public function useFallbackLocale(): bool + { + if (property_exists($this, 'useFallbackLocale')) { + return $this->useFallbackLocale; + } + + return true; + } + public function getAttributeValue($key): mixed { if (! $this->isTranslatableAttribute($key)) { return parent::getAttributeValue($key); } - return $this->getTranslation($key, $this->getLocale()); + return $this->getTranslation($key, $this->getLocale(), $this->useFallbackLocale()); } public function setAttribute($key, $value) From 80f191745f18bcafd73e408c56a87f09dcd88100 Mon Sep 17 00:00:00 2001 From: Yoeri Boven Date: Wed, 15 Mar 2023 20:33:14 +0100 Subject: [PATCH 121/229] add test --- .../TestSupport/TestModelWithoutFallback.php | 25 +++++++++++++++++++ tests/TranslatableTest.php | 14 +++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/TestSupport/TestModelWithoutFallback.php diff --git a/tests/TestSupport/TestModelWithoutFallback.php b/tests/TestSupport/TestModelWithoutFallback.php new file mode 100644 index 0000000..ed9eceb --- /dev/null +++ b/tests/TestSupport/TestModelWithoutFallback.php @@ -0,0 +1,25 @@ +attributes['field_with_mutator'] = $value; + } +} diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 825d544..9481c89 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -4,6 +4,7 @@ use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; use Spatie\Translatable\Facades\Translatable; use Spatie\Translatable\Test\TestSupport\TestModel; +use Spatie\Translatable\Test\TestSupport\TestModelWithoutFallback; beforeEach(function () { $this->testModel = new TestModel(); @@ -746,3 +747,16 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->whereLocales('name', ['de', 'be'])->get())->toHaveCount(0); }); + +it('can disable attribute locale fallback on a per model basis', function () { + config()->set('app.fallback_locale', 'en'); + + $model = new TestModelWithoutFallback(); + + $model->setTranslation('name', 'en', 'testValue_en'); + $model->save(); + + $model->setLocale('fr'); + + expect($model->name)->toBe(''); +}); From f472fbaec8a3d44096d3c6ed029484d0bf9116a7 Mon Sep 17 00:00:00 2001 From: Yoeri Boven Date: Fri, 17 Mar 2023 18:28:41 +0100 Subject: [PATCH 122/229] docs --- .../handling-missing-translations.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/basic-usage/handling-missing-translations.md b/docs/basic-usage/handling-missing-translations.md index 2a146e4..05986b7 100644 --- a/docs/basic-usage/handling-missing-translations.md +++ b/docs/basic-usage/handling-missing-translations.md @@ -97,3 +97,22 @@ Translatable::fallback(missingKeyCallback: function ( return MyRemoteTranslationService::getAutomaticTranslation($fallbackTranslation, $fallbackLocale, $locale); }); ``` + +### Disabling fallbacks on a per model basis +By default, a fallback will be used when you access a non-existent translation attribute. + +You can disable fallbacks on a model with the `$useFallbackLocale` property. + +```php +use Illuminate\Database\Eloquent\Model; +use Spatie\Translatable\HasTranslations; + +class NewsItem extends Model +{ + use HasTranslations; + + public $translatable = ['name']; + + protected $useFallbackLocale = false; +} +``` From c17f43d458e8b5eac3227b396088dc9a0d95620b Mon Sep 17 00:00:00 2001 From: freekmurze Date: Sun, 19 Mar 2023 17:51:16 +0000 Subject: [PATCH 123/229] Update CHANGELOG --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d5c64..0d33725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.4.0 - 2023-03-19 + +### What's Changed + +- Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/spatie/laravel-translatable/pull/376 +- Fix badge with `tests` status in `README.md` by @gomzyakov in https://github.com/spatie/laravel-translatable/pull/377 +- Update README.md by @alirezasalehizadeh in https://github.com/spatie/laravel-translatable/pull/381 +- Enable fallback locale on a per model basis by @yoeriboven in https://github.com/spatie/laravel-translatable/pull/380 + +### New Contributors + +- @gomzyakov made their first contribution in https://github.com/spatie/laravel-translatable/pull/377 +- @alirezasalehizadeh made their first contribution in https://github.com/spatie/laravel-translatable/pull/381 +- @yoeriboven made their first contribution in https://github.com/spatie/laravel-translatable/pull/380 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.3.0...6.4.0 + ## 6.3.0 - 2023-01-14 ### What's Changed From 1e57e90a75245d9dddea4555cfb49835019d3a5c Mon Sep 17 00:00:00 2001 From: MOHAMMAD RASIM Date: Mon, 10 Apr 2023 18:41:23 +0300 Subject: [PATCH 124/229] update customize-the-toarray-method.md The current example doesn't respect the selected columns by the query builder and returns unselected attributes as empty string if they are translatable This new function will account for this issue --- docs/advanced-usage/customize-the-toarray-method.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/advanced-usage/customize-the-toarray-method.md b/docs/advanced-usage/customize-the-toarray-method.md index 0b50843..16fafea 100644 --- a/docs/advanced-usage/customize-the-toarray-method.md +++ b/docs/advanced-usage/customize-the-toarray-method.md @@ -17,11 +17,15 @@ trait HasTranslations public function toArray() { - $attributes = parent::toArray(); - foreach ($this->getTranslatableAttributes() as $field) { + $attributes = $this->attributesToArray(); // attributes selected by the query + // remove attributes if they are not selected + $translatables = array_filter($this->getTranslatableAttributes(), function ($key) use ($attributes) { + return array_key_exists($key, $attributes); + }); + foreach ($translatables as $field) { $attributes[$field] = $this->getTranslation($field, \App::getLocale()); } - return $attributes; + return array_merge($attributes, $this->relationsToArray()); } } ``` From de016d771e85d82b9993eae3b5894dd3f4083960 Mon Sep 17 00:00:00 2001 From: Bram Date: Fri, 24 Mar 2023 11:07:08 +0000 Subject: [PATCH 125/229] Add Factory->translatable macro --- src/TranslatableServiceProvider.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index ef8bd33..36aec04 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -4,6 +4,7 @@ use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; +use Illuminate\Database\Eloquent\Factories\Factory; class TranslatableServiceProvider extends PackageServiceProvider { @@ -17,5 +18,13 @@ public function packageRegistered(): void { $this->app->singleton(Translatable::class, fn () => new Translatable()); $this->app->bind('translatable', Translatable::class); + + Factory::macro('translatable', function (string|array $locales, mixed $value) { + return json_encode( + is_array($value) + ? array_combine((array)$locale, $value) + : array_fill_keys((array)$locale, $value) + ); + }); } } From 19764c8ff1d3b9d6b65ed6490f425e759f09c590 Mon Sep 17 00:00:00 2001 From: Bram Date: Tue, 28 Mar 2023 10:39:03 +0100 Subject: [PATCH 126/229] Update TranslatableServiceProvider.php --- src/TranslatableServiceProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index 36aec04..ed95fb2 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -22,8 +22,8 @@ public function packageRegistered(): void Factory::macro('translatable', function (string|array $locales, mixed $value) { return json_encode( is_array($value) - ? array_combine((array)$locale, $value) - : array_fill_keys((array)$locale, $value) + ? array_combine((array)$locales, $value) + : array_fill_keys((array)$locales, $value) ); }); } From d870075176b91e69ceda57e087f8294a01bd2f4d Mon Sep 17 00:00:00 2001 From: Bram Ceulemans Date: Tue, 18 Apr 2023 12:05:34 +0100 Subject: [PATCH 127/229] Add basic tests --- src/TranslatableServiceProvider.php | 12 +++++------- tests/TranslatableTest.php | 9 +++++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index ed95fb2..73681e2 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -2,9 +2,9 @@ namespace Spatie\Translatable; +use Illuminate\Database\Eloquent\Factories\Factory; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; -use Illuminate\Database\Eloquent\Factories\Factory; class TranslatableServiceProvider extends PackageServiceProvider { @@ -18,13 +18,11 @@ public function packageRegistered(): void { $this->app->singleton(Translatable::class, fn () => new Translatable()); $this->app->bind('translatable', Translatable::class); - + Factory::macro('translatable', function (string|array $locales, mixed $value) { - return json_encode( - is_array($value) - ? array_combine((array)$locales, $value) - : array_fill_keys((array)$locales, $value) - ); + return is_array($value) + ? array_combine((array)$locales, $value) + : array_fill_keys((array)$locales, $value); }); } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 9481c89..c2beb0c 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1,5 +1,6 @@ name)->toBe(''); }); + +it('translatable macro meets expectations', function (mixed $expected, string|array $locales, mixed $value) { + expect(Factory::translatable($locales, $value))->toEqual($expected); +})->with([ + [['en' => 'english'], 'en', 'english'], + [['en' => 'english', 'nl' => 'english'], ['en', 'nl'], 'english'], + [['en' => 'english', 'nl' => 'dutch'], ['en', 'nl'], ['english', 'dutch']], +]); From 4352fca98d8db5126219963ba3463acaf895254e Mon Sep 17 00:00:00 2001 From: Bram Ceulemans Date: Tue, 18 Apr 2023 13:16:26 +0100 Subject: [PATCH 128/229] Add documentation --- docs/advanced-usage/usage-with-factories.md | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/advanced-usage/usage-with-factories.md diff --git a/docs/advanced-usage/usage-with-factories.md b/docs/advanced-usage/usage-with-factories.md new file mode 100644 index 0000000..87f50ad --- /dev/null +++ b/docs/advanced-usage/usage-with-factories.md @@ -0,0 +1,41 @@ +--- +title: Usage with factories +weight: 1 +--- + +A small helper for making translations has been added for use in factories: + +This is what a few possible usages look like: + +```php +/** @var $this \Illuminate\Database\Eloquent\Factories\Factory */ + +$this->translatable('en', 'english') +// output: ['en' => 'english'] + +$this->translatable(['en', 'nl'], 'english') +// output: ['en' => 'english', 'nl' => 'english'] + +$this->translatable(['en', 'nl'], ['english', 'dutch']) +// output: ['en' => 'english', 'nl' => 'dutch'] +``` + +The helper can also be used outside of factories using the following syntax: + +```php +\Illuminate\Database\Eloquent\Factories\Factory::translatable('en', 'english'); +// output: ['en' => 'english'] +``` + +## In a Factory + +```php +class UserFactory extends \Illuminate\Database\Eloquent\Factories\Factory { + public function definition(): array + { + return [ + 'bio' => $this->translatable('en', 'english'), + ]; + } +} +``` From 732e46b8c664a6da6d5d14751185c1844e2b5bc1 Mon Sep 17 00:00:00 2001 From: Bram Ceulemans Date: Thu, 20 Apr 2023 09:43:00 +0100 Subject: [PATCH 129/229] Rename translatable macro to translations --- docs/advanced-usage/usage-with-factories.md | 10 +++++----- src/TranslatableServiceProvider.php | 2 +- tests/TranslatableTest.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/advanced-usage/usage-with-factories.md b/docs/advanced-usage/usage-with-factories.md index 87f50ad..308a72b 100644 --- a/docs/advanced-usage/usage-with-factories.md +++ b/docs/advanced-usage/usage-with-factories.md @@ -10,20 +10,20 @@ This is what a few possible usages look like: ```php /** @var $this \Illuminate\Database\Eloquent\Factories\Factory */ -$this->translatable('en', 'english') +$this->translations('en', 'english') // output: ['en' => 'english'] -$this->translatable(['en', 'nl'], 'english') +$this->translations(['en', 'nl'], 'english') // output: ['en' => 'english', 'nl' => 'english'] -$this->translatable(['en', 'nl'], ['english', 'dutch']) +$this->translations(['en', 'nl'], ['english', 'dutch']) // output: ['en' => 'english', 'nl' => 'dutch'] ``` The helper can also be used outside of factories using the following syntax: ```php -\Illuminate\Database\Eloquent\Factories\Factory::translatable('en', 'english'); +\Illuminate\Database\Eloquent\Factories\Factory::translations('en', 'english'); // output: ['en' => 'english'] ``` @@ -34,7 +34,7 @@ class UserFactory extends \Illuminate\Database\Eloquent\Factories\Factory { public function definition(): array { return [ - 'bio' => $this->translatable('en', 'english'), + 'bio' => $this->translations('en', 'english'), ]; } } diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index 73681e2..3da7bf7 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -19,7 +19,7 @@ public function packageRegistered(): void $this->app->singleton(Translatable::class, fn () => new Translatable()); $this->app->bind('translatable', Translatable::class); - Factory::macro('translatable', function (string|array $locales, mixed $value) { + Factory::macro('translations', function (string|array $locales, mixed $value) { return is_array($value) ? array_combine((array)$locales, $value) : array_fill_keys((array)$locales, $value); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index c2beb0c..a4b7129 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -762,8 +762,8 @@ public function setAttributesExternally(array $attributes) expect($model->name)->toBe(''); }); -it('translatable macro meets expectations', function (mixed $expected, string|array $locales, mixed $value) { - expect(Factory::translatable($locales, $value))->toEqual($expected); +it('translations macro meets expectations', function (mixed $expected, string|array $locales, mixed $value) { + expect(Factory::translations($locales, $value))->toEqual($expected); })->with([ [['en' => 'english'], 'en', 'english'], [['en' => 'english', 'nl' => 'english'], ['en', 'nl'], 'english'], From 2868a61855c22c0c2fda1b937357e48a498a79aa Mon Sep 17 00:00:00 2001 From: freekmurze Date: Thu, 20 Apr 2023 08:54:55 +0000 Subject: [PATCH 130/229] Update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d33725..ec3d59e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.5.0 - 2023-04-20 + +### What's Changed + +- update customize-the-toarray-method.md by @moham96 in https://github.com/spatie/laravel-translatable/pull/387 +- Add macro for `$this->translations()` in factories by @bram-pkg in https://github.com/spatie/laravel-translatable/pull/382 + +### New Contributors + +- @moham96 made their first contribution in https://github.com/spatie/laravel-translatable/pull/387 +- @bram-pkg made their first contribution in https://github.com/spatie/laravel-translatable/pull/382 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.4.0...6.5.0 + ## 6.4.0 - 2023-03-19 ### What's Changed From c64377bd5d0bd374811fa8e4039b85f0285431ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 03:02:32 +0000 Subject: [PATCH 131/229] Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.6 to 1.4.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.6...v1.4.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index f2e85e7..4c8e4c3 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.3.6 + uses: dependabot/fetch-metadata@v1.4.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From 10386f08b7ba3dd5acc44db6a313582d67476d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Fri, 5 May 2023 12:53:48 +0200 Subject: [PATCH 132/229] Add getFallbackLocale method --- src/HasTranslations.php | 6 +++- .../TestModelWithFallbackLocale.php | 30 +++++++++++++++++++ tests/TranslatableTest.php | 17 +++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/TestSupport/TestModelWithFallbackLocale.php diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 580d1ca..201ddee 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -241,9 +241,13 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } + if (method_exists($this, 'getFallbackLocale')) { + $fallbackLocale = $this->getFallbackLocale(); + } + $fallbackConfig = app(Translatable::class); - $fallbackLocale = $fallbackConfig->fallbackLocale ?? config('app.fallback_locale'); + $fallbackLocale ??= $fallbackConfig->fallbackLocale ?? config('app.fallback_locale'); if (! is_null($fallbackLocale) && in_array($fallbackLocale, $translatedLocales)) { return $fallbackLocale; diff --git a/tests/TestSupport/TestModelWithFallbackLocale.php b/tests/TestSupport/TestModelWithFallbackLocale.php new file mode 100644 index 0000000..08579d1 --- /dev/null +++ b/tests/TestSupport/TestModelWithFallbackLocale.php @@ -0,0 +1,30 @@ +attributes['field_with_mutator'] = $value; + } +} diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index a4b7129..50a5ee0 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -5,6 +5,7 @@ use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; use Spatie\Translatable\Facades\Translatable; use Spatie\Translatable\Test\TestSupport\TestModel; +use Spatie\Translatable\Test\TestSupport\TestModelWithFallbackLocale; use Spatie\Translatable\Test\TestSupport\TestModelWithoutFallback; beforeEach(function () { @@ -762,6 +763,22 @@ public function setAttributesExternally(array $attributes) expect($model->name)->toBe(''); }); +it('can set fallback locale on model', function () { + config()->set('app.fallback_locale', 'en'); + + $model = new TestModelWithFallbackLocale(); + + TestModelWithFallbackLocale::$fallbackLocale = 'fr'; + + $model->setTranslation('name', 'fr', 'testValue_fr'); + $model->setTranslation('name', 'en', 'testValue_en'); + $model->save(); + + $model->setLocale('nl'); + + expect($model->name)->toBe('testValue_fr'); +}); + it('translations macro meets expectations', function (mixed $expected, string|array $locales, mixed $value) { expect(Factory::translations($locales, $value))->toEqual($expected); })->with([ From 31b5534082eccdd36652a8a439a5c90130d1e56a Mon Sep 17 00:00:00 2001 From: gdebrauwer Date: Fri, 5 May 2023 10:54:13 +0000 Subject: [PATCH 133/229] Fix styling --- tests/TestSupport/TestModelWithFallbackLocale.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestSupport/TestModelWithFallbackLocale.php b/tests/TestSupport/TestModelWithFallbackLocale.php index 08579d1..9a05db7 100644 --- a/tests/TestSupport/TestModelWithFallbackLocale.php +++ b/tests/TestSupport/TestModelWithFallbackLocale.php @@ -18,7 +18,7 @@ class TestModelWithFallbackLocale extends Model public $translatable = ['name', 'other_field', 'field_with_mutator']; - public function getFallbackLocale() : string + public function getFallbackLocale(): string { return static::$fallbackLocale; } From b8f102492f816608d832cfe9e420da6a856312cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Fri, 5 May 2023 14:18:21 +0200 Subject: [PATCH 134/229] Add documentation --- .../handling-missing-translations.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/basic-usage/handling-missing-translations.md b/docs/basic-usage/handling-missing-translations.md index 05986b7..127512a 100644 --- a/docs/basic-usage/handling-missing-translations.md +++ b/docs/basic-usage/handling-missing-translations.md @@ -33,6 +33,29 @@ as `$fallbackLocale` parameter: ); ``` +### Fallback locale per model + +If the fallback locale differs between models, you can define a `getFallbackLocale()` method on your model. + +```php +use Illuminate\Database\Eloquent\Model; +use Spatie\Translatable\HasTranslations; + +class NewsItem extends Model +{ + use HasTranslations; + + public $fillable = ['name', 'fallback_locale']; + + public $translatable = ['name']; + + public function getFallbackLocale() : string + { + return $this->fallback_locale; + } +} +``` + ### Falling back to any locale Sometimes it is favored to return any translation if neither the translation for the preferred locale nor the fallback From 5753e45cfc96dee5004e5e6ea54de383034db141 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Sat, 6 May 2023 10:22:49 +0000 Subject: [PATCH 135/229] Update CHANGELOG --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec3d59e..8192647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.5.1 - 2023-05-06 + +### What's Changed + +- Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 by @dependabot in https://github.com/spatie/laravel-translatable/pull/389 +- Add getFallbackLocale method by @gdebrauwer in https://github.com/spatie/laravel-translatable/pull/391 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.5.0...6.5.1 + ## 6.5.0 - 2023-04-20 ### What's Changed From 424db8512f4f34672e4a628f9744e43636ce3f1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 03:00:28 +0000 Subject: [PATCH 136/229] Bump dependabot/fetch-metadata from 1.4.0 to 1.5.1 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.4.0 to 1.5.1. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.4.0...v1.5.1) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 4c8e4c3..3f60ce0 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.4.0 + uses: dependabot/fetch-metadata@v1.5.1 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From 2794a16b02d892da226427afd5968ee0b903d488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Tue, 20 Jun 2023 18:24:47 +0200 Subject: [PATCH 137/229] Convert static methods to scopes --- src/HasTranslations.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 201ddee..67f0dc6 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -328,14 +328,14 @@ public function locales(): array ); } - public static function whereLocale(string $column, string $locale): Builder + public function scopeWhereLocale(Builder $query, string $column, string $locale): void { - return static::query()->whereNotNull("{$column}->{$locale}"); + $query->whereNotNull("{$column}->{$locale}"); } - public static function whereLocales(string $column, array $locales): Builder + public function scopeWhereLocales(Builder $query, string $column, array $locales): void { - return static::query()->where(function (Builder $query) use ($column, $locales) { + $query->where(function (Builder $query) use ($column, $locales) { foreach ($locales as $locale) { $query->orWhereNotNull("{$column}->{$locale}"); } From 29d08d2088bda0d2b05452a348a7af2e81f9c668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Tue, 20 Jun 2023 19:09:54 +0200 Subject: [PATCH 138/229] re-add old static methods with @deprecation --- src/HasTranslations.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 67f0dc6..b257c94 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -341,4 +341,24 @@ public function scopeWhereLocales(Builder $query, string $column, array $locales } }); } + + /** + * @deprecated + */ + public static function whereLocale(string $column, string $locale): Builder + { + return static::query()->whereNotNull("{$column}->{$locale}"); + } + + /** + * @deprecated + */ + public static function whereLocales(string $column, array $locales): Builder + { + return static::query()->where(function (Builder $query) use ($column, $locales) { + foreach ($locales as $locale) { + $query->orWhereNotNull("{$column}->{$locale}"); + } + }); + } } From 5c78f26e1a6e34d7417eb8995a2a487b6e886dad Mon Sep 17 00:00:00 2001 From: freekmurze Date: Tue, 20 Jun 2023 18:10:03 +0000 Subject: [PATCH 139/229] Update CHANGELOG --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8192647..b53ec7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.5.2 - 2023-06-20 + +### What's Changed + +- Bump dependabot/fetch-metadata from 1.4.0 to 1.5.1 by @dependabot in https://github.com/spatie/laravel-translatable/pull/394 +- Convert static methods to scopes by @gdebrauwer in https://github.com/spatie/laravel-translatable/pull/396 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.5.1...6.5.2 + ## 6.5.1 - 2023-05-06 ### What's Changed From 04fa944d3b3507d5226a63c27f606d41122353c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jul 2023 02:58:20 +0000 Subject: [PATCH 140/229] Bump dependabot/fetch-metadata from 1.5.1 to 1.6.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.5.1 to 1.6.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.5.1...v1.6.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 3f60ce0..60183c5 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.5.1 + uses: dependabot/fetch-metadata@v1.6.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From f30693a49fb8f4ddb2338ad4b9b9b7dfcf1c1a0a Mon Sep 17 00:00:00 2001 From: Messi89 Date: Wed, 12 Jul 2023 23:27:44 +0100 Subject: [PATCH 141/229] handle new attribute mutator :boom: --- src/HasTranslations.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index b257c94..97fbf45 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -131,6 +131,11 @@ public function setTranslation(string $key, string $locale, $value): self $value = $this->attributes[$key]; } + elseif($this->hasAttributeSetMutator($key)) { // handle new attribute mutator + $this->setAttributeMarkedMutatedAttributeValue($key, $value); + + $value = $this->attributes[$key]; + } $translations[$locale] = $value; From a852479b80a5333005d3896019ac2e9ae63358d2 Mon Sep 17 00:00:00 2001 From: Messi89 Date: Wed, 12 Jul 2023 23:40:09 +0100 Subject: [PATCH 142/229] handle get attribute mutator :fire: --- src/HasTranslations.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 97fbf45..629b6a9 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -83,6 +83,9 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc if ($this->hasGetMutator($key)) { return $this->mutateAttribute($key, $translation); } + else if($this->hasAttributeMutator($key)){ + return $this->mutateAttributeMarkedAttribute($key, $translation); + } return $translation; } From 1906a3f1492c4b4b99d9f150b67cca4b697d85d7 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Mon, 17 Jul 2023 20:35:53 -0400 Subject: [PATCH 143/229] cs --- src/HasTranslations.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 629b6a9..7f66746 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -83,7 +83,8 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc if ($this->hasGetMutator($key)) { return $this->mutateAttribute($key, $translation); } - else if($this->hasAttributeMutator($key)){ + + if($this->hasAttributeMutator($key)){ return $this->mutateAttributeMarkedAttribute($key, $translation); } From bea169a9671233d00e1bf853127cb03704fbf411 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Wed, 19 Jul 2023 19:22:01 +0000 Subject: [PATCH 144/229] Fix styling --- src/HasTranslations.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 7f66746..01efb1a 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -84,7 +84,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc return $this->mutateAttribute($key, $translation); } - if($this->hasAttributeMutator($key)){ + if($this->hasAttributeMutator($key)) { return $this->mutateAttributeMarkedAttribute($key, $translation); } @@ -134,8 +134,7 @@ public function setTranslation(string $key, string $locale, $value): self $this->{$method}($value, $locale); $value = $this->attributes[$key]; - } - elseif($this->hasAttributeSetMutator($key)) { // handle new attribute mutator + } elseif($this->hasAttributeSetMutator($key)) { // handle new attribute mutator $this->setAttributeMarkedMutatedAttributeValue($key, $value); $value = $this->attributes[$key]; From 99ded209da7b1b7a3a285ec0ba506f0e01779069 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Wed, 19 Jul 2023 19:22:23 +0000 Subject: [PATCH 145/229] Update CHANGELOG --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b53ec7d..e75cb6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.5.3 - 2023-07-19 + +### What's Changed + +- Bump dependabot/fetch-metadata from 1.5.1 to 1.6.0 by @dependabot in https://github.com/spatie/laravel-translatable/pull/398 +- handle new attribute mutator :boom: by @messi89 in https://github.com/spatie/laravel-translatable/pull/402 + +### New Contributors + +- @messi89 made their first contribution in https://github.com/spatie/laravel-translatable/pull/402 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.5.2...6.5.3 + ## 6.5.2 - 2023-06-20 ### What's Changed From 82a1b0aaa400b89b121131653d2d5a55dffed9dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 02:52:28 +0000 Subject: [PATCH 146/229] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- .github/workflows/run-tests.yml | 2 +- .github/workflows/update-changelog.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 937731b..f0beab3 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -8,7 +8,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f98dac1..1fe4ab9 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index b20f3b6..94df2c3 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main From abecffc20733168d2357c65d9b533575b1b99aee Mon Sep 17 00:00:00 2001 From: Samuel De Backer Date: Thu, 30 Nov 2023 11:03:01 +0100 Subject: [PATCH 147/229] Keep null value --- src/HasTranslations.php | 26 ++++++++++++++------------ tests/TranslatableTest.php | 27 ++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 01efb1a..15cc08a 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -65,7 +65,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc $translations = $this->getTranslations($key); - $translation = $translations[$normalizedLocale] ?? ''; + $translation = $translations[$normalizedLocale] ?? null; $translatableConfig = app(Translatable::class); @@ -101,20 +101,20 @@ public function getTranslationWithoutFallback(string $key, string $locale): mixe return $this->getTranslation($key, $locale, false); } - public function getTranslations(string $key = null, array $allowedLocales = null): array + public function getTranslations(string $key = null, array $allowedLocales = null, bool $keepNullValues = true): array { if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); return array_filter( json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], - fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales), + fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales, $keepNullValues), ARRAY_FILTER_USE_BOTH, ); } - return array_reduce($this->getTranslatableAttributes(), function ($result, $item) use ($allowedLocales) { - $result[$item] = $this->getTranslations($item, $allowedLocales); + return array_reduce($this->getTranslatableAttributes(), function ($result, $item) use ($allowedLocales, $keepNullValues) { + $result[$item] = $this->getTranslations($item, $allowedLocales, $keepNullValues); return $result; }); @@ -204,7 +204,7 @@ public function forgetAllTranslations(string $locale): self public function getTranslatedLocales(string $key): array { - return array_keys($this->getTranslations($key)); + return array_keys($this->getTranslations($key, null, false)); } public function isTranslatableAttribute(string $key): bool @@ -268,14 +268,16 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function filterTranslations(mixed $value = null, string $locale = null, array $allowedLocales = null): bool + protected function filterTranslations(mixed $value = null, string $locale = null, array $allowedLocales = null, bool $keepNullValues = true): bool { - if ($value === null) { - return false; - } + if (! $keepNullValues) { + if ($value === null) { + return false; + } - if ($value === '') { - return false; + if ($value === '') { + return false; + } } if ($allowedLocales === null) { diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 50a5ee0..e59ff8e 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -39,7 +39,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - expect($this->testModel->getTranslation('name', 'fr', false))->toBe(''); + expect($this->testModel->getTranslation('name', 'fr', false))->toBe(null); }); it('will return fallback locale translation when getting an unknown locale and fallback is true', function () { @@ -126,7 +126,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - expect($this->testModel->getTranslationWithoutFallback('name', 'fr'))->toBe(''); + expect($this->testModel->getTranslationWithoutFallback('name', 'fr'))->toBe(null); }); it('will return an empty string when getting an unknown locale and fallback is empty', function () { @@ -139,7 +139,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - expect($this->testModel->getTranslation('name', 'fr'))->toBe(''); + expect($this->testModel->getTranslation('name', 'fr'))->toBe(null); }); it('can save a translated attribute', function () { @@ -149,6 +149,13 @@ expect($this->testModel->name)->toBe('testValue_en'); }); +it('can save null value in a translated attribute', function () { + $this->testModel->setTranslation('name', 'en', null); + $this->testModel->save(); + + expect($this->testModel->name)->toBe(null); +}); + it('can set translated values when creating a model', function () { $model = TestModel::create([ 'name' => ['en' => 'testValue_en'], @@ -448,6 +455,7 @@ public function setNameAttribute($value) it('can check if an attribute has translation', function () { $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->setTranslation('name', 'nl', null); + $this->testModel->setTranslation('name', 'de', null); $this->testModel->save(); expect($this->testModel->hasTranslation('name', 'en'))->toBeTrue(); @@ -455,6 +463,15 @@ public function setNameAttribute($value) expect($this->testModel->hasTranslation('name', 'pt'))->toBeFalse(); }); +it('will return the same number of translations with the same values as saved', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'nl', null); + $this->testModel->setTranslation('name', 'de', ''); + $this->testModel->save(); + + expect($this->testModel->getTranslations('name'))->toEqual(['en' => 'testValue_en', 'nl' => null, 'de' => '']); +}); + it('can correctly set a field when a mutator is defined', function () { $testModel = (new class () extends TestModel { public function setNameAttribute($value) @@ -699,7 +716,7 @@ public function setAttributesExternally(array $attributes) $this->testModel->save(); $this->testModel->setLocale('it'); - expect($this->testModel->getTranslation('name', 'it', false))->toBe(''); + expect($this->testModel->getTranslation('name', 'it', false))->toBe(null); }); it('will return default fallback locale translation when getting an unknown locale with fallback any', function () { @@ -760,7 +777,7 @@ public function setAttributesExternally(array $attributes) $model->setLocale('fr'); - expect($model->name)->toBe(''); + expect($model->name)->toBe(null); }); it('can set fallback locale on model', function () { From 18e0b072d18f8357d8eae2b53e4ea10f554f58a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 02:33:20 +0000 Subject: [PATCH 148/229] Bump stefanzweifel/git-auto-commit-action from 4 to 5 Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 4 to 5. - [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases) - [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v4...v5) --- updated-dependencies: - dependency-name: stefanzweifel/git-auto-commit-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- .github/workflows/update-changelog.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index f0beab3..5b87253 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -18,6 +18,6 @@ jobs: args: --config=.php_cs.dist.php --allow-risky=yes - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Fix styling diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 94df2c3..0cdea23 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -21,7 +21,7 @@ jobs: release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: branch: main commit_message: Update CHANGELOG From 867223c1028a928d75f52e9ddca25378724fdec0 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Fri, 1 Dec 2023 10:26:58 +0000 Subject: [PATCH 149/229] Update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e75cb6b..d2a548d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.5.4 - 2023-12-01 + +### What's Changed + +* Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/spatie/laravel-translatable/pull/413 +* Keep the number of translations even with null values by @sdebacker in https://github.com/spatie/laravel-translatable/pull/427 +* Bump stefanzweifel/git-auto-commit-action from 4 to 5 by @dependabot in https://github.com/spatie/laravel-translatable/pull/418 + +### New Contributors + +* @sdebacker made their first contribution in https://github.com/spatie/laravel-translatable/pull/427 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.5.3...6.5.4 + ## 6.5.3 - 2023-07-19 ### What's Changed From d6dc7c9fe3c678ce50b2d6a4a7434fcbcfc3df4c Mon Sep 17 00:00:00 2001 From: Muhammed Sari Date: Wed, 6 Dec 2023 10:40:57 +0100 Subject: [PATCH 150/229] Revert "Keep null value" This reverts commit abecffc20733168d2357c65d9b533575b1b99aee. --- src/HasTranslations.php | 26 ++++++++++++-------------- tests/TranslatableTest.php | 27 +++++---------------------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 15cc08a..01efb1a 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -65,7 +65,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc $translations = $this->getTranslations($key); - $translation = $translations[$normalizedLocale] ?? null; + $translation = $translations[$normalizedLocale] ?? ''; $translatableConfig = app(Translatable::class); @@ -101,20 +101,20 @@ public function getTranslationWithoutFallback(string $key, string $locale): mixe return $this->getTranslation($key, $locale, false); } - public function getTranslations(string $key = null, array $allowedLocales = null, bool $keepNullValues = true): array + public function getTranslations(string $key = null, array $allowedLocales = null): array { if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); return array_filter( json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], - fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales, $keepNullValues), + fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales), ARRAY_FILTER_USE_BOTH, ); } - return array_reduce($this->getTranslatableAttributes(), function ($result, $item) use ($allowedLocales, $keepNullValues) { - $result[$item] = $this->getTranslations($item, $allowedLocales, $keepNullValues); + return array_reduce($this->getTranslatableAttributes(), function ($result, $item) use ($allowedLocales) { + $result[$item] = $this->getTranslations($item, $allowedLocales); return $result; }); @@ -204,7 +204,7 @@ public function forgetAllTranslations(string $locale): self public function getTranslatedLocales(string $key): array { - return array_keys($this->getTranslations($key, null, false)); + return array_keys($this->getTranslations($key)); } public function isTranslatableAttribute(string $key): bool @@ -268,16 +268,14 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function filterTranslations(mixed $value = null, string $locale = null, array $allowedLocales = null, bool $keepNullValues = true): bool + protected function filterTranslations(mixed $value = null, string $locale = null, array $allowedLocales = null): bool { - if (! $keepNullValues) { - if ($value === null) { - return false; - } + if ($value === null) { + return false; + } - if ($value === '') { - return false; - } + if ($value === '') { + return false; } if ($allowedLocales === null) { diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index e59ff8e..50a5ee0 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -39,7 +39,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - expect($this->testModel->getTranslation('name', 'fr', false))->toBe(null); + expect($this->testModel->getTranslation('name', 'fr', false))->toBe(''); }); it('will return fallback locale translation when getting an unknown locale and fallback is true', function () { @@ -126,7 +126,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - expect($this->testModel->getTranslationWithoutFallback('name', 'fr'))->toBe(null); + expect($this->testModel->getTranslationWithoutFallback('name', 'fr'))->toBe(''); }); it('will return an empty string when getting an unknown locale and fallback is empty', function () { @@ -139,7 +139,7 @@ $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->save(); - expect($this->testModel->getTranslation('name', 'fr'))->toBe(null); + expect($this->testModel->getTranslation('name', 'fr'))->toBe(''); }); it('can save a translated attribute', function () { @@ -149,13 +149,6 @@ expect($this->testModel->name)->toBe('testValue_en'); }); -it('can save null value in a translated attribute', function () { - $this->testModel->setTranslation('name', 'en', null); - $this->testModel->save(); - - expect($this->testModel->name)->toBe(null); -}); - it('can set translated values when creating a model', function () { $model = TestModel::create([ 'name' => ['en' => 'testValue_en'], @@ -455,7 +448,6 @@ public function setNameAttribute($value) it('can check if an attribute has translation', function () { $this->testModel->setTranslation('name', 'en', 'testValue_en'); $this->testModel->setTranslation('name', 'nl', null); - $this->testModel->setTranslation('name', 'de', null); $this->testModel->save(); expect($this->testModel->hasTranslation('name', 'en'))->toBeTrue(); @@ -463,15 +455,6 @@ public function setNameAttribute($value) expect($this->testModel->hasTranslation('name', 'pt'))->toBeFalse(); }); -it('will return the same number of translations with the same values as saved', function () { - $this->testModel->setTranslation('name', 'en', 'testValue_en'); - $this->testModel->setTranslation('name', 'nl', null); - $this->testModel->setTranslation('name', 'de', ''); - $this->testModel->save(); - - expect($this->testModel->getTranslations('name'))->toEqual(['en' => 'testValue_en', 'nl' => null, 'de' => '']); -}); - it('can correctly set a field when a mutator is defined', function () { $testModel = (new class () extends TestModel { public function setNameAttribute($value) @@ -716,7 +699,7 @@ public function setAttributesExternally(array $attributes) $this->testModel->save(); $this->testModel->setLocale('it'); - expect($this->testModel->getTranslation('name', 'it', false))->toBe(null); + expect($this->testModel->getTranslation('name', 'it', false))->toBe(''); }); it('will return default fallback locale translation when getting an unknown locale with fallback any', function () { @@ -777,7 +760,7 @@ public function setAttributesExternally(array $attributes) $model->setLocale('fr'); - expect($model->name)->toBe(null); + expect($model->name)->toBe(''); }); it('can set fallback locale on model', function () { From ff9a94d74fdd5257502b7822a45819f5292df473 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Wed, 6 Dec 2023 10:57:10 +0000 Subject: [PATCH 151/229] Update CHANGELOG --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2a548d..0fedd8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.5.5 - 2023-12-06 + +### What's Changed + +* Revert "Keep null value" by @mabdullahsari in https://github.com/spatie/laravel-translatable/pull/428 + +### New Contributors + +* @mabdullahsari made their first contribution in https://github.com/spatie/laravel-translatable/pull/428 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.5.4...6.5.5 + ## 6.5.4 - 2023-12-01 ### What's Changed From dd5b71966a960840b76cdc4eda7e0508943e525d Mon Sep 17 00:00:00 2001 From: Mo Khosh Date: Fri, 23 Feb 2024 16:02:17 +0330 Subject: [PATCH 152/229] add laravel 11 support --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index da9d715..a56acb8 100644 --- a/composer.json +++ b/composer.json @@ -28,14 +28,14 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^9.0|^10.0", - "illuminate/support": "^9.0|^10.0", + "illuminate/database": "^9.0|^10.0|^11.0", + "illuminate/support": "^9.0|^10.0|^11.0", "spatie/laravel-package-tools": "^1.11" }, "require-dev": { "mockery/mockery": "^1.4", - "orchestra/testbench": "^7.0|^8.0", - "pestphp/pest": "^1.20" + "orchestra/testbench": "^7.0|^8.0|^9.0", + "pestphp/pest": "^1.20|^2.0" }, "autoload": { "psr-4": { From 46ca7887fe05cc4bfcd6ee739d9dfaa4af64b1b4 Mon Sep 17 00:00:00 2001 From: Mo Khosh Date: Fri, 23 Feb 2024 16:03:56 +0330 Subject: [PATCH 153/229] update ci for laravel 11 --- .github/workflows/run-tests.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 1fe4ab9..d757fa9 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,10 +9,13 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.2, 8.1, 8.0] - laravel: [10.*, 9.*] + php: [8.3, 8.2, 8.1, 8.0] + laravel: [11.*, 10.*, 9.*] stability: [prefer-lowest, prefer-stable] include: + - laravel: 11.* + testbench: 9.* + carbon: ^3.0 - laravel: 10.* testbench: 8.* carbon: ^2.63 @@ -20,6 +23,8 @@ jobs: testbench: 7.* carbon: ^2.63 exclude: + - laravel: 11.* + php: [8.1, 8.0] - laravel: 10.* php: 8.0 From 11f0b548dd43b846a5bdca1431de173ac77ed349 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Fri, 23 Feb 2024 14:51:32 +0100 Subject: [PATCH 154/229] Update run-tests.yml --- .github/workflows/run-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d757fa9..6b98667 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -24,7 +24,9 @@ jobs: carbon: ^2.63 exclude: - laravel: 11.* - php: [8.1, 8.0] + php: 8.1 + - laravel: 11.* + php: 8.0 - laravel: 10.* php: 8.0 From db3281f15310e20c7a289d50af26bde9cbbb3a4e Mon Sep 17 00:00:00 2001 From: freekmurze Date: Fri, 23 Feb 2024 13:53:17 +0000 Subject: [PATCH 155/229] Update CHANGELOG --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fedd8a..563819f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.6.0 - 2024-02-23 + +### What's Changed + +* Add laravel 11 support by @mokhosh in https://github.com/spatie/laravel-translatable/pull/434 + +### New Contributors + +* @mokhosh made their first contribution in https://github.com/spatie/laravel-translatable/pull/434 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.5.5...6.6.0 + ## 6.5.5 - 2023-12-06 ### What's Changed From 1437edfc264788ba20138f865ffd6e76dc3d0672 Mon Sep 17 00:00:00 2001 From: Norman Huth Date: Sun, 25 Feb 2024 13:42:38 +0100 Subject: [PATCH 156/229] fix: allow raw searchable umlauts --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 01efb1a..124ef1d 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -142,7 +142,7 @@ public function setTranslation(string $key, string $locale, $value): self $translations[$locale] = $value; - $this->attributes[$key] = $this->asJson($translations); + $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); event(new TranslationHasBeenSetEvent($this, $key, $locale, $oldValue, $value)); From 71f9f367f495c291256b28f5bdc71d1165b7cd4e Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 26 Feb 2024 08:38:11 +0000 Subject: [PATCH 157/229] Update CHANGELOG --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 563819f..0dc0420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.6.1 - 2024-02-26 + +### What's Changed + +* fix: allow raw searchable umlauts by @Muetze42 in https://github.com/spatie/laravel-translatable/pull/436 + +### New Contributors + +* @Muetze42 made their first contribution in https://github.com/spatie/laravel-translatable/pull/436 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.6.0...6.6.1 + ## 6.6.0 - 2024-02-23 ### What's Changed From 529b4e89ad0b0982d9c635696260661d1cf2612c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vencel=20K=C3=A1tai?= Date: Thu, 29 Feb 2024 02:47:21 +0100 Subject: [PATCH 158/229] Fix toArray when using accessors on translatable attributes --- src/HasTranslations.php | 11 +++++++++++ tests/TranslatableTest.php | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 124ef1d..44b1d94 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -36,6 +36,17 @@ public function getAttributeValue($key): mixed return $this->getTranslation($key, $this->getLocale(), $this->useFallbackLocale()); } + protected function mutateAttributeForArray($key, $value): mixed + { + if (! $this->isTranslatableAttribute($key)) { + return parent::mutateAttributeForArray($key, $value); + } + + $translations = $this->getTranslations($key); + + return array_map(fn ($value) => parent::mutateAttributeForArray($key, $value), $translations); + } + public function setAttribute($key, $value) { if ($this->isTranslatableAttribute($key) && is_array($value)) { diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 50a5ee0..e2da13b 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -397,6 +397,25 @@ public function getNameAttribute($value): string expect('I just accessed testValue_en')->toEqual($testModel->name); }); +it('can be converted to array when using accessors on translated attributes', function () { + $testModel = new class () extends TestModel { + public function getNameAttribute($value) + { + return "I just accessed {$value}"; + } + }; + + $testModel->setTranslation('name', 'en', 'testValue_en'); + $testModel->setTranslation('name', 'nl', 'testValue_nl'); + + expect($testModel->toArray()) + ->toHaveKey('name') + ->toContain([ + 'en' => 'I just accessed testValue_en', + 'nl' => 'I just accessed testValue_nl', + ]); +}); + it('can use mutators on translated attributes', function () { $testModel = new class () extends TestModel { public function setNameAttribute($value) From 3cc1d76b961c7edae456748eefc79d2387d6fb0e Mon Sep 17 00:00:00 2001 From: freekmurze Date: Fri, 1 Mar 2024 10:25:28 +0000 Subject: [PATCH 159/229] Update CHANGELOG --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dc0420..5436b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.6.2 - 2024-03-01 + +### What's Changed + +* Fix toArray when using accessors on translatable attributes by @vencelkatai in https://github.com/spatie/laravel-translatable/pull/437 + +### New Contributors + +* @vencelkatai made their first contribution in https://github.com/spatie/laravel-translatable/pull/437 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.6.1...6.6.2 + ## 6.6.1 - 2024-02-26 ### What's Changed From a98fead02f01a71057781f1b5da876aed42b59e0 Mon Sep 17 00:00:00 2001 From: Norman Huth Date: Sun, 24 Mar 2024 20:06:04 +0100 Subject: [PATCH 160/229] Add method comment to Facade for IDE autocompletion --- src/Facades/Translatable.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Facades/Translatable.php b/src/Facades/Translatable.php index 992c3bf..0fd70a2 100644 --- a/src/Facades/Translatable.php +++ b/src/Facades/Translatable.php @@ -6,6 +6,8 @@ /** * @see \Spatie\Translatable\Translatable + * + * @method static fallback(?string $fallbackLocale = null, ?bool $fallbackAny = false, $missingKeyCallback = null) */ class Translatable extends Facade { From 4d409b61207aeec518cf5c01b4fb9774da650f21 Mon Sep 17 00:00:00 2001 From: Fahri Meral Date: Thu, 28 Mar 2024 23:51:40 +0300 Subject: [PATCH 161/229] Docs: add type declarations `array $translatable` --- docs/installation-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation-setup.md b/docs/installation-setup.md index 0434a55..92f1b4d 100644 --- a/docs/installation-setup.md +++ b/docs/installation-setup.md @@ -27,5 +27,5 @@ class NewsItem extends Model { use HasTranslations; - public $translatable = ['name']; + public array $translatable = ['name']; } From e7e223caf01fc6b72dacea3106df31e19fa059d5 Mon Sep 17 00:00:00 2001 From: AbdelrahmanBl Date: Sun, 12 May 2024 17:38:23 +0300 Subject: [PATCH 162/229] [FEAT] add ability for filtering a column's locale or multiple locales with a specific value --- README.md | 8 ++++++++ docs/basic-usage/querying-translations.md | 10 ++++++++++ src/HasTranslations.php | 14 ++++++++++++++ tests/TranslatableTest.php | 22 ++++++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/README.md b/README.md index 5ea2cbd..3e1e750 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,14 @@ $newsItem->name; // Returns 'Naam in het Nederlands' NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a name in English NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch + +// Returns all news items that has name in English with value `Name in English` +NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); + +// Returns all news items that has name in English or Dutch with value `Name in English` +NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in English')->get(); + + ``` ## Support us diff --git a/docs/basic-usage/querying-translations.md b/docs/basic-usage/querying-translations.md index 210c505..506d7bf 100644 --- a/docs/basic-usage/querying-translations.md +++ b/docs/basic-usage/querying-translations.md @@ -22,3 +22,13 @@ NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a nam NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch ``` + +If you want to query records based on locale's value, you can use the `whereJsonContainsLocale` and `whereJsonContainsLocales` methods. + +```php +// Returns all news items that has name in English with value `Name in English` +NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); + +// Returns all news items that has name in English or Dutch with value `Name in English` +NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in English')->get(); +``` diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 44b1d94..769a500 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -361,6 +361,20 @@ public function scopeWhereLocales(Builder $query, string $column, array $locales }); } + public function scopeWhereJsonContainsLocale(Builder $query, string $column, string $locale, mixed $value): void + { + $query->whereJsonContains("{$column}->{$locale}", $value); + } + + public function scopeWhereJsonContainsLocales(Builder $query, string $column, array $locales, mixed $value): void + { + $query->where(function (Builder $query) use ($column, $locales, $value) { + foreach($locales as $locale) { + $query->orWhereJsonContains("{$column}->{$locale}", $value); + } + }); + } + /** * @deprecated */ diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index e2da13b..a8df6ac 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -769,6 +769,28 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->whereLocales('name', ['de', 'be'])->get())->toHaveCount(0); }); +it('queries the database whether a value exists in a locale', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'tr', 'testValue_tr'); + $this->testModel->save(); + + expect($this->testModel->whereJsonContainsLocale('name', 'en', 'testValue_en')->get())->toHaveCount(1); + + expect($this->testModel->whereJsonContainsLocale('name', 'en', 'testValue_fr')->get())->toHaveCount(0); +}); + +it('queries the database whether a value exists in a multiple locales', function () { + $this->testModel->setTranslation('name', 'en', 'testValue_en'); + $this->testModel->setTranslation('name', 'fr', 'testValue_fr'); + $this->testModel->setTranslation('name', 'tr', 'testValue_tr'); + $this->testModel->save(); + + expect($this->testModel->whereJsonContainsLocales('name', ['en', 'fr'], 'testValue_en')->get())->toHaveCount(1); + + expect($this->testModel->whereJsonContainsLocales('name', ['en', 'fr'], 'testValue_tr')->get())->toHaveCount(0); +}); + it('can disable attribute locale fallback on a per model basis', function () { config()->set('app.fallback_locale', 'en'); From b75b3300949cdc6ce191f9a4b70addbce5d54ff5 Mon Sep 17 00:00:00 2001 From: AbdelrahmanBl Date: Mon, 13 May 2024 15:06:35 +0300 Subject: [PATCH 163/229] [FIX] replace whereJsonContains with where for more database's driver compatibility --- src/HasTranslations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 769a500..9057a9a 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -363,14 +363,14 @@ public function scopeWhereLocales(Builder $query, string $column, array $locales public function scopeWhereJsonContainsLocale(Builder $query, string $column, string $locale, mixed $value): void { - $query->whereJsonContains("{$column}->{$locale}", $value); + $query->where("{$column}->{$locale}", $value); } public function scopeWhereJsonContainsLocales(Builder $query, string $column, array $locales, mixed $value): void { $query->where(function (Builder $query) use ($column, $locales, $value) { foreach($locales as $locale) { - $query->orWhereJsonContains("{$column}->{$locale}", $value); + $query->orWhere("{$column}->{$locale}", $value); } }); } From f07f7993f334daf901cb849aa2a56996e4ff4cd2 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 13 May 2024 12:35:02 +0000 Subject: [PATCH 164/229] Update CHANGELOG --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5436b77..b38158c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.7.0 - 2024-05-13 + +### What's Changed + +* Add method comment to Facade for IDE autocompletion by @Muetze42 in https://github.com/spatie/laravel-translatable/pull/438 +* Docs: add type declarations `array $translatable` by @fahrim in https://github.com/spatie/laravel-translatable/pull/441 +* [FEAT] add ability for filtering a column's locale or multiple locale… by @AbdelrahmanBl in https://github.com/spatie/laravel-translatable/pull/447 + +### New Contributors + +* @fahrim made their first contribution in https://github.com/spatie/laravel-translatable/pull/441 +* @AbdelrahmanBl made their first contribution in https://github.com/spatie/laravel-translatable/pull/447 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.6.2...6.7.0 + ## 6.6.2 - 2024-03-01 ### What's Changed From 8c6c35360ddfdaa19ca9ed43da44839a587f775e Mon Sep 17 00:00:00 2001 From: Kyryl Bogach Date: Tue, 14 May 2024 11:46:58 +0200 Subject: [PATCH 165/229] fix: PHPDoc block in Translatable facade Fix fallback method definition that is lacking "void", occasioning code analyzers like PHPStan to fail. --- src/Facades/Translatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Facades/Translatable.php b/src/Facades/Translatable.php index 0fd70a2..6e50fc4 100644 --- a/src/Facades/Translatable.php +++ b/src/Facades/Translatable.php @@ -7,7 +7,7 @@ /** * @see \Spatie\Translatable\Translatable * - * @method static fallback(?string $fallbackLocale = null, ?bool $fallbackAny = false, $missingKeyCallback = null) + * @method static void fallback(?string $fallbackLocale = null, ?bool $fallbackAny = false, $missingKeyCallback = null) */ class Translatable extends Facade { From d55384cbcf867b3cf21ff4d062403596d94acf81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 02:19:50 +0000 Subject: [PATCH 166/229] Bump dependabot/fetch-metadata from 1.6.0 to 2.1.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.6.0 to 2.1.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.6.0...v2.1.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 60183c5..c09678f 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.6.0 + uses: dependabot/fetch-metadata@v2.1.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From 2b81c88beb7ca6616808d9a1cc98a0b3d0377e1a Mon Sep 17 00:00:00 2001 From: freekmurze Date: Tue, 14 May 2024 11:36:28 +0000 Subject: [PATCH 167/229] Update CHANGELOG --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b38158c..823bf5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.7.1 - 2024-05-14 + +### What's Changed + +* fix: PHPDoc block in Translatable facade by @kyryl-bogach in https://github.com/spatie/laravel-translatable/pull/448 +* Bump dependabot/fetch-metadata from 1.6.0 to 2.1.0 by @dependabot in https://github.com/spatie/laravel-translatable/pull/446 + +### New Contributors + +* @kyryl-bogach made their first contribution in https://github.com/spatie/laravel-translatable/pull/448 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.7.0...6.7.1 + ## 6.7.0 - 2024-05-13 ### What's Changed From cf21f5101c4779acc3fb328923953f6de324addd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 02:27:44 +0000 Subject: [PATCH 168/229] Bump dependabot/fetch-metadata from 2.1.0 to 2.2.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2.1.0 to 2.2.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v2.1.0...v2.2.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index c09678f..9db8ce3 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.1.0 + uses: dependabot/fetch-metadata@v2.2.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From 5b78c35bc98dd790767e26ccadb9569ad5e935d5 Mon Sep 17 00:00:00 2001 From: Ricardo Cerljenko Date: Tue, 23 Jul 2024 14:49:26 +0200 Subject: [PATCH 169/229] added operand for json scopes --- src/HasTranslations.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 9057a9a..f61a328 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -361,16 +361,16 @@ public function scopeWhereLocales(Builder $query, string $column, array $locales }); } - public function scopeWhereJsonContainsLocale(Builder $query, string $column, string $locale, mixed $value): void + public function scopeWhereJsonContainsLocale(Builder $query, string $column, string $locale, mixed $value, string $operand = '='): void { - $query->where("{$column}->{$locale}", $value); + $query->where("{$column}->{$locale}", $operand, $value); } - public function scopeWhereJsonContainsLocales(Builder $query, string $column, array $locales, mixed $value): void + public function scopeWhereJsonContainsLocales(Builder $query, string $column, array $locales, mixed $value, string $operand = '='): void { - $query->where(function (Builder $query) use ($column, $locales, $value) { + $query->where(function (Builder $query) use ($column, $locales, $value, $operand) { foreach($locales as $locale) { - $query->orWhere("{$column}->{$locale}", $value); + $query->orWhere("{$column}->{$locale}", $operand, $value); } }); } From 1115e7a8ea8dbec70a1737ec03174e74ac4a87d6 Mon Sep 17 00:00:00 2001 From: Ricardo Cerljenko Date: Wed, 24 Jul 2024 09:27:20 +0200 Subject: [PATCH 170/229] added tests and readme explanation --- README.md | 10 ++++++++-- tests/TranslatableTest.php | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e1e750..4ba080a 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,16 @@ NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a nam NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch // Returns all news items that has name in English with value `Name in English` -NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); +NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); + +// Returns all news items that has name in English with value like `Name in...` +NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in%', 'like')->get(); // Returns all news items that has name in English or Dutch with value `Name in English` -NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in English')->get(); +NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in English')->get(); + +// Returns all news items that has name in English or Dutch with value like `Name in...` +NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in%', 'like')->get(); ``` diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index a8df6ac..3430e97 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -777,6 +777,8 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->whereJsonContainsLocale('name', 'en', 'testValue_en')->get())->toHaveCount(1); + expect($this->testModel->whereJsonContainsLocale('name', 'en', 'test%en', 'like')->get())->toHaveCount(1); + expect($this->testModel->whereJsonContainsLocale('name', 'en', 'testValue_fr')->get())->toHaveCount(0); }); @@ -788,6 +790,8 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->whereJsonContainsLocales('name', ['en', 'fr'], 'testValue_en')->get())->toHaveCount(1); + expect($this->testModel->whereJsonContainsLocales('name', ['en', 'fr'], 'test%en', 'like')->get())->toHaveCount(1); + expect($this->testModel->whereJsonContainsLocales('name', ['en', 'fr'], 'testValue_tr')->get())->toHaveCount(0); }); From 0ef7e8e9d65bb834b7c68f22ec362a6179f50381 Mon Sep 17 00:00:00 2001 From: Ricardo Cerljenko Date: Wed, 24 Jul 2024 09:28:48 +0200 Subject: [PATCH 171/229] added tests and readme explanation --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4ba080a..6d5871e 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,14 @@ NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items w // Returns all news items that has name in English with value `Name in English` NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); -// Returns all news items that has name in English with value like `Name in...` -NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in%', 'like')->get(); - // Returns all news items that has name in English or Dutch with value `Name in English` NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in English')->get(); +// The last argument is the "operand" which you can tweak to achieve something like this: + +// Returns all news items that has name in English with value like `Name in...` +NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in%', 'like')->get(); + // Returns all news items that has name in English or Dutch with value like `Name in...` NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in%', 'like')->get(); From 9990835e68c691f0ac4471106588aa760d431c29 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Wed, 24 Jul 2024 14:27:06 +0000 Subject: [PATCH 172/229] Update CHANGELOG --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 823bf5b..947a69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.8.0 - 2024-07-24 + +### What's Changed + +* Bump dependabot/fetch-metadata from 2.1.0 to 2.2.0 by @dependabot in https://github.com/spatie/laravel-translatable/pull/453 +* Added operand for json scopes by @rcerljenko in https://github.com/spatie/laravel-translatable/pull/454 + +### New Contributors + +* @rcerljenko made their first contribution in https://github.com/spatie/laravel-translatable/pull/454 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.7.1...6.8.0 + ## 6.7.1 - 2024-05-14 ### What's Changed From 62a5ffad5c48ca6e85f7b39102d6f0d3f2f7badf Mon Sep 17 00:00:00 2001 From: Colin Sheaff Date: Fri, 27 Sep 2024 17:00:24 -0500 Subject: [PATCH 173/229] PHP 8.4 deprecates implicitly nullable parameter types. This commit fixes the issue by adding nullable types to the method signatures. https://github.com/php/php-src/blob/php-8.4.0RC1/UPGRADING#L497 4. Deprecated Functionality - Core: . Implicitly nullable parameter types are now deprecated. RFC: https://wiki.php.net/rfc/deprecate-implicitly-nullable-types --- src/HasTranslations.php | 6 +++--- src/Translatable.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index f61a328..93e1396 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -112,7 +112,7 @@ public function getTranslationWithoutFallback(string $key, string $locale): mixe return $this->getTranslation($key, $locale, false); } - public function getTranslations(string $key = null, array $allowedLocales = null): array + public function getTranslations(?string $key = null, ?array $allowedLocales = null): array { if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); @@ -223,7 +223,7 @@ public function isTranslatableAttribute(string $key): bool return in_array($key, $this->getTranslatableAttributes()); } - public function hasTranslation(string $key, string $locale = null): bool + public function hasTranslation(string $key, ?string $locale = null): bool { $locale = $locale ?: $this->getLocale(); @@ -279,7 +279,7 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function filterTranslations(mixed $value = null, string $locale = null, array $allowedLocales = null): bool + protected function filterTranslations(mixed $value = null, ?string $locale = null, ?array $allowedLocales = null): bool { if ($value === null) { return false; diff --git a/src/Translatable.php b/src/Translatable.php index 18df5d8..797828d 100644 --- a/src/Translatable.php +++ b/src/Translatable.php @@ -22,7 +22,7 @@ class Translatable public function fallback( ?string $fallbackLocale = null, ?bool $fallbackAny = false, - $missingKeyCallback = null + ?Closure $missingKeyCallback = null ): self { $this->fallbackLocale = $fallbackLocale; $this->fallbackAny = $fallbackAny; From fa67e38dda1143e3ad4019de30cc19d5c299663f Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 10:40:18 -0400 Subject: [PATCH 174/229] Add .idea to .gitignore, PHP CS Fixer to dev dependencies, and rename PHP CS Fixer config --- .gitignore | 2 +- .php_cs.dist.php => .php-cs-fixer.dist.php | 0 composer.json | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) rename .php_cs.dist.php => .php-cs-fixer.dist.php (100%) diff --git a/.gitignore b/.gitignore index 93febc6..b06a48e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ composer.lock vendor .phpunit.result.cache .php-cs-fixer.cache - +.idea diff --git a/.php_cs.dist.php b/.php-cs-fixer.dist.php similarity index 100% rename from .php_cs.dist.php rename to .php-cs-fixer.dist.php diff --git a/composer.json b/composer.json index a56acb8..a909e2e 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "spatie/laravel-package-tools": "^1.11" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.64", "mockery/mockery": "^1.4", "orchestra/testbench": "^7.0|^8.0|^9.0", "pestphp/pest": "^1.20|^2.0" From 420713ebfb0c25595758f9200ead20b79529f7b9 Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 07:59:03 -0400 Subject: [PATCH 175/229] - Add `allowNullForTranslation` and `allowEmptyStringForTranslation` options to `Translatable`. - Update `HasTranslations->getTranslation` to handle null values - Modify `HasTranslations->filterTranslations` to allow null and empty strings based on configuration. --- src/HasTranslations.php | 14 ++++++++++---- src/Translatable.php | 4 ++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 93e1396..d717e20 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -70,6 +70,11 @@ public function translate(string $key, string $locale = '', bool $useFallbackLoc public function getTranslation(string $key, string $locale, bool $useFallbackLocale = true): mixed { + // if column value is `null` then we have nothing to do, return `null` + if (is_null(parent::getAttributeValue($key))) { + return null; + } + $normalizedLocale = $this->normalizeLocale($key, $locale, $useFallbackLocale); $isKeyMissingFromLocale = ($locale !== $normalizedLocale); @@ -116,10 +121,11 @@ public function getTranslations(?string $key = null, ?array $allowedLocales = nu { if ($key !== null) { $this->guardAgainstNonTranslatableAttribute($key); + $translatableConfig = app(Translatable::class); return array_filter( json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], - fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales), + fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales, $translatableConfig->allowNullForTranslation, $translatableConfig->allowEmptyStringForTranslation), ARRAY_FILTER_USE_BOTH, ); } @@ -279,13 +285,13 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac return $locale; } - protected function filterTranslations(mixed $value = null, ?string $locale = null, ?array $allowedLocales = null): bool + protected function filterTranslations(mixed $value = null, ?string $locale = null, ?array $allowedLocales = null, bool $allowNull = false, bool $allowEmptyString = false): bool { - if ($value === null) { + if ($value === null && !$allowNull) { return false; } - if ($value === '') { + if ($value === '' && !$allowEmptyString) { return false; } diff --git a/src/Translatable.php b/src/Translatable.php index 797828d..04fac7f 100644 --- a/src/Translatable.php +++ b/src/Translatable.php @@ -19,6 +19,10 @@ class Translatable public ?Closure $missingKeyCallback = null; + public bool $allowNullForTranslation = false; + + public bool $allowEmptyStringForTranslation = false; + public function fallback( ?string $fallbackLocale = null, ?bool $fallbackAny = false, From d0daeb320f1cb5c4e4a653987e6f520b2ee069b0 Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 08:54:57 -0400 Subject: [PATCH 176/229] composer format --- src/HasTranslations.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index d717e20..2eddb13 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -100,7 +100,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc return $this->mutateAttribute($key, $translation); } - if($this->hasAttributeMutator($key)) { + if ($this->hasAttributeMutator($key)) { return $this->mutateAttributeMarkedAttribute($key, $translation); } @@ -151,7 +151,7 @@ public function setTranslation(string $key, string $locale, $value): self $this->{$method}($value, $locale); $value = $this->attributes[$key]; - } elseif($this->hasAttributeSetMutator($key)) { // handle new attribute mutator + } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator $this->setAttributeMarkedMutatedAttributeValue($key, $value); $value = $this->attributes[$key]; @@ -287,11 +287,11 @@ protected function normalizeLocale(string $key, string $locale, bool $useFallbac protected function filterTranslations(mixed $value = null, ?string $locale = null, ?array $allowedLocales = null, bool $allowNull = false, bool $allowEmptyString = false): bool { - if ($value === null && !$allowNull) { + if ($value === null && ! $allowNull) { return false; } - if ($value === '' && !$allowEmptyString) { + if ($value === '' && ! $allowEmptyString) { return false; } @@ -375,7 +375,7 @@ public function scopeWhereJsonContainsLocale(Builder $query, string $column, str public function scopeWhereJsonContainsLocales(Builder $query, string $column, array $locales, mixed $value, string $operand = '='): void { $query->where(function (Builder $query) use ($column, $locales, $value, $operand) { - foreach($locales as $locale) { + foreach ($locales as $locale) { $query->orWhere("{$column}->{$locale}", $operand, $value); } }); From 52a7ccc6d55698b2edda37e8c03b3d381769b5db Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 10:04:55 -0400 Subject: [PATCH 177/229] - Add `allowNullForTranslation` and `allowEmptyStringForTranslation` fluent methods to Translatable - Introduce fluent methods to configure null and empty string translation behavior --- src/Translatable.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Translatable.php b/src/Translatable.php index 04fac7f..9f1a521 100644 --- a/src/Translatable.php +++ b/src/Translatable.php @@ -34,4 +34,18 @@ public function fallback( return $this; } + + public function allowNullForTranslation(bool $allowNullForTranslation = true): self + { + $this->allowNullForTranslation = $allowNullForTranslation; + + return $this; + } + + public function allowEmptyStringForTranslation(bool $allowEmptyStringForTranslation = true): self + { + $this->allowEmptyStringForTranslation = $allowEmptyStringForTranslation; + + return $this; + } } From 704c3d019892906bb64123a0bfeb3564742bc53e Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 10:06:13 -0400 Subject: [PATCH 178/229] - tests added --- tests/TranslatableTest.php | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 3430e97..9a74a32 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -831,3 +831,56 @@ public function setAttributesExternally(array $attributes) [['en' => 'english', 'nl' => 'english'], ['en', 'nl'], 'english'], [['en' => 'english', 'nl' => 'dutch'], ['en', 'nl'], ['english', 'dutch']], ]); + +it('should return null when the underlying attribute in database is null', function () { + // we need to remove the name attribute from the translatable array + // and add it back to make sure the name + // attribute is holding `null` raw value + $this->testModel->translatable = array_filter($this->testModel->translatable, fn($attribute) => $attribute !== 'name'); + $this->testModel->name = null; + $this->testModel->translatable = array_merge($this->testModel->translatable, ['name']); + + $translation = $this->testModel->getTranslation('name', 'en'); + + expect($translation)->toBeNull(); +}); + +it('should return locales with empty string translations when allowEmptyStringForTranslation is true', function () { + Translatable::allowEmptyStringForTranslation(); + + $this->testModel->setTranslation('name', 'en', ''); + + $translations = $this->testModel->getTranslations('name'); + + expect($translations)->toEqual(['en' => '']); +}); + +it('should not return locales with empty string translations when allowEmptyStringForTranslation is false', function () { + Translatable::allowEmptyStringForTranslation(false); + + $this->testModel->setTranslation('name', 'en', ''); + + $translations = $this->testModel->getTranslations('name'); + + expect($translations)->toEqual([]); +}); + +it('should return locales with null translations when allowNullForTranslation is true', function () { + Translatable::allowNullForTranslation(); + + $this->testModel->setTranslation('name', 'en', null); + + $translations = $this->testModel->getTranslations('name'); + + expect($translations)->toEqual(['en' => null]); +}); + +it('should not return locales with null translations when allowNullForTranslation is false', function () { + Translatable::allowNullForTranslation(false); + + $this->testModel->setTranslation('name', 'en', null); + + $translations = $this->testModel->getTranslations('name'); + + expect($translations)->toEqual([]); +}); From e9cd8ee246d52b778f0b74059fd1d88e7c1c9ca2 Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 10:08:01 -0400 Subject: [PATCH 179/229] composer format --- tests/TranslatableTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 9a74a32..3976048 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -836,7 +836,7 @@ public function setAttributesExternally(array $attributes) // we need to remove the name attribute from the translatable array // and add it back to make sure the name // attribute is holding `null` raw value - $this->testModel->translatable = array_filter($this->testModel->translatable, fn($attribute) => $attribute !== 'name'); + $this->testModel->translatable = array_filter($this->testModel->translatable, fn ($attribute) => $attribute !== 'name'); $this->testModel->name = null; $this->testModel->translatable = array_merge($this->testModel->translatable, ['name']); From 7d97397f15b11c0f358f767aaa166e6fbd3f9118 Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 9 Dec 2024 16:28:16 +0000 Subject: [PATCH 180/229] Update CHANGELOG --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 947a69f..1cce284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.9.0 - 2024-12-09 + +### What's Changed + +* PHP 8.4 deprecates implicitly nullable parameter types. by @selfsimilar in https://github.com/spatie/laravel-translatable/pull/458 +* Add .idea to .gitignore, PHP CS Fixer to dev dependencies, and rename PHP CS Fixer config by @alipadron in https://github.com/spatie/laravel-translatable/pull/466 +* Allow configuration for handling null and empty strings in translations (Fixes #456) by @alipadron in https://github.com/spatie/laravel-translatable/pull/465 + +### New Contributors + +* @selfsimilar made their first contribution in https://github.com/spatie/laravel-translatable/pull/458 +* @alipadron made their first contribution in https://github.com/spatie/laravel-translatable/pull/466 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.8.0...6.9.0 + ## 6.8.0 - 2024-07-24 ### What's Changed From fc3f318b83fb19d3dedabdfd0dbc0346df71d539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vencel=20K=C3=A1tai?= Date: Tue, 10 Dec 2024 20:42:42 +0100 Subject: [PATCH 181/229] Fix attribute mutators --- src/HasTranslations.php | 2 +- tests/TranslatableTest.php | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 2eddb13..b6ce506 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -71,7 +71,7 @@ public function translate(string $key, string $locale = '', bool $useFallbackLoc public function getTranslation(string $key, string $locale, bool $useFallbackLocale = true): mixed { // if column value is `null` then we have nothing to do, return `null` - if (is_null(parent::getAttributeValue($key))) { + if (is_null(parent::getAttributeFromArray($key))) { return null; } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 3976048..6196882 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1,5 +1,6 @@ getTranslations('field_with_mutator'))->toEqual($translations); }); +it('uses the attribute to mutate the translated value', function () { + $testModel = (new class () extends TestModel { + public $mutatedValues = []; + + protected function name(): Attribute + { + return Attribute::get(function ($value) { + $this->mutatedValues[] = $value; + + return 'mutated'; + }); + } + }); + + $testModel->name = 'hello'; + $testModel->save(); + + expect($testModel->name)->toEqual('mutated'); + expect($testModel->mutatedValues)->toBe(['hello']); +}); + it('can translate a field based on the translations of another one', function () { $testModel = (new class () extends TestModel { public function setOtherFieldAttribute($value, $locale = 'en') From c55ea3ce9c3d40b9dc927ed8050f07cc797193dd Mon Sep 17 00:00:00 2001 From: freekmurze Date: Wed, 11 Dec 2024 09:16:20 +0000 Subject: [PATCH 182/229] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cce284..4efd9f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.9.1 - 2024-12-11 + +### What's Changed + +* Fix attribute mutators by @vencelkatai in https://github.com/spatie/laravel-translatable/pull/470 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.9.0...6.9.1 + ## 6.9.0 - 2024-12-09 ### What's Changed From 859db4440077299f761811ea2079035001a5a7c3 Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Wed, 20 Nov 2024 15:15:30 -0400 Subject: [PATCH 183/229] Refactor `setAttribute` function in a simpler way, to allow to set an array list as value for translation --- src/HasTranslations.php | 16 ++++++---------- tests/TranslatableTest.php | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index b6ce506..3f0282e 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -49,18 +49,14 @@ protected function mutateAttributeForArray($key, $value): mixed public function setAttribute($key, $value) { - if ($this->isTranslatableAttribute($key) && is_array($value)) { - return $this->setTranslations($key, $value); - } - - // Pass arrays and untranslatable attributes to the parent method. - if (! $this->isTranslatableAttribute($key) || is_array($value)) { - return parent::setAttribute($key, $value); + if ($this->isTranslatableAttribute($key)) { + if (is_array($value) && ! array_is_list($value)) { + return $this->setTranslations($key, $value); + } + return $this->setTranslation($key, $this->getLocale(), $value); } - // If the attribute is translatable and not already translated, set a - // translation for the current app locale. - return $this->setTranslation($key, $this->getLocale(), $value); + return parent::setAttribute($key, $value); } public function translate(string $key, string $locale = '', bool $useFallbackLocale = true): mixed diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 6196882..7597115 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -906,3 +906,17 @@ public function setAttributesExternally(array $attributes) expect($translations)->toEqual([]); }); + +it('can set an array list as value for translation using `setTranslation`', function () { + $this->testModel->setTranslation('name', 'en', ['testValue_en']); + $this->testModel->save(); + + expect($this->testModel->getTranslation('name', 'en'))->toEqual(['testValue_en']); +}); + +it('can set an array list as value for translation using default local', function () { + $this->testModel->name = ['testValue_en']; + $this->testModel->save(); + + expect($this->testModel->getTranslation('name', 'en'))->toEqual(['testValue_en']); +}); From ffbf9fcf85df81a53c69365a3ff27ac921c147ae Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Mon, 9 Dec 2024 13:20:01 -0400 Subject: [PATCH 184/229] Apply early return to improve readability and prevent deep nesting --- src/HasTranslations.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 3f0282e..a5b8753 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -49,14 +49,15 @@ protected function mutateAttributeForArray($key, $value): mixed public function setAttribute($key, $value) { - if ($this->isTranslatableAttribute($key)) { - if (is_array($value) && ! array_is_list($value)) { - return $this->setTranslations($key, $value); - } - return $this->setTranslation($key, $this->getLocale(), $value); + if (!$this->isTranslatableAttribute($key)) { + return parent::setAttribute($key, $value); + } + + if (is_array($value) && ! array_is_list($value)) { + return $this->setTranslations($key, $value); } - return parent::setAttribute($key, $value); + return $this->setTranslation($key, $this->getLocale(), $value); } public function translate(string $key, string $locale = '', bool $useFallbackLocale = true): mixed From a7c6aa171bd252dfef7729788a050a7346f83a5e Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Mon, 9 Dec 2024 13:20:27 -0400 Subject: [PATCH 185/229] composer format --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index a5b8753..9645edc 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -49,7 +49,7 @@ protected function mutateAttributeForArray($key, $value): mixed public function setAttribute($key, $value) { - if (!$this->isTranslatableAttribute($key)) { + if (! $this->isTranslatableAttribute($key)) { return parent::setAttribute($key, $value); } From d679f8292daaae42b1643abca4da929065c4711b Mon Sep 17 00:00:00 2001 From: freekmurze Date: Wed, 11 Dec 2024 09:51:55 +0000 Subject: [PATCH 186/229] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4efd9f1..fa2ae9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.9.2 - 2024-12-11 + +### What's Changed + +* Improve `setAttribute` to handle array list as value for translation by @alipadron in https://github.com/spatie/laravel-translatable/pull/469 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.9.1...6.9.2 + ## 6.9.1 - 2024-12-11 ### What's Changed From 5f0712701a71054ba9bd6693808c4748f1f4ebda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vencel=20K=C3=A1tai?= Date: Fri, 13 Dec 2024 05:54:43 +0100 Subject: [PATCH 187/229] Revert return value change when column value is `null` --- src/HasTranslations.php | 5 ----- tests/TranslatableTest.php | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 9645edc..d54acbf 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -67,11 +67,6 @@ public function translate(string $key, string $locale = '', bool $useFallbackLoc public function getTranslation(string $key, string $locale, bool $useFallbackLocale = true): mixed { - // if column value is `null` then we have nothing to do, return `null` - if (is_null(parent::getAttributeFromArray($key))) { - return null; - } - $normalizedLocale = $this->normalizeLocale($key, $locale, $useFallbackLocale); $isKeyMissingFromLocale = ($locale !== $normalizedLocale); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 7597115..c068f75 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -854,7 +854,7 @@ public function setAttributesExternally(array $attributes) [['en' => 'english', 'nl' => 'dutch'], ['en', 'nl'], ['english', 'dutch']], ]); -it('should return null when the underlying attribute in database is null', function () { +it('should return empty string when the underlying attribute in database is null', function () { // we need to remove the name attribute from the translatable array // and add it back to make sure the name // attribute is holding `null` raw value @@ -864,7 +864,7 @@ public function setAttributesExternally(array $attributes) $translation = $this->testModel->getTranslation('name', 'en'); - expect($translation)->toBeNull(); + expect($translation)->toBe(''); }); it('should return locales with empty string translations when allowEmptyStringForTranslation is true', function () { From de819371e38d7c45bd969af9fa2658fd42bba24d Mon Sep 17 00:00:00 2001 From: freekmurze Date: Mon, 16 Dec 2024 12:58:49 +0000 Subject: [PATCH 188/229] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa2ae9c..7406fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.9.3 - 2024-12-16 + +### What's Changed + +* Revert return value change when column value is `null` by @vencelkatai in https://github.com/spatie/laravel-translatable/pull/474 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.9.2...6.9.3 + ## 6.9.2 - 2024-12-11 ### What's Changed From 2bf11d71bbb4f2261f9f025dee1ad5e3b48ec716 Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Fri, 3 Jan 2025 12:57:29 -0400 Subject: [PATCH 189/229] Add support for clearing translations with an empty array Update HasTranslations trait to handle empty arrays as valid input for clearing translations. Add a test to ensure empty arrays clear translations for the specified attribute. --- src/HasTranslations.php | 2 +- tests/TranslatableTest.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index d54acbf..26dfe5f 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -53,7 +53,7 @@ public function setAttribute($key, $value) return parent::setAttribute($key, $value); } - if (is_array($value) && ! array_is_list($value)) { + if (is_array($value) && (! array_is_list($value) || count($value) === 0)) { return $this->setTranslations($key, $value); } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index c068f75..d8ca301 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -920,3 +920,10 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->getTranslation('name', 'en'))->toEqual(['testValue_en']); }); + +it('can treat an empty array as value for clearing translations', function () { + $this->testModel->name = []; + $this->testModel->save(); + + expect($this->testModel->getTranslations('name'))->toEqual([]); +}); From a6e87292c17716ae2fcf7adabed48fdb89500f8e Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Sun, 26 Jan 2025 00:49:00 +0300 Subject: [PATCH 190/229] Add support for nested key translations --- src/HasTranslations.php | 62 ++++++++++++++++++++++++-------------- tests/TestCase.php | 1 + tests/TranslatableTest.php | 53 ++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 22 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 26dfe5f..bbf86f5 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Support\Arr; use Illuminate\Support\Str; use Spatie\Translatable\Events\TranslationHasBeenSetEvent; use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; @@ -13,6 +14,14 @@ trait HasTranslations { protected ?string $translationLocale = null; + public function initializeHasTranslations(): void + { + $this->mergeCasts(array_merge( + $this->getCasts(), + array_fill_keys($this->getTranslatableAttributes(), 'array'), + )); + } + public static function usingLocale(string $locale): self { return (new self())->setLocale($locale); @@ -88,12 +97,14 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc } } - if ($this->hasGetMutator($key)) { - return $this->mutateAttribute($key, $translation); - } + if (! $this->isNestedKey($key)) { + if ($this->hasGetMutator($key)) { + return $this->mutateAttribute($key, $translation); + } - if ($this->hasAttributeMutator($key)) { - return $this->mutateAttributeMarkedAttribute($key, $translation); + if ($this->hasAttributeMutator($key)) { + return $this->mutateAttributeMarkedAttribute($key, $translation); + } } return $translation; @@ -115,8 +126,12 @@ public function getTranslations(?string $key = null, ?array $allowedLocales = nu $this->guardAgainstNonTranslatableAttribute($key); $translatableConfig = app(Translatable::class); + if ($this->isNestedKey($key)) { + [$key, $nestedKey] = explode('.',str_replace('->', '.', $key), 2); + } + return array_filter( - json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], + Arr::get($this->fromJson($this->getAttributeFromArray($key)), $nestedKey ?? null, []), fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales, $translatableConfig->allowNullForTranslation, $translatableConfig->allowEmptyStringForTranslation), ARRAY_FILTER_USE_BOTH, ); @@ -137,21 +152,27 @@ public function setTranslation(string $key, string $locale, $value): self $oldValue = $translations[$locale] ?? ''; - if ($this->hasSetMutator($key)) { - $method = 'set'.Str::studly($key).'Attribute'; + if (! $this->isNestedKey($key)) { + if ($this->hasSetMutator($key)) { + $method = 'set'.Str::studly($key).'Attribute'; - $this->{$method}($value, $locale); + $this->{$method}($value, $locale); - $value = $this->attributes[$key]; - } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator - $this->setAttributeMarkedMutatedAttributeValue($key, $value); + $value = $this->attributes[$key]; + } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator + $this->setAttributeMarkedMutatedAttributeValue($key, $value); - $value = $this->attributes[$key]; + $value = $this->attributes[$key]; + } } $translations[$locale] = $value; - $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + if ($this->isNestedKey($key)) { + $this->fillJsonAttribute($key, $translations); + } else { + $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } event(new TranslationHasBeenSetEvent($this, $key, $locale, $oldValue, $value)); @@ -216,6 +237,11 @@ public function getTranslatedLocales(string $key): array return array_keys($this->getTranslations($key)); } + public function isNestedKey(string $key): bool + { + return str_contains($key, '->'); + } + public function isTranslatableAttribute(string $key): bool { return in_array($key, $this->getTranslatableAttributes()); @@ -328,14 +354,6 @@ public function translations(): Attribute }); } - public function getCasts(): array - { - return array_merge( - parent::getCasts(), - array_fill_keys($this->getTranslatableAttributes(), 'array'), - ); - } - public function locales(): array { return array_unique( diff --git a/tests/TestCase.php b/tests/TestCase.php index b7e24c4..a1296ba 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -28,6 +28,7 @@ protected function setUpDatabase() $table->text('name')->nullable(); $table->text('other_field')->nullable(); $table->text('field_with_mutator')->nullable(); + $table->json('nested')->nullable(); }); } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index d8ca301..32b683a 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -927,3 +927,56 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->getTranslations('name'))->toEqual([]); }); + +it('can set and retrieve translations for nested fields', function () { + $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->setTranslations($nestedDeepFieldKey, [ + 'ar'=> 'nestedDeepFieldKey_ar', + 'en'=> 'nestedDeepFieldKey_en', + ]); + + $testModel->save(); + + expect($testModel->getTranslations()) + ->toEqual([ + $nestedFieldKey => [ + 'ar' => 'nestedFieldKey_ar', + 'nl' => 'nestedFieldKey_nl', + 'en' => 'nestedFieldKey_en', + ], + $nestedDeepFieldKey => [ + 'ar'=> 'nestedDeepFieldKey_ar', + 'en'=> 'nestedDeepFieldKey_en', + ], + ]); + + + expect($testModel->getTranslations($nestedDeepFieldKey)) + ->toEqual([ + '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'); +}); From c0fc6dc4f663deb463cd4e9b680c1540e2ff446b Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Sun, 26 Jan 2025 15:34:00 +0300 Subject: [PATCH 191/229] Enable mutators for nested fields --- src/HasTranslations.php | 38 +++++++++++++++++++----------------- tests/TranslatableTest.php | 40 +++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index bbf86f5..662c8f9 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -97,14 +97,14 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc } } - if (! $this->isNestedKey($key)) { - if ($this->hasGetMutator($key)) { - return $this->mutateAttribute($key, $translation); - } + $key = str_replace('->', '-', $key); - if ($this->hasAttributeMutator($key)) { - return $this->mutateAttributeMarkedAttribute($key, $translation); - } + if ($this->hasGetMutator($key)) { + return $this->mutateAttribute($key, $translation); + } + + if ($this->hasAttributeMutator($key)) { + return $this->mutateAttributeMarkedAttribute($key, $translation); } return $translation; @@ -152,23 +152,25 @@ public function setTranslation(string $key, string $locale, $value): self $oldValue = $translations[$locale] ?? ''; - if (! $this->isNestedKey($key)) { - if ($this->hasSetMutator($key)) { - $method = 'set'.Str::studly($key).'Attribute'; + $mutatorKey = str_replace('->', '-', $key); - $this->{$method}($value, $locale); + if ($this->hasSetMutator($mutatorKey)) { + $method = 'set'.Str::studly($mutatorKey).'Attribute'; - $value = $this->attributes[$key]; - } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator - $this->setAttributeMarkedMutatedAttributeValue($key, $value); + $this->{$method}($value, $locale); - $value = $this->attributes[$key]; - } + $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]); + $this->fillJsonAttribute($key, $translations); } else { $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 32b683a..2735d1e 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1,6 +1,6 @@ $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 { + public $translatable = ['nested->field', 'nested->deep->field']; + + public function setNestedFieldAttribute($value) + { + $this->attributes['nested->field'] = strtolower($value); + } + + public function getNestedFieldAttribute($value) + { + return ucfirst($value); + } + + protected function nestedDeepField(): Attribute + { + return Attribute::make( + get: fn (string $value) => ucfirst($value), + set: fn (string $value) => strtolower($value), + ); + } + }; + + $nestedFieldKey = 'nested->field'; + $nestedDeepFieldKey = 'nested->deep->field'; + + app()->setLocale('ar'); + $testModel->$nestedFieldKey = 'NESTED FIELD AR'; + $testModel->$nestedDeepFieldKey = 'NESTED DEEP FIELD AR'; + $testModel->save(); + + expect($testModel->$nestedFieldKey) + ->toEqual('Nested field ar'); + + expect($testModel->$nestedDeepFieldKey) + ->toEqual('Nested deep field ar'); +}); From 151fa1c9f4bb699b185930ae2f8231010fd1c03d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 02:33:44 +0000 Subject: [PATCH 192/229] Bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 9db8ce3..e99b9aa 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.2.0 + uses: dependabot/fetch-metadata@v2.3.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From 6b471a71381956c3ee666dc73403214c216b190b Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Mon, 27 Jan 2025 18:55:49 +0300 Subject: [PATCH 193/229] Refactor test to use new Attribute() instead of Attribute::make() - Ensures compatibility with all Laravel 9.0 and 9.1 --- tests/TranslatableTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 2735d1e..6ed891e 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -997,7 +997,7 @@ public function getNestedFieldAttribute($value) protected function nestedDeepField(): Attribute { - return Attribute::make( + return new Attribute( get: fn (string $value) => ucfirst($value), set: fn (string $value) => strtolower($value), ); From 099a209387c4f4e036de0316f5c709413098554c Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Mon, 27 Jan 2025 20:38:11 +0300 Subject: [PATCH 194/229] Update README to include nested key translation support --- README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6d5871e..ab1d81a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ class NewsItem extends Model { use HasTranslations; + public $translatable = ['name']; // translatable attributes + // ... } ``` @@ -32,14 +34,30 @@ $newsItem->name; // Returns 'Name in English' given that the current app locale $newsItem->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands' app()->setLocale('nl'); - $newsItem->name; // Returns 'Naam in het Nederlands' -// If you want to query records based on locales, you can use the `whereLocale` and `whereLocales` methods. +$newsItem->getTranslations('name'); // returns an array of all name translations + +// You can translate nested keys of a JSON column using the -> notation +// First, add the path to the $translatable array, e.g., 'meta->description' +$newsItem + ->setTranslation('meta->description', 'en', 'Description in English') + ->setTranslation('meta->description', 'nl', 'Beschrijving in het Nederlands') + ->save(); -NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a name in English +$attributeKey = 'meta->description'; +$newsItem->$attributeKey; // Returns 'Description in English' +$newsItem->getTranslation('meta->description', 'nl'); // Returns 'Beschrijving in het Nederlands' +``` -NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch +Also providing scoped queries for retrieving records based on locales + +```php +// Returns all news items with a name in English +NewsItem::whereLocale('name', 'en')->get(); + +// Returns all news items with a name in English or Dutch +NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items that has name in English with value `Name in English` NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); @@ -54,8 +72,6 @@ NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in%', 'like')->ge // Returns all news items that has name in English or Dutch with value like `Name in...` NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in%', 'like')->get(); - - ``` ## Support us From c795d240f8cdcae0d7f446b8e1714548985a0d7e Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Sun, 26 Jan 2025 00:49:00 +0300 Subject: [PATCH 195/229] Add support for nested key translations --- src/HasTranslations.php | 62 ++++++++++++++++++++++++-------------- tests/TestCase.php | 1 + tests/TranslatableTest.php | 53 ++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 22 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 26dfe5f..bbf86f5 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Support\Arr; use Illuminate\Support\Str; use Spatie\Translatable\Events\TranslationHasBeenSetEvent; use Spatie\Translatable\Exceptions\AttributeIsNotTranslatable; @@ -13,6 +14,14 @@ trait HasTranslations { protected ?string $translationLocale = null; + public function initializeHasTranslations(): void + { + $this->mergeCasts(array_merge( + $this->getCasts(), + array_fill_keys($this->getTranslatableAttributes(), 'array'), + )); + } + public static function usingLocale(string $locale): self { return (new self())->setLocale($locale); @@ -88,12 +97,14 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc } } - if ($this->hasGetMutator($key)) { - return $this->mutateAttribute($key, $translation); - } + if (! $this->isNestedKey($key)) { + if ($this->hasGetMutator($key)) { + return $this->mutateAttribute($key, $translation); + } - if ($this->hasAttributeMutator($key)) { - return $this->mutateAttributeMarkedAttribute($key, $translation); + if ($this->hasAttributeMutator($key)) { + return $this->mutateAttributeMarkedAttribute($key, $translation); + } } return $translation; @@ -115,8 +126,12 @@ public function getTranslations(?string $key = null, ?array $allowedLocales = nu $this->guardAgainstNonTranslatableAttribute($key); $translatableConfig = app(Translatable::class); + if ($this->isNestedKey($key)) { + [$key, $nestedKey] = explode('.',str_replace('->', '.', $key), 2); + } + return array_filter( - json_decode($this->getAttributes()[$key] ?? '' ?: '{}', true) ?: [], + Arr::get($this->fromJson($this->getAttributeFromArray($key)), $nestedKey ?? null, []), fn ($value, $locale) => $this->filterTranslations($value, $locale, $allowedLocales, $translatableConfig->allowNullForTranslation, $translatableConfig->allowEmptyStringForTranslation), ARRAY_FILTER_USE_BOTH, ); @@ -137,21 +152,27 @@ public function setTranslation(string $key, string $locale, $value): self $oldValue = $translations[$locale] ?? ''; - if ($this->hasSetMutator($key)) { - $method = 'set'.Str::studly($key).'Attribute'; + if (! $this->isNestedKey($key)) { + if ($this->hasSetMutator($key)) { + $method = 'set'.Str::studly($key).'Attribute'; - $this->{$method}($value, $locale); + $this->{$method}($value, $locale); - $value = $this->attributes[$key]; - } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator - $this->setAttributeMarkedMutatedAttributeValue($key, $value); + $value = $this->attributes[$key]; + } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator + $this->setAttributeMarkedMutatedAttributeValue($key, $value); - $value = $this->attributes[$key]; + $value = $this->attributes[$key]; + } } $translations[$locale] = $value; - $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + if ($this->isNestedKey($key)) { + $this->fillJsonAttribute($key, $translations); + } else { + $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } event(new TranslationHasBeenSetEvent($this, $key, $locale, $oldValue, $value)); @@ -216,6 +237,11 @@ public function getTranslatedLocales(string $key): array return array_keys($this->getTranslations($key)); } + public function isNestedKey(string $key): bool + { + return str_contains($key, '->'); + } + public function isTranslatableAttribute(string $key): bool { return in_array($key, $this->getTranslatableAttributes()); @@ -328,14 +354,6 @@ public function translations(): Attribute }); } - public function getCasts(): array - { - return array_merge( - parent::getCasts(), - array_fill_keys($this->getTranslatableAttributes(), 'array'), - ); - } - public function locales(): array { return array_unique( diff --git a/tests/TestCase.php b/tests/TestCase.php index b7e24c4..a1296ba 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -28,6 +28,7 @@ protected function setUpDatabase() $table->text('name')->nullable(); $table->text('other_field')->nullable(); $table->text('field_with_mutator')->nullable(); + $table->json('nested')->nullable(); }); } } diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index d8ca301..32b683a 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -927,3 +927,56 @@ public function setAttributesExternally(array $attributes) expect($this->testModel->getTranslations('name'))->toEqual([]); }); + +it('can set and retrieve translations for nested fields', function () { + $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->setTranslations($nestedDeepFieldKey, [ + 'ar'=> 'nestedDeepFieldKey_ar', + 'en'=> 'nestedDeepFieldKey_en', + ]); + + $testModel->save(); + + expect($testModel->getTranslations()) + ->toEqual([ + $nestedFieldKey => [ + 'ar' => 'nestedFieldKey_ar', + 'nl' => 'nestedFieldKey_nl', + 'en' => 'nestedFieldKey_en', + ], + $nestedDeepFieldKey => [ + 'ar'=> 'nestedDeepFieldKey_ar', + 'en'=> 'nestedDeepFieldKey_en', + ], + ]); + + + expect($testModel->getTranslations($nestedDeepFieldKey)) + ->toEqual([ + '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'); +}); From 0affcb473418b1f28c9ab411833dbe3d43ec5c08 Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Sun, 26 Jan 2025 15:34:00 +0300 Subject: [PATCH 196/229] Enable mutators for nested fields --- src/HasTranslations.php | 38 +++++++++++++++++++----------------- tests/TranslatableTest.php | 40 +++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index bbf86f5..662c8f9 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -97,14 +97,14 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc } } - if (! $this->isNestedKey($key)) { - if ($this->hasGetMutator($key)) { - return $this->mutateAttribute($key, $translation); - } + $key = str_replace('->', '-', $key); - if ($this->hasAttributeMutator($key)) { - return $this->mutateAttributeMarkedAttribute($key, $translation); - } + if ($this->hasGetMutator($key)) { + return $this->mutateAttribute($key, $translation); + } + + if ($this->hasAttributeMutator($key)) { + return $this->mutateAttributeMarkedAttribute($key, $translation); } return $translation; @@ -152,23 +152,25 @@ public function setTranslation(string $key, string $locale, $value): self $oldValue = $translations[$locale] ?? ''; - if (! $this->isNestedKey($key)) { - if ($this->hasSetMutator($key)) { - $method = 'set'.Str::studly($key).'Attribute'; + $mutatorKey = str_replace('->', '-', $key); - $this->{$method}($value, $locale); + if ($this->hasSetMutator($mutatorKey)) { + $method = 'set'.Str::studly($mutatorKey).'Attribute'; - $value = $this->attributes[$key]; - } elseif ($this->hasAttributeSetMutator($key)) { // handle new attribute mutator - $this->setAttributeMarkedMutatedAttributeValue($key, $value); + $this->{$method}($value, $locale); - $value = $this->attributes[$key]; - } + $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]); + $this->fillJsonAttribute($key, $translations); } else { $this->attributes[$key] = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 32b683a..2735d1e 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1,6 +1,6 @@ $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 { + public $translatable = ['nested->field', 'nested->deep->field']; + + public function setNestedFieldAttribute($value) + { + $this->attributes['nested->field'] = strtolower($value); + } + + public function getNestedFieldAttribute($value) + { + return ucfirst($value); + } + + protected function nestedDeepField(): Attribute + { + return Attribute::make( + get: fn (string $value) => ucfirst($value), + set: fn (string $value) => strtolower($value), + ); + } + }; + + $nestedFieldKey = 'nested->field'; + $nestedDeepFieldKey = 'nested->deep->field'; + + app()->setLocale('ar'); + $testModel->$nestedFieldKey = 'NESTED FIELD AR'; + $testModel->$nestedDeepFieldKey = 'NESTED DEEP FIELD AR'; + $testModel->save(); + + expect($testModel->$nestedFieldKey) + ->toEqual('Nested field ar'); + + expect($testModel->$nestedDeepFieldKey) + ->toEqual('Nested deep field ar'); +}); From 9f8e5d32abdbff0443b6bb2a6505a9480fe9cf3e Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Mon, 27 Jan 2025 18:55:49 +0300 Subject: [PATCH 197/229] Refactor test to use new Attribute() instead of Attribute::make() - Ensures compatibility with all Laravel 9.0 and 9.1 --- tests/TranslatableTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 2735d1e..6ed891e 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -997,7 +997,7 @@ public function getNestedFieldAttribute($value) protected function nestedDeepField(): Attribute { - return Attribute::make( + return new Attribute( get: fn (string $value) => ucfirst($value), set: fn (string $value) => strtolower($value), ); From e669d97b17a8423043af7ecc737c9c6c3b1c2bdf Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Mon, 27 Jan 2025 20:38:11 +0300 Subject: [PATCH 198/229] Update README to include nested key translation support --- README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6d5871e..ab1d81a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ class NewsItem extends Model { use HasTranslations; + public $translatable = ['name']; // translatable attributes + // ... } ``` @@ -32,14 +34,30 @@ $newsItem->name; // Returns 'Name in English' given that the current app locale $newsItem->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands' app()->setLocale('nl'); - $newsItem->name; // Returns 'Naam in het Nederlands' -// If you want to query records based on locales, you can use the `whereLocale` and `whereLocales` methods. +$newsItem->getTranslations('name'); // returns an array of all name translations + +// You can translate nested keys of a JSON column using the -> notation +// First, add the path to the $translatable array, e.g., 'meta->description' +$newsItem + ->setTranslation('meta->description', 'en', 'Description in English') + ->setTranslation('meta->description', 'nl', 'Beschrijving in het Nederlands') + ->save(); -NewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a name in English +$attributeKey = 'meta->description'; +$newsItem->$attributeKey; // Returns 'Description in English' +$newsItem->getTranslation('meta->description', 'nl'); // Returns 'Beschrijving in het Nederlands' +``` -NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items with a name in English or Dutch +Also providing scoped queries for retrieving records based on locales + +```php +// Returns all news items with a name in English +NewsItem::whereLocale('name', 'en')->get(); + +// Returns all news items with a name in English or Dutch +NewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items that has name in English with value `Name in English` NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); @@ -54,8 +72,6 @@ NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in%', 'like')->ge // Returns all news items that has name in English or Dutch with value like `Name in...` NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in%', 'like')->get(); - - ``` ## Support us From 4509548f609949a0512ebf296719854aa71013c0 Mon Sep 17 00:00:00 2001 From: freekmurze <483853+freekmurze@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:03:45 +0000 Subject: [PATCH 199/229] Update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7406fb8..82258ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.10.0 - 2025-01-31 + +### What's Changed + +* Support clearing translations using an empty array by @alipadron in https://github.com/spatie/laravel-translatable/pull/478 +* Bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 by @dependabot in https://github.com/spatie/laravel-translatable/pull/484 +* Add support for nested key translations by @thaqebon in https://github.com/spatie/laravel-translatable/pull/483 + +### New Contributors + +* @thaqebon made their first contribution in https://github.com/spatie/laravel-translatable/pull/483 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.9.3...6.10.0 + ## 6.9.3 - 2024-12-16 ### What's Changed From 2bf4dcd7b348f7bb113acfc73c23ee8dff964fba Mon Sep 17 00:00:00 2001 From: Ali Padron Date: Fri, 3 Jan 2025 15:25:21 -0400 Subject: [PATCH 200/229] Handle null values in database columns as null in translations - Updated the HasTranslations trait to return null for translations when the underlying database attribute is null. - Adjusted the logic in getTranslation to check if the raw attribute value is null before attempting to resolve translations. - Modified a test case to validate that null database values are treated as null in translations instead of empty strings. --- src/HasTranslations.php | 2 +- tests/TranslatableTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 662c8f9..80b4989 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -82,7 +82,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc $translations = $this->getTranslations($key); - $translation = $translations[$normalizedLocale] ?? ''; + $translation = is_null(self::getAttributeFromArray($key)) ? null : $translations[$normalizedLocale] ?? ''; $translatableConfig = app(Translatable::class); diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 6ed891e..231c673 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -854,7 +854,7 @@ public function setAttributesExternally(array $attributes) [['en' => 'english', 'nl' => 'dutch'], ['en', 'nl'], ['english', 'dutch']], ]); -it('should return empty string when the underlying attribute in database is null', function () { +it('should return null when the underlying attribute in database is null', function () { // we need to remove the name attribute from the translatable array // and add it back to make sure the name // attribute is holding `null` raw value @@ -864,7 +864,7 @@ public function setAttributesExternally(array $attributes) $translation = $this->testModel->getTranslation('name', 'en'); - expect($translation)->toBe(''); + expect($translation)->toBeNull(); }); it('should return locales with empty string translations when allowEmptyStringForTranslation is true', function () { From 0653875942887b87efb33fb0d2521594b86cadce Mon Sep 17 00:00:00 2001 From: freekmurze <483853+freekmurze@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:05:38 +0000 Subject: [PATCH 201/229] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82258ab..811103d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.10.1 - 2025-01-31 + +### What's Changed + +* Handle null database values as null in translations by @alipadron in https://github.com/spatie/laravel-translatable/pull/479 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.10.0...6.10.1 + ## 6.10.0 - 2025-01-31 ### What's Changed From 535386938f9c8ee5c9fd523a2916a44793817b6a Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Fri, 31 Jan 2025 20:49:08 +0300 Subject: [PATCH 202/229] fix casts on initialization of HasTranslation - to not add `id` on initialization --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index 80b4989..fa159fd 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -17,7 +17,7 @@ trait HasTranslations public function initializeHasTranslations(): void { $this->mergeCasts(array_merge( - $this->getCasts(), + $this->casts, array_fill_keys($this->getTranslatableAttributes(), 'array'), )); } From e1786c070f9618a7dcb5150ea1e484d540b4beff Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Fri, 31 Jan 2025 20:51:41 +0300 Subject: [PATCH 203/229] Handle null values for nested key --- src/HasTranslations.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index fa159fd..bbfcae2 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -82,7 +82,9 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc $translations = $this->getTranslations($key); - $translation = is_null(self::getAttributeFromArray($key)) ? null : $translations[$normalizedLocale] ?? ''; + $baseKey = Str::before($key, '->'); // get base key in case it is JSON nested key + + $translation = is_null(self::getAttributeFromArray($baseKey)) ? null : $translations[$normalizedLocale] ?? ''; $translatableConfig = app(Translatable::class); From f596f7292a8abbc2d0a53cb4bd78718752f69a8c Mon Sep 17 00:00:00 2001 From: Omar Alnabris Date: Fri, 31 Jan 2025 23:17:50 +0300 Subject: [PATCH 204/229] Remove duplicate merging; `mergeCasts()` now handles the merge correctly. --- src/HasTranslations.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index bbfcae2..aad9e1a 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -16,10 +16,9 @@ trait HasTranslations public function initializeHasTranslations(): void { - $this->mergeCasts(array_merge( - $this->casts, + $this->mergeCasts( array_fill_keys($this->getTranslatableAttributes(), 'array'), - )); + ); } public static function usingLocale(string $locale): self From f2e883ca2d0978bdfca982f1f621e51fe99591a9 Mon Sep 17 00:00:00 2001 From: freekmurze <483853+freekmurze@users.noreply.github.com> Date: Mon, 3 Feb 2025 08:49:49 +0000 Subject: [PATCH 205/229] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 811103d..e8f4925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.10.2 - 2025-02-03 + +### What's Changed + +* Fix casts on initialization of HasTranslation by @thaqebon in https://github.com/spatie/laravel-translatable/pull/486 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.10.1...6.10.2 + ## 6.10.1 - 2025-01-31 ### What's Changed From b0781bf846f5ae5c5110dc319f512b3c4588755d Mon Sep 17 00:00:00 2001 From: Vladyslav Martynenko Date: Wed, 12 Feb 2025 21:39:30 +0200 Subject: [PATCH 206/229] test: add test for return null when translation is null and allowNullForTranslation is true --- tests/TranslatableTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 231c673..cfa2753 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1018,3 +1018,13 @@ protected function nestedDeepField(): Attribute expect($testModel->$nestedDeepFieldKey) ->toEqual('Nested deep field ar'); }); + +it('should return null when translation is null and allowNullForTranslation is true', function () { + Translatable::allowNullForTranslation(true); + + $this->testModel->setTranslation('name', 'en', null); + + $translation = $this->testModel->getTranslation('name', 'en'); + + expect($translation)->toBeNull(); +}); From d0a3efaec80d7f5714dd449ac17ae5ed8916895f Mon Sep 17 00:00:00 2001 From: Vladyslav Martynenko Date: Wed, 12 Feb 2025 22:32:11 +0200 Subject: [PATCH 207/229] test: add test for return empty string when translation is null and allowNullForTranslation is false --- tests/TranslatableTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index cfa2753..03b3fe7 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -1028,3 +1028,13 @@ protected function nestedDeepField(): Attribute expect($translation)->toBeNull(); }); + +it('should return empty string when translation is null and allowNullForTranslation is false', function () { + Translatable::allowNullForTranslation(false); + + $this->testModel->setTranslation('name', 'en', null); + + $translation = $this->testModel->getTranslation('name', 'en'); + + expect($translation)->toBe(''); +}); From 2c1b6fe02e08320b1806741547b2977f04242596 Mon Sep 17 00:00:00 2001 From: Vladyslav Martynenko Date: Wed, 12 Feb 2025 22:33:50 +0200 Subject: [PATCH 208/229] feature: return null if translation is null and allowNullForTranslation is true --- src/HasTranslations.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index aad9e1a..b52a5f7 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -83,10 +83,15 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc $baseKey = Str::before($key, '->'); // get base key in case it is JSON nested key - $translation = is_null(self::getAttributeFromArray($baseKey)) ? null : $translations[$normalizedLocale] ?? ''; - $translatableConfig = app(Translatable::class); + if (is_null(self::getAttributeFromArray($baseKey))) { + $translation = null; + } else { + $translation = isset($translations[$normalizedLocale]) ? $translations[$normalizedLocale] : null; + $translation ??= ($translatableConfig->allowNullForTranslation) ? null : ''; + } + if ($isKeyMissingFromLocale && $translatableConfig->missingKeyCallback) { try { $callbackReturnValue = (app(Translatable::class)->missingKeyCallback)($this, $key, $locale, $translation, $normalizedLocale); From c34190db26f64b43dde6e6b93ad0c71ebfe87902 Mon Sep 17 00:00:00 2001 From: Vladyslav Martynenko Date: Wed, 12 Feb 2025 22:36:52 +0200 Subject: [PATCH 209/229] chore: add missing methods docs in Translatable facade --- src/Facades/Translatable.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Facades/Translatable.php b/src/Facades/Translatable.php index 6e50fc4..dd88583 100644 --- a/src/Facades/Translatable.php +++ b/src/Facades/Translatable.php @@ -8,6 +8,8 @@ * @see \Spatie\Translatable\Translatable * * @method static void fallback(?string $fallbackLocale = null, ?bool $fallbackAny = false, $missingKeyCallback = null) + * @method static void allowNullForTranslation(bool $allowNullForTranslation = true) + * @method static void allowEmptyStringForTranslation(bool $allowEmptyStringForTranslation = true) */ class Translatable extends Facade { From 8b4432d5d7130f164a069d9bbbd4434f5ff87ce0 Mon Sep 17 00:00:00 2001 From: Vladyslav Martynenko Date: Wed, 12 Feb 2025 23:08:29 +0200 Subject: [PATCH 210/229] chore: use already existing config object to call missingKeyCallback Use existing object instead of retrieving the same singleton object from container --- src/HasTranslations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index b52a5f7..c35f1a1 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -94,7 +94,7 @@ public function getTranslation(string $key, string $locale, bool $useFallbackLoc if ($isKeyMissingFromLocale && $translatableConfig->missingKeyCallback) { try { - $callbackReturnValue = (app(Translatable::class)->missingKeyCallback)($this, $key, $locale, $translation, $normalizedLocale); + $callbackReturnValue = ($translatableConfig->missingKeyCallback)($this, $key, $locale, $translation, $normalizedLocale); if (is_string($callbackReturnValue)) { $translation = $callbackReturnValue; } From bdce1c5702b92593cce084eb8ae7b4601c2e1e67 Mon Sep 17 00:00:00 2001 From: freekmurze <483853+freekmurze@users.noreply.github.com> Date: Fri, 14 Feb 2025 14:47:15 +0000 Subject: [PATCH 211/229] Update CHANGELOG --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8f4925..41fe4d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.11.3 - 2025-02-14 + +### What's Changed + +* Allow null value in translations if allowNullForTranslation is true by @dont-know-php in https://github.com/spatie/laravel-translatable/pull/488 + +### New Contributors + +* @dont-know-php made their first contribution in https://github.com/spatie/laravel-translatable/pull/488 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.10.2...6.11.3 + ## 6.10.2 - 2025-02-03 ### What's Changed From 900cbeee7b518f538bf7c5263332a4e408273568 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 20 Feb 2025 16:42:21 +0100 Subject: [PATCH 212/229] bump versions --- .github/workflows/run-tests.yml | 15 +++++++++------ .phpunit.cache/test-results | 1 + composer.json | 8 ++++---- phpunit.xml.dist | 12 ++++++------ 4 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 .phpunit.cache/test-results diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 6b98667..55fc46f 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,20 +9,23 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.3, 8.2, 8.1, 8.0] - laravel: [11.*, 10.*, 9.*] + php: [8.4, 8.3, 8.2, 8.1, 8.0] + laravel: [12.*, 11.*, 10.*, 9.*] stability: [prefer-lowest, prefer-stable] include: + - laravel: 12.* + testbench: 10.* - laravel: 11.* testbench: 9.* - carbon: ^3.0 - laravel: 10.* testbench: 8.* - carbon: ^2.63 - laravel: 9.* testbench: 7.* - carbon: ^2.63 exclude: + - laravel: 12.* + php: 8.1 + - laravel: 12.* + php: 8.0 - laravel: 11.* php: 8.1 - laravel: 11.* @@ -50,7 +53,7 @@ jobs: - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "nesbot/carbon:${{ matrix.carbon }}" --no-interaction --no-update + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests diff --git a/.phpunit.cache/test-results b/.phpunit.cache/test-results new file mode 100644 index 0000000..96aead2 --- /dev/null +++ b/.phpunit.cache/test-results @@ -0,0 +1 @@ +{"version":"pest_3.7.4","defects":[],"times":{"P\\Tests\\EventTest::__pest_evaluable_it_will_fire_an_event_when_a_translation_has_been_set":0.013,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_package_fallback_locale_translation_when_getting_an_unknown_locale":0.008,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_provides_a_flog_to_not_return_fallback_locale_translation_when_getting_an_unknown_locale":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_fallback_locale_translation_when_getting_an_unknown_locale_and_fallback_is_true":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_execute_callback_fallback_when_getting_an_unknown_locale_and_fallback_callback_is_enabled":0.005,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_use_callback_fallback_return_value_as_translation":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_wont_use_callback_fallback_return_value_as_translation_if_it_is_not_a_string":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_wont_execute_callback_fallback_when_getting_an_existing_translation":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_wont_fail_if_callback_fallback_throw_exception":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_not_set":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_an_empty_string_when_getting_an_unknown_locale_and_fallback_is_empty":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_save_a_translated_attribute":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_translated_values_when_creating_a_model":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_save_multiple_translations":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_the_value_of_the_current_locale_when_using_the_property":0.002,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_get_all_translations_in_one_go":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_get_specified_translations_in_one_go":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_get_all_translations_for_all_translatable_attributes_in_one_go":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_get_specified_translations_for_all_translatable_attributes_in_one_go":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_get_the_locales_which_have_a_translation":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_forget_a_translation":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_forget_all_translations_of_field":0.002,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_forget_all_translations_of_field_and_make_field_null":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_forget_a_field_with_mutator_translation":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_forget_all_translations":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_throw_an_exception_when_trying_to_translate_an_untranslatable_attribute":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_is_compatible_with_accessors_on_non_translatable_attributes":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_use_accessors_on_translated_attributes":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_be_converted_to_array_when_using_accessors_on_translated_attributes":0.002,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_use_mutators_on_translated_attributes":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_translations_for_default_language":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_multiple_translations_at_once":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_check_if_an_attribute_is_translatable":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_check_if_an_attribute_has_translation":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_correctly_set_a_field_when_a_mutator_is_defined":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_multiple_translations_when_a_mutator_is_defined":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_multiple_translations_on_field_when_a_mutator_is_defined":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_uses_the_attribute_to_mutate_the_translated_value":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_translate_a_field_based_on_the_translations_of_another_one":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_handle_null_value_from_database":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_get_all_translations":0.002,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_fallback_locale_translation_when_getting_an_empty_translation_from_the_locale":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_correct_translation_value_if_value_is_set_to_zero":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_not_return_fallback_value_if_value_is_set_to_zero":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_not_remove_zero_value_of_other_locale_in_database":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_be_translated_based_on_given_locale":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_and_fetch_attributes_based_on_set_locale":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_replace_translations":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_use_any_locale_if_given_locale_not_set":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_set_translation_when_fallback_any_set":0.002,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_fallback_translation_when_fallback_any_set":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_provides_a_flog_to_not_return_any_translation_when_getting_an_unknown_locale":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_default_fallback_locale_translation_when_getting_an_unknown_locale_with_fallback_any":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_will_return_all_locales_when_getting_all_translations":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_queries_the_database_whether_a_locale_exists":0.002,"P\\Tests\\TranslatableTest::__pest_evaluable_it_queries_the_database_for_multiple_locales":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_queries_the_database_whether_a_value_exists_in_a_locale":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_queries_the_database_whether_a_value_exists_in_a_multiple_locales":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_disable_attribute_locale_fallback_on_a_per_model_basis":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_fallback_locale_on_model":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_translations_macro_meets_expectations#(['english'], 'en', 'english')":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_translations_macro_meets_expectations#(['english', 'english'], ['en', 'nl'], 'english')":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_translations_macro_meets_expectations#(['english', 'dutch'], ['en', 'nl'], ['english', 'dutch'])":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_return_null_when_the_underlying_attribute_in_database_is_null":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_return_locales_with_empty_string_translations_when_allowEmptyStringForTranslation_is_true":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_not_return_locales_with_empty_string_translations_when_allowEmptyStringForTranslation_is_false":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_return_locales_with_null_translations_when_allowNullForTranslation_is_true":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_not_return_locales_with_null_translations_when_allowNullForTranslation_is_false":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_an_array_list_as_value_for_translation_using__setTranslation_":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_an_array_list_as_value_for_translation_using_default_local":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_treat_an_empty_array_as_value_for_clearing_translations":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_can_set_and_retrieve_translations_for_nested_fields":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_uses_mutators_for_setting_and_getting_translated_values_of_nested_fields":0.001,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_return_null_when_translation_is_null_and_allowNullForTranslation_is_true":0,"P\\Tests\\TranslatableTest::__pest_evaluable_it_should_return_empty_string_when_translation_is_null_and_allowNullForTranslation_is_false":0}} \ No newline at end of file diff --git a/composer.json b/composer.json index a909e2e..659aa4b 100644 --- a/composer.json +++ b/composer.json @@ -28,15 +28,15 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^9.0|^10.0|^11.0", - "illuminate/support": "^9.0|^10.0|^11.0", + "illuminate/database": "^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^9.0|^10.0|^11.0|^12.0", "spatie/laravel-package-tools": "^1.11" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.64", "mockery/mockery": "^1.4", - "orchestra/testbench": "^7.0|^8.0|^9.0", - "pestphp/pest": "^1.20|^2.0" + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "pestphp/pest": "^1.20|^2.0|^3.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index ea5583b..bdaf3e7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,10 +1,5 @@ - - - - src/ - - + tests @@ -13,4 +8,9 @@ + + + src/ + + From 929feb3780aa6b025cd9380043045d26fb3f90ea Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 20 Feb 2025 16:43:28 +0100 Subject: [PATCH 213/229] wip --- .php-cs-fixer.dist.php => .php-cs.dist.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .php-cs-fixer.dist.php => .php-cs.dist.php (100%) diff --git a/.php-cs-fixer.dist.php b/.php-cs.dist.php similarity index 100% rename from .php-cs-fixer.dist.php rename to .php-cs.dist.php From 73f6d06425de147a59a3203fbf31b9758ab6b8f0 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 20 Feb 2025 16:44:11 +0100 Subject: [PATCH 214/229] wip --- .github/workflows/run-tests.yml | 2 +- composer.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 55fc46f..26eab19 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,7 +10,7 @@ jobs: matrix: os: [ubuntu-latest] php: [8.4, 8.3, 8.2, 8.1, 8.0] - laravel: [12.*, 11.*, 10.*, 9.*] + laravel: [12.*, 11.*, 10.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 12.* diff --git a/composer.json b/composer.json index 659aa4b..79bf8cc 100644 --- a/composer.json +++ b/composer.json @@ -28,8 +28,8 @@ ], "require": { "php": "^8.0", - "illuminate/database": "^9.0|^10.0|^11.0|^12.0", - "illuminate/support": "^9.0|^10.0|^11.0|^12.0", + "illuminate/database": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", "spatie/laravel-package-tools": "^1.11" }, "require-dev": { From 6deab5909002478862b44d01ffaf4be4a02e6a1a Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 20 Feb 2025 16:50:08 +0100 Subject: [PATCH 215/229] wip --- .github/workflows/php-cs-fixer.yml | 19 ++++++++------ .github/workflows/run-tests.yml | 11 +++----- .php-cs.dist.php | 40 ------------------------------ 3 files changed, 15 insertions(+), 55 deletions(-) delete mode 100644 .php-cs.dist.php diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 5b87253..3f35219 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -1,10 +1,17 @@ -name: Check & fix styling +name: Fix PHP code style issues -on: [push] +on: + push: + paths: + - '**.php' + +permissions: + contents: write jobs: - php-cs-fixer: + php-code-styling: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: Checkout code @@ -12,10 +19,8 @@ jobs: with: ref: ${{ github.head_ref }} - - name: Run PHP CS Fixer - uses: docker://oskarstark/php-cs-fixer-ga - with: - args: --config=.php_cs.dist.php --allow-risky=yes + - name: Fix PHP code style issues + uses: aglipanci/laravel-pint-action@2.4 - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v5 diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 26eab19..f0e15ae 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,7 +10,7 @@ jobs: matrix: os: [ubuntu-latest] php: [8.4, 8.3, 8.2, 8.1, 8.0] - laravel: [12.*, 11.*, 10.*] + laravel: [12.*, 11.*, 10.*, 9.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 12.* @@ -29,7 +29,7 @@ jobs: - laravel: 11.* php: 8.1 - laravel: 11.* - php: 8.0 + php: 8.0 # - laravel: 10.* php: 8.0 @@ -46,14 +46,9 @@ jobs: extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick coverage: none - - name: Setup problem matchers - run: | - echo "::add-matcher::${{ runner.tool_cache }}/php.json" - echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests diff --git a/.php-cs.dist.php b/.php-cs.dist.php deleted file mode 100644 index 8d8a790..0000000 --- a/.php-cs.dist.php +++ /dev/null @@ -1,40 +0,0 @@ -in([ - __DIR__ . '/src', - __DIR__ . '/tests', - ]) - ->name('*.php') - ->notName('*.blade.php') - ->ignoreDotFiles(true) - ->ignoreVCS(true); - -return (new PhpCsFixer\Config()) - ->setRules([ - '@PSR12' => true, - 'array_syntax' => ['syntax' => 'short'], - 'ordered_imports' => ['sort_algorithm' => 'alpha'], - 'no_unused_imports' => true, - 'not_operator_with_successor_space' => true, - 'trailing_comma_in_multiline' => true, - 'phpdoc_scalar' => true, - 'unary_operator_spaces' => true, - 'binary_operator_spaces' => true, - 'blank_line_before_statement' => [ - 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], - ], - 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_var_without_name' => true, - 'class_attributes_separation' => [ - 'elements' => [ - 'method' => 'one', - ], - ], - 'method_argument_space' => [ - 'on_multiline' => 'ensure_fully_multiline', - 'keep_multiple_spaces_after_comma' => true, - ], - 'single_trait_insert_per_statement' => true, - ]) - ->setFinder($finder); From 87167fdfa06eeef7764b3e5b52cc665667198c11 Mon Sep 17 00:00:00 2001 From: freekmurze <483853+freekmurze@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:50:33 +0000 Subject: [PATCH 216/229] Fix styling --- src/HasTranslations.php | 16 ++-- src/TranslatableServiceProvider.php | 6 +- tests/EventTest.php | 2 +- tests/TestSupport/TestModel.php | 1 + .../TestModelWithFallbackLocale.php | 1 + .../TestSupport/TestModelWithoutFallback.php | 1 + tests/TranslatableTest.php | 94 ++++++++++--------- 7 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/HasTranslations.php b/src/HasTranslations.php index c35f1a1..feeb736 100644 --- a/src/HasTranslations.php +++ b/src/HasTranslations.php @@ -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 @@ -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 } } @@ -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); } @@ -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), @@ -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]); diff --git a/src/TranslatableServiceProvider.php b/src/TranslatableServiceProvider.php index 3da7bf7..6cf6c01 100644 --- a/src/TranslatableServiceProvider.php +++ b/src/TranslatableServiceProvider.php @@ -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); }); } } diff --git a/tests/EventTest.php b/tests/EventTest.php index 8ca73fa..e281878 100644 --- a/tests/EventTest.php +++ b/tests/EventTest.php @@ -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 () { diff --git a/tests/TestSupport/TestModel.php b/tests/TestSupport/TestModel.php index f10e18b..ea9e337 100644 --- a/tests/TestSupport/TestModel.php +++ b/tests/TestSupport/TestModel.php @@ -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']; diff --git a/tests/TestSupport/TestModelWithFallbackLocale.php b/tests/TestSupport/TestModelWithFallbackLocale.php index 9a05db7..a75e3ee 100644 --- a/tests/TestSupport/TestModelWithFallbackLocale.php +++ b/tests/TestSupport/TestModelWithFallbackLocale.php @@ -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']; diff --git a/tests/TestSupport/TestModelWithoutFallback.php b/tests/TestSupport/TestModelWithoutFallback.php index ed9eceb..9e46e90 100644 --- a/tests/TestSupport/TestModelWithoutFallback.php +++ b/tests/TestSupport/TestModelWithoutFallback.php @@ -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']; diff --git a/tests/TranslatableTest.php b/tests/TranslatableTest.php index 03b3fe7..d4b3d72 100644 --- a/tests/TranslatableTest.php +++ b/tests/TranslatableTest.php @@ -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 () { @@ -56,8 +56,8 @@ 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'); @@ -65,12 +65,12 @@ 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'); @@ -94,8 +94,8 @@ 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'); @@ -103,12 +103,12 @@ 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'); @@ -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}"; @@ -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}"; @@ -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}"; @@ -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}"; @@ -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}"; @@ -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 @@ -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); } }); @@ -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; @@ -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(); @@ -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'; @@ -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 => [ @@ -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); @@ -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'); From aab7dc72cdd29b473e7a47f006d548f2f1d663b6 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Thu, 20 Feb 2025 16:51:12 +0100 Subject: [PATCH 217/229] wip --- .github/workflows/run-tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f0e15ae..fe3b7ef 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,7 +10,7 @@ jobs: matrix: os: [ubuntu-latest] php: [8.4, 8.3, 8.2, 8.1, 8.0] - laravel: [12.*, 11.*, 10.*, 9.*] + laravel: [12.*, 11.*, 10.*] stability: [prefer-lowest, prefer-stable] include: - laravel: 12.* @@ -19,8 +19,6 @@ jobs: testbench: 9.* - laravel: 10.* testbench: 8.* - - laravel: 9.* - testbench: 7.* exclude: - laravel: 12.* php: 8.1 From 525ca368a1ca2a2f3825f93e7de392729f834d10 Mon Sep 17 00:00:00 2001 From: freekmurze <483853+freekmurze@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:53:08 +0000 Subject: [PATCH 218/229] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41fe4d8..8ebff21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `laravel-translatable` will be documented in this file +## 6.11.4 - 2025-02-20 + +**Full Changelog**: https://github.com/spatie/laravel-translatable/compare/6.11.3...6.11.4 + ## 6.11.3 - 2025-02-14 ### What's Changed From 115f83d3feb8859512b8622746392e069cbe7016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 02:38:17 +0000 Subject: [PATCH 219/229] Bump aglipanci/laravel-pint-action from 2.4 to 2.5 Bumps [aglipanci/laravel-pint-action](https://github.com/aglipanci/laravel-pint-action) from 2.4 to 2.5. - [Release notes](https://github.com/aglipanci/laravel-pint-action/releases) - [Commits](https://github.com/aglipanci/laravel-pint-action/compare/2.4...2.5) --- updated-dependencies: - dependency-name: aglipanci/laravel-pint-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 3f35219..6035670 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -20,7 +20,7 @@ jobs: ref: ${{ github.head_ref }} - name: Fix PHP code style issues - uses: aglipanci/laravel-pint-action@2.4 + uses: aglipanci/laravel-pint-action@2.5 - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v5 From 078d450b9c2fda88db6078f254f3a079207967be Mon Sep 17 00:00:00 2001 From: Jimi Robaer Date: Tue, 8 Apr 2025 17:15:36 +0200 Subject: [PATCH 220/229] Update README.md --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab1d81a..6d75dac 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,19 @@ -# A trait to make Eloquent models translatable +
+ + + + Logo for laravel-translatable + + + +

A trait to make Eloquent models translatable

[![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-translatable/run-tests.yml) [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-translatable) + +
This package contains a trait `HasTranslations` to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them. From 32ba750b2ed16091be017fd93be2073e12e9b725 Mon Sep 17 00:00:00 2001 From: Jimi Robaer Date: Tue, 22 Apr 2025 09:32:19 +0200 Subject: [PATCH 221/229] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d75dac..c763531 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ - Logo for laravel-translatable + Logo for laravel-translatable From 68da39a39e2f48948c9ed4afc4147103d20874f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 02:43:22 +0000 Subject: [PATCH 222/229] Bump dependabot/fetch-metadata from 2.3.0 to 2.4.0 Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v2.3.0...v2.4.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index e99b9aa..531772b 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.3.0 + uses: dependabot/fetch-metadata@v2.4.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true From 5d535dcc1d45139bf30b94cc50a2439a77cc031e Mon Sep 17 00:00:00 2001 From: Afzaal565 <98333630+Afzaal565@users.noreply.github.com> Date: Tue, 20 May 2025 21:11:58 +0500 Subject: [PATCH 223/229] Update README.md Added a link of DB Field Translation Package Created By Afzaal565 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c763531..49a4ad9 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,8 @@ We publish all received postcards [on our company website](https://spatie.be/en/ - [All Contributors](../../contributors) We got the idea to store translations as json in a column from [Mohamed Said](https://github.com/themsaid). Parts of the readme of [his multilingual package](https://github.com/themsaid/laravel-multilingual) were used in this readme. - +And the new Ideas is to manage and store translation with morhpto many method for each model. Parts of the readme of [DB-Fields-Translations](https://github.com/Afzaal565/DB-Fields-Translations) +## For more detail please visit (https://github.com/Afzaal565/DB-Fields-Translations) ## License The MIT License (MIT). Please see [License File](LICENSE.md) for more information. From 709a67ab90c83c6a275464c55380e6040244f08f Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Tue, 20 May 2025 18:28:32 +0200 Subject: [PATCH 224/229] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 49a4ad9..4ddd883 100644 --- a/README.md +++ b/README.md @@ -125,8 +125,11 @@ We publish all received postcards [on our company website](https://spatie.be/en/ - [All Contributors](../../contributors) We got the idea to store translations as json in a column from [Mohamed Said](https://github.com/themsaid). Parts of the readme of [his multilingual package](https://github.com/themsaid/laravel-multilingual) were used in this readme. -And the new Ideas is to manage and store translation with morhpto many method for each model. Parts of the readme of [DB-Fields-Translations](https://github.com/Afzaal565/DB-Fields-Translations) -## For more detail please visit (https://github.com/Afzaal565/DB-Fields-Translations) + +## Alternatives + +- [DB-Fields-Translations](https://github.com/Afzaal565/DB-Fields-Translations) + ## License The MIT License (MIT). Please see [License File](LICENSE.md) for more information. From cd7dc7c89cf74cda2b687c989cc57b2df1ebecc4 Mon Sep 17 00:00:00 2001 From: Jimi Robaer Date: Thu, 5 Jun 2025 13:16:30 +0200 Subject: [PATCH 225/229] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ddd883..c959042 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ - Logo for laravel-translatable + Logo for laravel-translatable From 8581368d1f0303275f8b2c835ed6d933e889499b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 02:24:48 +0000 Subject: [PATCH 226/229] Bump stefanzweifel/git-auto-commit-action from 5 to 6 Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 5 to 6. - [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases) - [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v5...v6) --- updated-dependencies: - dependency-name: stefanzweifel/git-auto-commit-action dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- .github/workflows/update-changelog.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 6035670..768eefa 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -23,6 +23,6 @@ jobs: uses: aglipanci/laravel-pint-action@2.5 - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v6 with: commit_message: Fix styling diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 0cdea23..de5865b 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -21,7 +21,7 @@ jobs: release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v6 with: branch: main commit_message: Update CHANGELOG From 917292a7af24cd682af024b18f8a406814a8ccf2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 03:03:04 +0000 Subject: [PATCH 227/229] Bump aglipanci/laravel-pint-action from 2.5 to 2.6 Bumps [aglipanci/laravel-pint-action](https://github.com/aglipanci/laravel-pint-action) from 2.5 to 2.6. - [Release notes](https://github.com/aglipanci/laravel-pint-action/releases) - [Commits](https://github.com/aglipanci/laravel-pint-action/compare/2.5...2.6) --- updated-dependencies: - dependency-name: aglipanci/laravel-pint-action dependency-version: '2.6' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 768eefa..a662e22 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -20,7 +20,7 @@ jobs: ref: ${{ github.head_ref }} - name: Fix PHP code style issues - uses: aglipanci/laravel-pint-action@2.5 + uses: aglipanci/laravel-pint-action@2.6 - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v6 From 34e4281d6157fcc7792d01b3c45f0939aef19d33 Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Mon, 8 Sep 2025 08:52:26 +0200 Subject: [PATCH 228/229] Update issue template --- .github/ISSUE_TEMPLATE/config.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..141e28e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Feature Request + url: https://github.com/spatie/laravel-translatable/discussions/new?category=ideas + about: Share ideas for new features + - name: Ask a Question + url: https://github.com/spatie/laravel-translatable/discussions/new?category=q-a + about: Ask the community for help From b067f1ce8e310bfeb1264531bdff1f9fbe4cff3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 02:03:32 +0000 Subject: [PATCH 229/229] Bump stefanzweifel/git-auto-commit-action from 6 to 7 Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 6 to 7. - [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases) - [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v6...v7) --- updated-dependencies: - dependency-name: stefanzweifel/git-auto-commit-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/php-cs-fixer.yml | 2 +- .github/workflows/update-changelog.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index a662e22..fce0e57 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -23,6 +23,6 @@ jobs: uses: aglipanci/laravel-pint-action@2.6 - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v6 + uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Fix styling diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index de5865b..d9e92e7 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -21,7 +21,7 @@ jobs: release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v6 + uses: stefanzweifel/git-auto-commit-action@v7 with: branch: main commit_message: Update CHANGELOG