├── .eslintrc ├── .github ├── FUNDING.yml └── workflows │ ├── php-cs-fixer.yml │ └── run-tests.yml ├── .prettierrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── package.json ├── src ├── Exceptions │ └── InvalidConfiguration.php └── Translatable.php ├── webpack.mix.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:vue/essential", 5 | "prettier" 6 | ], 7 | "parserOptions": { 8 | "ecmaVersion": 2017 9 | }, 10 | "globals": { 11 | "Nova": true 12 | }, 13 | "env": { 14 | "browser": true, 15 | "node": true 16 | }, 17 | "rules": { 18 | "vue/html-indent": ["error", 4] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://spatie.be/open-source/support-us 2 | -------------------------------------------------------------------------------- /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: Check & fix styling 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v2 12 | with: 13 | ref: ${{ github.head_ref }} 14 | 15 | - name: Run PHP CS Fixer 16 | uses: docker://oskarstark/php-cs-fixer-ga 17 | with: 18 | args: --config=.php_cs.dist --allow-risky=yes 19 | 20 | - name: Commit changes 21 | uses: stefanzweifel/git-auto-commit-action@v4 22 | with: 23 | commit_message: Fix styling 24 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: run-tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: true 10 | matrix: 11 | os: [ubuntu-latest] 12 | php: [8.2, 8.1, 8.0, 7.4] 13 | laravel: [7.*, 8.*, 9.*] 14 | dependency-version: [prefer-stable] 15 | include: 16 | - laravel: 9.* 17 | testbench: 7.* 18 | - laravel: 8.* 19 | testbench: 6.* 20 | - laravel: 7.* 21 | testbench: 5.* 22 | exclude: 23 | - laravel: 9.* 24 | php: 7.4 25 | - laravel: 7.* 26 | php: 8.1 27 | 28 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 29 | 30 | steps: 31 | - name: Checkout code 32 | uses: actions/checkout@v2 33 | 34 | - name: Setup PHP 35 | uses: shivammathur/setup-php@v2 36 | with: 37 | php-version: ${{ matrix.php }} 38 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo 39 | coverage: none 40 | 41 | - name: Install dependencies 42 | run: | 43 | composer require "laravel/framework:${{ matrix.laravel }}" "nesbot/carbon:^2.63" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 44 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction 45 | env: 46 | COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} 47 | 48 | - name: Execute tests 49 | run: vendor/bin/phpunit 50 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "tabWidth": 4, 5 | "trailingComma": "es5" 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `nova-translatable` will be documented in this file 4 | 5 | ## 3.0.3 - 2021-04-22 6 | 7 | - updated spatie/laravel-translatable dependency to ^4.0 | ^5.0 8 | 9 | ## 3.0.2 - 2020-09-09 10 | 11 | - Add support for Laravel 8 12 | 13 | ## 3.0.1 - 2020-03-18 14 | 15 | - Add `translatedFieldsByLocale` property (#38) 16 | 17 | ## 2.0.3 - 2019-09-04 18 | 19 | - Support Laravel 6 20 | 21 | ## 2.0.2 - 2019-04-02 22 | 23 | - Fix locale not supporting underscores (#27) 24 | 25 | ## 2.0.1 - 2019-03-03 26 | 27 | - improve Nova dep 28 | 29 | ## 2.0.0 - 2019-02-27 30 | 31 | - support for Laravel 5.8 and Nova 2.0 32 | 33 | ## 1.0.1 - 2019-01-12 34 | 35 | - fix support for nova panels wrapping translatable fields 36 | 37 | ## 1.0.0 - 2018-10-24 38 | 39 | - initial release 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Spatie bvba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Making Nova fields translatable 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/nova-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/nova-translatable) 4 | ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spatie/nova-translatable/run-tests.yml?branch=main&style=flat-square&label=Tests) 5 | ![Check & fix styling](https://img.shields.io/github/actions/workflow/status/spatie/nova-translatable/php-cs-fixer.yml?branch=main&style=flat-square&label=Check%20%26%20fix%20styling) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/nova-translatable.svg?style=flat-square)](https://packagist.org/packages/spatie/nova-translatable) 7 | 8 | This package contains a `Translatable` class you can use to make any Nova field type translatable. 9 | 10 | Imagine you have this `fields` method in a `Post` Nova resource: 11 | 12 | ```php 13 | public function fields(Request $request) 14 | { 15 | return [ 16 | ID::make()->sortable(), 17 | 18 | Translatable::make([ 19 | Text::make('title'), 20 | Trix::make('text'), 21 | ]), 22 | ]; 23 | } 24 | ``` 25 | 26 | That `Post` Nova resource will be rendered like this. 27 | 28 | ![screenshot]( https://spatie.github.io/nova-translatable/screenshot.png) 29 | 30 | ## Support us 31 | 32 | [](https://spatie.be/github-ad-click/nova-translatable) 33 | 34 | 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). 35 | 36 | 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). 37 | 38 | ## Requirements 39 | 40 | This Nova field requires Nova 4 or 5 specifically and MySQL 5.7.8 or higher. 41 | 42 | ## Installation 43 | 44 | First you must install [spatie/laravel-translatable](https://github.com/spatie/laravel-translatable) into your Laravel app. In a nutshell, this package will store translations for your model in a json column in your table. On top of that, it provides many handy functions to store and retrieve translations. Be sure to read [the entire readme of laravel-translatable](https://github.com/spatie/laravel-translatable/blob/master/README.md) before using this Nova package. 45 | 46 | Next, you can install this Nova package into a Laravel app that uses [Nova](https://nova.laravel.com) via composer: 47 | 48 | ```bash 49 | composer require spatie/nova-translatable 50 | ``` 51 | 52 | ## Usage 53 | 54 | In order to use the package you must first let `Translatable` know which locales your app is using using the `Translatable::defaultLocales()` method. You can put this code in `AppServiceProvider` or a dedicated service provider of your own. 55 | 56 | ```php 57 | // in any service provider 58 | 59 | \Spatie\NovaTranslatable\Translatable::defaultLocales(['en', 'fr']); 60 | ``` 61 | 62 | Next, you must prepare your model [as explained](https://github.com/spatie/laravel-translatable#making-a-model-translatable) in the readme of laravel-translatable. In short: you must add `json` columns to your model's table for each field you want to translate. Your model must use the `Spatie\Translatable\HasTranslations` on your model. Finally, you must also add a `$translatable` property on your model that holds an array with the translatable attribute names. 63 | 64 | Now that your model is configured for translations, you can use `Translatable` in the related Nova resource. Any fields you want to display in a multilingual way can be passed as an array to `Translatable. 65 | 66 | ```php 67 | public function fields(Request $request) 68 | { 69 | return [ 70 | ID::make()->sortable(), 71 | 72 | Translatable::make([ 73 | Text::make('title'), 74 | Trix::make('text'), 75 | ]), 76 | ]; 77 | } 78 | ``` 79 | 80 | ### Making translations searchable 81 | 82 | Every translation of the translated fields should be added into the `$search` array separately. 83 | 84 | ```php 85 | /** 86 | * The columns that should be searched. 87 | * 88 | * @var array 89 | */ 90 | public static $search = [ 91 | 'id', 'name->en', 'name->fr', 92 | ]; 93 | ``` 94 | 95 | ### Customizing the locales per translatable 96 | 97 | If you have a Nova resource where you want different locales than the ones configured globally, you can call the `locales` method on `Translatable`. 98 | 99 | ```php 100 | Translatable::make([ 101 | Text::make('title'), 102 | Trix::make('text'), 103 | ])->locales(['de', 'es']), 104 | ``` 105 | 106 | These fields will now use the `de` and `es` locales. 107 | 108 | ### Customizing the name of a translatable 109 | 110 | By default translatable fields get ` ($locale)` appended to their name. You can customize this behaviour globally by providing a closure to `displayLocalizedNameByDefaultUsing` on `Translatable`. This callback will be used to render the localized field names. 111 | 112 | ```php 113 | Translatable::displayLocalizedNameByDefaultUsing(function(Field $field, string $locale) { 114 | return ucfirst($field->name) . " [{$locale}]"; 115 | }) 116 | ``` 117 | 118 | With this in place all names of translatable fields will get ` [$locale]` appended. 119 | 120 | You can also customize the localized field name per resource by passing a closure the `displayLocalizedNameUsing` function. 121 | 122 | ```php 123 | Translatable::make([ 124 | Text::make('title'), 125 | Trix::make('text'), 126 | ])->displayLocalizedNameUsing(function(Field $field, string $locale) { 127 | return ucfirst($field->name) . " --- {$locale}]"; 128 | }), 129 | ``` 130 | 131 | With this in place, the localized field names will be suffixed with ` --- $locale`. 132 | 133 | Of course you can still customize the name of a field as usual. 134 | 135 | ```php 136 | Translatable::make([ 137 | Text::make('My title', 'title'), 138 | Trix::make('text'), 139 | ])->displayLocalizedNameUsing(function(Field $field, string $locale) { 140 | return ucfirst($field->name) . " [{$locale}]"; 141 | }), 142 | ``` 143 | 144 | Using the code about above the name for the `title` field will be "My title ['en']". 145 | 146 | ### Customizing the rules of a translatable 147 | 148 | You may use the regular Nova functionality to define rules on the fields inside your Translatable fields collection. However, this will apply those rules to all locales. If you wish to define different rules per locale you can do so on the Translatable collection. 149 | 150 | ```php 151 | Translatable::make([ 152 | Text::make('My title', 'title'), 153 | Trix::make('text'), 154 | ])->rules([ 155 | 'title' => ['en' => 'required', 'nl' => 'nullable'], 156 | 'text' => ['en' => 'required|min:10', 'nl' => 'nullable|min:10'], 157 | ] 158 | ), 159 | ``` 160 | 161 | You may also use the more fluent `rulesFor()` method, which allows you to define rules per field per locale. 162 | 163 | ```php 164 | Translatable::make([ 165 | Text::make('My title', 'title'), 166 | Trix::make('text'), 167 | ])->rulesFor('title', 'en', 'required') 168 | ->rulesFor('title', 'nl', 'nullable'), 169 | ``` 170 | 171 | There are also methods for update and creation rules called `creationRules()`, `updateRules()`, `creationRulesFor()` and `updateRulesFor()`. They function in the same way as the `rules()` and `rulesFor()` methods. 172 | 173 | ## On customizing the UI 174 | 175 | You might wonder why we didn't render the translatable fields in tabs, panels or with magical unicorns displayed next to them. The truth is that everybody wants translations to be displayed a bit different. That's why we opted to keep them very simple for now. 176 | 177 | If Nova gains the ability to better structure a long form natively, we'd probably start leveraging that in a new major version of the package. 178 | 179 | ### Testing 180 | 181 | ```bash 182 | composer test 183 | ``` 184 | 185 | ### Changelog 186 | 187 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 188 | 189 | ## Contributing 190 | 191 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 192 | 193 | ### Security 194 | 195 | If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. 196 | 197 | ## Credits 198 | 199 | - [Freek Van der Herten](https://github.com/freekmurze) 200 | 201 | ## License 202 | 203 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 204 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/nova-translatable", 3 | "description": "Making Nova fields translatable", 4 | "keywords": [ 5 | "laravel", 6 | "nova" 7 | ], 8 | "homepage": "https://github.com/spatie/nova-translatable", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Freek Van der Herten", 13 | "email": "freek@spatie.be", 14 | "role": "Developer" 15 | } 16 | ], 17 | "repositories": [ 18 | { 19 | "type": "composer", 20 | "url": "https://nova.laravel.com" 21 | } 22 | ], 23 | "require": { 24 | "php": "^7.3|^8.0", 25 | "laravel/nova": "^4.0|^5.0", 26 | "spatie/laravel-translatable": "^5.0|^6.0" 27 | }, 28 | "require-dev": { 29 | "mockery/mockery": "^1.4", 30 | "orchestra/testbench": "^5.0|^6.0|^7.0", 31 | "phpunit/phpunit": "^8.5|^9.0" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Spatie\\NovaTranslatable\\": "src/" 36 | } 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Spatie\\NovaTranslatable\\Tests\\": "tests" 41 | } 42 | }, 43 | "config": { 44 | "sort-packages": true 45 | }, 46 | "minimum-stability": "dev", 47 | "prefer-stable": true, 48 | "scripts": { 49 | "test": "vendor/bin/phpunit" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 11 | "check-format": "prettier --list-different 'resources/**/*.{css,js,vue}'", 12 | "format": "prettier --write 'resources/js/**/*.{css,js,vue}'", 13 | "lint": "eslint resources/js --fix --ext js,vue" 14 | }, 15 | "devDependencies": { 16 | "cross-env": "^5.0.0", 17 | "eslint": "^4.19.1", 18 | "eslint-config-prettier": "^2.9.0", 19 | "eslint-plugin-vue": "^4.4.0", 20 | "laravel-mix": "^1.0", 21 | "laravel-nova": "^1.0", 22 | "prettier": "^1.14.2" 23 | 24 | }, 25 | "dependencies": { 26 | "animated-scroll-to": "^1.2.2", 27 | "vue": "^2.5.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidConfiguration.php: -------------------------------------------------------------------------------- 1 | locales = static::$defaultLocales; 70 | 71 | $this->originalFields = $fields; 72 | 73 | $this->displayLocalizedNameUsingCallback = self::$displayLocalizedNameByDefaultUsingCallback ?? function (Field $field, string $locale) { 74 | return ucfirst($field->name)." ({$locale})"; 75 | }; 76 | 77 | $this->createTranslatableFields(); 78 | } 79 | 80 | public static function defaultLocales(array $locales) 81 | { 82 | static::$defaultLocales = $locales; 83 | } 84 | 85 | public function locales(array $locales) 86 | { 87 | $this->locales = $locales; 88 | 89 | $this->createTranslatableFields(); 90 | 91 | return $this; 92 | } 93 | 94 | public function rules(array $rules) 95 | { 96 | $this->rules = $rules; 97 | 98 | $this->createTranslatableFields(); 99 | 100 | return $this; 101 | } 102 | 103 | public function creationRules(array $rules) 104 | { 105 | $this->creationRules = $rules; 106 | 107 | $this->createTranslatableFields(); 108 | 109 | return $this; 110 | } 111 | 112 | public function updateRules(array $rules) 113 | { 114 | $this->updateRules = $rules; 115 | 116 | $this->createTranslatableFields(); 117 | 118 | return $this; 119 | } 120 | 121 | public function rulesFor(string $field, string $locale, $rules) 122 | { 123 | $this->rules[$field][$locale] = $rules; 124 | 125 | $this->createTranslatableFields(); 126 | 127 | return $this; 128 | } 129 | 130 | public function creationRulesFor(string $field, string $locale, $rules) 131 | { 132 | $this->creationRules[$field][$locale] = $rules; 133 | 134 | $this->createTranslatableFields(); 135 | 136 | return $this; 137 | } 138 | 139 | public function updateRulesFor(string $field, string $locale, $rules) 140 | { 141 | $this->updateRules[$field][$locale] = $rules; 142 | 143 | $this->createTranslatableFields(); 144 | 145 | return $this; 146 | } 147 | 148 | public static function displayLocalizedNameByDefaultUsing(Closure $displayLocalizedNameByDefaultUsingCallback) 149 | { 150 | static::$displayLocalizedNameByDefaultUsingCallback = $displayLocalizedNameByDefaultUsingCallback; 151 | } 152 | 153 | public function displayLocalizedNameUsing(Closure $displayLocalizedNameUsingCallback) 154 | { 155 | $this->displayLocalizedNameUsingCallback = $displayLocalizedNameUsingCallback; 156 | 157 | $this->createTranslatableFields(); 158 | 159 | return $this; 160 | } 161 | 162 | protected function createTranslatableFields() 163 | { 164 | if ($this->onIndexPage()) { 165 | $this->data = $this->originalFields; 166 | 167 | return; 168 | } 169 | 170 | if ($this->isFieldAttachmentRequest(request())) { 171 | collect($this->locales) 172 | ->crossJoin($this->originalFields) 173 | ->eachSpread(function (string $locale, Field $field) { 174 | $translatedField = clone $field; 175 | $translatedField->attribute = 'translations_'.$translatedField->attribute.'_'.$locale; 176 | 177 | $this->data[] = $translatedField; 178 | $this->translatedFieldsByLocale[$locale][] = $translatedField; 179 | }); 180 | 181 | return; 182 | } 183 | 184 | $this->data = []; 185 | 186 | collect($this->locales) 187 | ->crossJoin($this->originalFields) 188 | ->eachSpread(function (string $locale, Field $field) { 189 | $translatedField = $this->createTranslatedField($field, $locale); 190 | 191 | $this->data[] = $translatedField; 192 | $this->translatedFieldsByLocale[$locale][] = $translatedField; 193 | }); 194 | } 195 | 196 | protected function createTranslatedField(Field $originalField, string $locale): Field 197 | { 198 | $translatedField = clone $originalField; 199 | 200 | $originalAttribute = $translatedField->attribute; 201 | 202 | $translatedField->attribute = 'translations'; 203 | 204 | $translatedField->name = (count($this->locales) > 1) 205 | ? ($this->displayLocalizedNameUsingCallback)($translatedField, $locale) 206 | : $translatedField->name; 207 | 208 | $translatedField 209 | ->resolveUsing(function ($value, Model $model) use ($translatedField, $locale, $originalAttribute) { 210 | $translatedField->attribute = 'translations_'.$originalAttribute.'_'.$locale; 211 | $translatedField->panel = $translatedField->panel ?? $this->panel; 212 | $translatedField->assignedPanel = $translatedField->assignedPanel ?? $this->assignedPanel; 213 | 214 | return $model->translations[$originalAttribute][$locale] ?? ''; 215 | }); 216 | 217 | $translatedField->fillUsing(function ($request, $model, $attribute, $requestAttribute) use ($locale, $originalAttribute) { 218 | $model->setTranslation($originalAttribute, $locale, $request->get($requestAttribute)); 219 | }); 220 | 221 | if (isset($this->rules[$originalAttribute][$locale])) { 222 | $translatedField->rules( 223 | is_string($this->rules[$originalAttribute][$locale]) 224 | ? explode('|', $this->rules[$originalAttribute][$locale]) 225 | : $this->rules[$originalAttribute][$locale] 226 | ); 227 | } 228 | if (isset($this->creationRules[$originalAttribute][$locale])) { 229 | $translatedField->creationRules( 230 | is_string($this->creationRules[$originalAttribute][$locale]) 231 | ? explode('|', $this->creationRules[$originalAttribute][$locale]) 232 | : $this->creationRules[$originalAttribute][$locale] 233 | ); 234 | } 235 | if (isset($this->updateRules[$originalAttribute][$locale])) { 236 | $translatedField->updateRules( 237 | is_string($this->updateRules[$originalAttribute][$locale]) 238 | ? explode('|', $this->updateRules[$originalAttribute][$locale]) 239 | : $this->updateRules[$originalAttribute][$locale] 240 | ); 241 | } 242 | 243 | return $translatedField; 244 | } 245 | 246 | protected function onIndexPage(): bool 247 | { 248 | if (! request()->route()) { 249 | return false; 250 | } 251 | 252 | $currentController = Str::before(request()->route()->getAction()['controller'] ?? '', '@'); 253 | 254 | return $currentController === ResourceIndexController::class; 255 | } 256 | 257 | protected function isFieldAttachmentRequest(Request $request): bool 258 | { 259 | if (! $request->route()) { 260 | return false; 261 | } 262 | 263 | $currentController = Str::before(request()->route()->getAction()['controller'] ?? '', '@'); 264 | 265 | return $currentController === FieldAttachmentController::class; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix') 2 | 3 | mix.js('resources/js/field.js', 'dist/js') 4 | .sass('resources/sass/field.scss', 'dist/css') 5 | .webpackConfig({ 6 | resolve: { 7 | symlinks: false 8 | } 9 | }) 10 | --------------------------------------------------------------------------------