Skip to content

Commit 47e0869

Browse files
committed
Improve language selection by synchronizing all buttons with the same language code
1 parent 4e574fc commit 47e0869

File tree

9 files changed

+173
-109
lines changed

9 files changed

+173
-109
lines changed

README.md

Lines changed: 105 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## DESCRIPTION
44
Adds the ability to insert translations in content using a language table.
5-
For example you can create a main model that stores the object id and the data that is not translatable, on the lang model you have to define the foreign key for the main object(in this case post_id) and the one for the language that has always to be "language_id".
5+
For example, you can create a main model that stores the object id and the data that is not translatable, on the lang model you have to define the foreign key for the main object(in this case post_id) and the one for the language that has always to be "language_id".
66
Below an example of model definition in YAML for blueprint package:
77
```yaml
88
Post:
@@ -20,7 +20,6 @@ Below an example of model definition in YAML for blueprint package:
2020
relationships:
2121
belongsTo: Language
2222
```
23-
2423
## INSTALLATION
2524
2625
Simply install using composer
@@ -54,95 +53,104 @@ class AdminPanelProvider extends PanelProvider
5453
}
5554
```
5655

57-
## MAIN MODEL
56+
## HOW TO USE IT
5857

59-
In the main model extend the FmtModel:
58+
### MAIN MODEL
59+
In the main model use the provided trait "HasTranslation":
6060

6161
```php
62-
use Unusualdope\FilamentModelTranslatable\Models\FmtModel;
62+
use Unusualdope\FilamentModelTranslatable\Traits\HasTranslation;
6363

64-
class Post extends FmtModel
64+
class Post extends Model
6565
{
66+
use HasTranslation;
67+
}
6668
//...
6769
```
68-
69-
Define some properties to make the plugin work, see the example with comments:
70+
The plugin assumes that the translatable model is named as the main model + "Language" and the foreign key is the main model name in CamelCase + "Language" (e.g. PostLanguage)
71+
```php
72+
protected string $lang_model = __CLASS__ . 'Language';
73+
```
74+
if you want to change the language model name you can do so overwriting the property in your main model
7075
```php
7176
/**
7277
* Translatable props needed
7378
*/
7479

75-
protected $lang_model = 'App\Models\PostLanguage'; //fqn of the translatable model
76-
protected $lang_foreign_key = 'post_id'; //foreign key
77-
78-
protected $is_translatable = true;
79-
protected $translatable = [
80-
'title' => [ //field name that will match with the LangModel db field and property
81-
'formType' => 'TextInput', //The type of form input field as in Filament
82-
'name' => 'Title', //Field Label
83-
'methods' => [ //The methods you want to call from filament on your field to define it
84-
'required' => '1',
85-
'prefix' => 'title',
86-
...
87-
'anotherMethod' => [
88-
'param1' => '1',
89-
'param2' => 'test'
90-
...
91-
'paramN' => 'xxx'
92-
]
93-
],
94-
],
95-
'content' => [
96-
'formType' => 'RichEditor',
97-
'name' => 'Content',
98-
'methods' => [
99-
'columnSpanFull' => '',
100-
],
101-
],
102-
];
80+
protected $lang_model = 'App\Models\PostTranslated'; //fqn of the translatable model
10381
```
82+
the plugin assumes that the foreign key is the standard laravel foreign key
83+
(eg: post_id), if you want to change it you can do so overwriting the property in your main model
84+
```php
85+
/**
86+
* Specify the foreign key if not the standard one
87+
*/
10488

105-
## RESOURCE
89+
protected $lang_foreign_key = 'post_ext_id';
90+
```
91+
if for any reason you want to stop/pause the translat-ability of your model
92+
you can set the property $is_translatable to false
93+
```php
94+
/**
95+
* Set to false in order to disable the translatable feature
96+
*/
10697

107-
In the RESOURCE you have to use the Trait fmtTrait and retrieve the translatable fields with
98+
protected bool $is_translatable = false;
99+
```
100+
On the main model you have to define the fields that will be translatable using standard Filament fields
101+
as you would do in a resource, specify them in method setTranslatableFilamentFields(), the make() method
102+
has to contain the field names that are present in the database on the <Model>Language table
108103

109104
```php
110-
self::addTranslatableFieldsToSchema(array $schema, Form $form, Bool false);
111-
```
105+
use Filament\Forms\Components\Textarea;
106+
use Filament\Forms\Components\TextInput;
107+
108+
public function setTranslatableFilamentFields()
109+
{
110+
return [
111+
TextInput::make('name')
112+
->required()
113+
->label('Name'),
114+
TextInput::make('link_rewrite')
115+
->maxLength(128)
116+
->label('Link Rewrite'),
117+
TextInput::make('meta_title')
118+
->maxLength(128)
119+
->label('Meta Title'),
120+
Textarea::make('meta_description')
121+
->maxLength(512)
122+
->label('Meta Description'),
123+
//...
124+
];
125+
}
126+
```
112127

113-
1 - As first parameter you can pass the current schema and it will give you back the full schema with the translatable fields appended at the end.
128+
### RESOURCE
114129

115-
2 - the Form object
130+
In the RESOURCE when defining the form insert the translatable fields where you want
131+
by using the method addTranslatableFieldsToSchema() and passing as parameter the field name
132+
exactly as defined in the database and in the main model
116133

117-
3 - If you want back only the array containing the schema of the translatable fields (to allow you to place it in the middle of your schema) set this to false (default is true)
118-
Below is just an example:
119134

120135
```php
121-
class PostResource extends Resource
122-
{
123-
use FmtModelTrait;
124-
125-
protected static ?string $model = Post::class;
126-
127-
protected static ?string $navigationIcon = 'heroicon-o-document-duplicate';
128-
129136
public static function form(Form $form): Form
130137
{
131-
132-
$schema = [
133-
Forms\Components\Select::make('user_id')
134-
->relationship('user', 'name')
135-
->searchable()
136-
->required(),
137-
Forms\Components\Select::make('post_status_id')
138-
->relationship('postStatus', 'name')
139-
->required(),
140-
];
141-
142-
$schema = self::addTranslatableFieldsToSchema($schema, $form);
143-
144138
return $form
145-
->schema($schema);
139+
->schema([
140+
//translatable
141+
FeatureGroup::addTranslatableFieldsToSchema('name'),
142+
//not translatable
143+
Forms\Components\TextInput::make('position')
144+
->required()
145+
->numeric()
146+
->hidden()
147+
->default(0),
148+
//translatable
149+
FeatureGroup::addTranslatableFieldsToSchema('tooltip'),
150+
151+
//..
152+
153+
]);
146154
}
147155
```
148156

@@ -151,6 +159,11 @@ On the CREATE page extend
151159

152160
```php
153161
Unusualdope\FilamentModelTranslatable\Filament\Resources\Pages\FmtCreateRecord
162+
163+
class CreatePost extends FmtCreateRecord
164+
{
165+
//..
166+
}
154167
```
155168

156169
instead of the standard
@@ -159,26 +172,41 @@ instead of the standard
159172
On the EDIT page extend
160173
```php
161174
Unusualdope\FilamentModelTranslatable\Filament\Resources\Pages\FmtEditRecord
162-
```
163-
instead of the standard ~~`Filament\Resources\Pages\EditRecord`~~
164-
165-
e.g.:
166-
167-
```php
168-
use Unusualdope\FilamentModelTranslatable\Filament\Resources\Pages\FmtCreateRecord;
169175

170-
class CreatePlan extends FmtCreateRecord
176+
class EditPost extends FmtEditRecord
171177
{
172-
protected static string $resource = PlanResource::class;
178+
//..
173179
}
174180
```
181+
instead of the standard ~~`Filament\Resources\Pages\EditRecord`~~
182+
175183

176184

177185
## RESULT
178186
You will get a tab that let you change language and fill the content for every language:
179187

180-
![Fmt Preview Image](https://unusualdope.com/external/images/fmt/fmtPreview01.png)
188+
![Fmt Preview Image 1](https://unusualdope.com/fmtImages/fmt_preview01.png)
189+
![Fmt Preview Image 2](https://unusualdope.com/fmtImages/fmt_preview02.png)
190+
191+
## DATA RETRIEVAL
192+
The trait HasTranslation provides a method to retrieve the translated data for the current language
193+
by using the defined HasOne relationship "currentLanguage", if you want to retrieve the post name in the
194+
current language in frontend you can do so by using the following code:
195+
196+
```php
197+
$post = Post::find(1);
198+
$post->currentLanguage->name;
199+
```
200+
201+
if you need to access all the data for all the languages
202+
you can use the HasMany relationship "languageData", you can do so by using the following code:
203+
204+
```php
205+
$post = Post::find(1);
206+
$post->languageData;
207+
```
181208

182209
## ISSUES OR SUGGESTIONS
183210

184-
Please feel free to give any suggestions for improvements or report any issue directly on the github [plugin repository](https://github.com/geimsdin/filament-model-translatable)
211+
Please feel free to give any suggestions for improvements or
212+
report any issue directly on the gitHub [plugin repository](https://github.com/geimsdin/filament-model-translatable)

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "unusualdope/filament-model-translatable",
33
"type": "library",
44
"license": "MIT",
5-
"version": "2.0.4",
5+
"version": "2.1.0",
66
"autoload": {
77
"psr-4": {
88
"Unusualdope\\FilamentModelTranslatable\\": "src"

resources/js/lang-switcher.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
document.addEventListener('DOMContentLoaded', function() {
2+
// Function to extract ISO code from a tab identifier like "-en-tab"
3+
function extractIsoCode(tabId) {
4+
const match = tabId.match(/-([a-z]{2})-tab/);
5+
return match ? match[1] : null;
6+
}
7+
8+
// Create a global language selection tracking object
9+
window.languageSelectionCoordinator = {
10+
// Method to synchronize all buttons for a given language
11+
synchronizeLanguage: function(isoCode) {
12+
// Find all buttons that set tab to the language code
13+
const allLangButtons = document.querySelectorAll(`button[x-on\\:click*="tab = '-${isoCode}-tab'"]`);
14+
15+
// Click each button to ensure related content is displayed
16+
allLangButtons.forEach(button => {
17+
// Skip clicking the button that initiated the change to prevent loops
18+
if (!button.dataset.triggeredByCoordinator) {
19+
button.dataset.triggeredByCoordinator = 'true';
20+
button.click();
21+
setTimeout(() => {
22+
delete button.dataset.triggeredByCoordinator;
23+
}, 100);
24+
}
25+
});
26+
}
27+
};
28+
29+
// Find all language buttons
30+
const languageButtons = document.querySelectorAll('button[x-on\\:click*="-tab"]');
31+
32+
// Attach click listeners to all language buttons
33+
languageButtons.forEach(button => {
34+
button.addEventListener('click', function(event) {
35+
// Only proceed if this wasn't triggered by our coordinator
36+
if (button.dataset.triggeredByCoordinator === 'true') {
37+
return;
38+
}
39+
40+
// Extract the ISO code from the x-on:click attribute
41+
const clickAttr = button.getAttribute('x-on:click');
42+
if (!clickAttr) return;
43+
44+
const tabMatch = clickAttr.match(/tab = ['"](-([a-z]{2})-tab)['"]/);
45+
if (!tabMatch) return;
46+
47+
const isoCode = tabMatch[2];
48+
49+
// Synchronize all buttons for this language
50+
window.languageSelectionCoordinator.synchronizeLanguage(isoCode);
51+
}, { capture: true }); // Use capture to run before Alpine's handlers
52+
});
53+
});

resources/views/components/tab-click-handler.blade.php

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Commands/Install.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@ public function handle()
6363

6464
}
6565
}
66+
if ($this->confirm("For FMTLang plugin to work properly you need to publish the assets, would you like to proceed?",true)){
67+
$this->call('filament:assets');
68+
}
6669

6770
$this->line('All Done, enjoy your translatable content!');
68-
if ($this->confirm('All done! Would you like to show some love by starring our plugin on GitHub?', true)) {
71+
if ($this->confirm('Would you like to show some love by starring our plugin on GitHub?', true)) {
6972
if (PHP_OS_FAMILY === 'Darwin') {
7073
exec('open https://github.com/geimsdin/filament-model-translatable');
7174
}

src/Filament/Resources/Pages/FmtCreateRecord.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,4 @@ protected function afterCreate(): void
4141
FmtHelper::saveWithLang( $this->record, $this->translatable_data, false);
4242
}
4343

44-
protected function getRenderHook(): string
45-
{
46-
return 'filament-model-translatable::components.tab-click-handler';
47-
}
48-
4944
}

src/Filament/Resources/Pages/FmtEditRecord.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,4 @@ protected function afterSave()
6969
FmtHelper::saveWithLang( $this->record, $this->translatable_data, true);
7070
}
7171

72-
protected function getRenderHook(): string
73-
{
74-
return 'filament-model-translatable::components.tab-click-handler';
75-
}
7672
}

src/FmtServiceProvider.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Unusualdope\FilamentModelTranslatable;
44

5+
use Filament\Facades\Filament;
6+
use Filament\Support\Assets\Js;
7+
use Filament\Support\Facades\FilamentAsset;
58
use Spatie\LaravelPackageTools\Package;
69
use Spatie\LaravelPackageTools\PackageServiceProvider;
710
use Unusualdope\FilamentModelTranslatable\Commands\Install;
@@ -26,6 +29,12 @@ public function boot()
2629
// Ensure views are correctly loaded
2730
$this->loadViewsFrom(__DIR__.'/../resources/views', 'filament-model-translatable');
2831

32+
FilamentAsset::register(
33+
[
34+
Js::make('lang-switcher-js', __DIR__ . '/../resources/js/lang-switcher.js')
35+
],
36+
package: 'unusualdope/filament-model-translatable');
37+
2938
return $this;
3039
}
3140

src/Traits/HasTranslation.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static function addTranslatableFieldsToSchema($field_name = null, $schema
4444
foreach ($languages as $lang_id => $lang_iso_code) {
4545
$schema_tab = $object->getTranslatableFilamentFields( $field_name )['schema_' . $lang_id];
4646

47-
$lang_tab = Tabs\Tab::make(strtoupper($lang_iso_code))->extraAttributes(['class' => 'fmt_tab_lang_' . $lang_id])
47+
$lang_tab = Tabs\Tab::make(strtoupper($lang_iso_code))->extraAttributes(['class' => 'fmt_tab_lang_' . $lang_iso_code])
4848
->schema(
4949
$schema_tab
5050
);

0 commit comments

Comments
 (0)