Skip to content

Commit b0fdc90

Browse files
committed
fix nested content title translations, ensure locale is mounted when refresh page
1 parent 118b515 commit b0fdc90

File tree

4 files changed

+87
-54
lines changed

4 files changed

+87
-54
lines changed

src/Base/Filament/Concerns/ContentFormTrait.php

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,34 @@ public function updatedActiveLocale(string $newActiveLocale): void
155155

156156
$translatableAttributes = $this->getTranslatableAttributesForContent();
157157

158-
$this->otherLocaleData[$this->oldActiveLocale] = Arr::only($this->data, $translatableAttributes);
158+
// Handle nested title structure
159+
$dataToStore = [];
160+
foreach ($translatableAttributes as $attribute) {
161+
if ($attribute === 'title' && isset($this->data['title']) && is_array($this->data['title'])) {
162+
// Extract only the old locale's value from the nested title array
163+
$dataToStore['title'] = $this->data['title'][$this->oldActiveLocale] ?? '';
164+
} else {
165+
$dataToStore[$attribute] = $this->data[$attribute] ?? null;
166+
}
167+
}
168+
169+
$this->otherLocaleData[$this->oldActiveLocale] = $dataToStore;
170+
171+
// Prepare data for new locale
172+
$newLocaleData = $this->otherLocaleData[$this->activeLocale] ?? [];
173+
174+
// Handle nested title structure for new locale
175+
if (isset($this->data['title']) && is_array($this->data['title'])) {
176+
// If we have a stored value for the new locale, put it back in the array
177+
if (isset($newLocaleData['title'])) {
178+
$this->data['title'][$this->activeLocale] = $newLocaleData['title'];
179+
unset($newLocaleData['title']);
180+
}
181+
}
159182

160183
$this->data = $this->mutuateDataWhileUpdatedActiveLocale(
161184
Arr::except($this->data, $translatableAttributes),
162-
$this->otherLocaleData[$this->activeLocale] ?? []
185+
$newLocaleData
163186
);
164187

165188
unset($this->otherLocaleData[$this->activeLocale]);
@@ -174,15 +197,33 @@ protected function fillForm(): void
174197
$record = $this->getRecord();
175198
$translatableAttributes = static::getResource()::getTranslatableAttributes();
176199

200+
// Initialize title with all translations for the nested structure
201+
$allTitleTranslations = [];
202+
if (in_array('title', $translatableAttributes)) {
203+
foreach ($this->getTranslatableLocales() as $locale) {
204+
$allTitleTranslations[$locale] = $record->getTranslation('title', $locale, useFallbackLocale: false);
205+
}
206+
}
207+
177208
foreach ($this->getTranslatableLocales() as $locale) {
178209
$translatedData = [];
179210

180211
foreach ($translatableAttributes as $attribute) {
181-
$translatedData[$attribute] = $record->getTranslation($attribute, $locale, useFallbackLocale: false);
212+
if ($attribute === 'title') {
213+
// For title, use the complete translations array
214+
$translatedData[$attribute] = $allTitleTranslations;
215+
} else {
216+
$translatedData[$attribute] = $record->getTranslation($attribute, $locale, useFallbackLocale: false);
217+
}
182218
}
183219

184220
if ($locale !== $this->activeLocale) {
185-
$this->otherLocaleData[$locale] = $this->mutateFormDataBeforeFill($translatedData);
221+
// For otherLocaleData, store individual locale values (not the full array)
222+
$storedData = $translatedData;
223+
if (isset($storedData['title']) && is_array($storedData['title'])) {
224+
$storedData['title'] = $storedData['title'][$locale] ?? '';
225+
}
226+
$this->otherLocaleData[$locale] = $this->mutateFormDataBeforeFill($storedData);
186227

187228
continue;
188229
}
@@ -554,5 +595,6 @@ protected function publishDescendantsAndSelfAction()
554595
->color('gray')
555596
->action(fn (array $data, $action) => $this->publish($data, $action, true));
556597
}
598+
557599
// endregion Actions
558600
}

src/Base/Filament/Resources/Pages/BaseContentEditPage.php

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ public function booted(): void
5050
}
5151
}
5252

53+
public function mountTranslatable(): void
54+
{
55+
// Call trait implementation (if trait provides it)
56+
if (method_exists($this, 'traitMountTranslatable')) {
57+
$this->traitMountTranslatable();
58+
}
59+
// Ensure query string param takes precedence if present
60+
if ($locale = request()->query('activeLocale')) {
61+
$this->activeLocale = $locale;
62+
}
63+
}
64+
5365
protected function getHeaderActions(): array
5466
{
5567
return [
@@ -63,36 +75,36 @@ protected function getHeaderActions(): array
6375
ViewAction::make(),
6476

6577
DeleteAction::make()
66-
->visible(fn (Model $record) => ! $record->isLocked()),
78+
->visible(fn(Model $record) => ! $record->isLocked()),
6779

6880
RestoreAction::make(),
6981

7082
ForceDeleteAction::make(),
7183

7284
LockContentAction::make()
73-
->successRedirectUrl(fn ($record) => $this->getUrl(array_merge(['record' => $record], $this->getRedirectUrlParameters()))),
85+
->successRedirectUrl(fn($record) => $this->getUrl(array_merge(['record' => $record], $this->getRedirectUrlParameters()))),
7486

7587
UnlockContentAction::make()
76-
->successRedirectUrl(fn ($record) => $this->getUrl(array_merge(['record' => $record], $this->getRedirectUrlParameters()))),
88+
->successRedirectUrl(fn($record) => $this->getUrl(array_merge(['record' => $record], $this->getRedirectUrlParameters()))),
7789
])
7890
->dropdown(false)
79-
->hidden(fn (ActionGroup $action) => FilamentActionHelper::isAnyVisibleActionInActionGroup($action)),
91+
->hidden(fn(ActionGroup $action) => FilamentActionHelper::isAnyVisibleActionInActionGroup($action)),
8092

8193
ActionGroup::make([
8294
UpdateContentRouteAction::make(),
8395
ContentHistoryAction::make(),
8496
AdjustChildOrderAction::make()
85-
->nodeParentId(fn (Content | Model $record) => $record->nestable_tree_id ?? ($record->nestableTree?->getKey() ?? 0))
97+
->nodeParentId(fn(Content | Model $record) => $record->nestable_tree_id ?? ($record->nestableTree?->getKey() ?? 0))
8698
->hidden(
87-
fn (?Model $record) => ! $record instanceof Content ||
88-
$record->trashed()
99+
fn(?Model $record) => ! $record instanceof Content ||
100+
$record->trashed()
89101
)
90102
->successRedirectUrl(function ($record) {
91103
return $this->getUrl(['record' => $record, ...$this->getRedirectUrlParameters()]);
92104
}),
93105
])
94106
->dropdown(false)
95-
->hidden(fn (ActionGroup $action) => FilamentActionHelper::isAnyVisibleActionInActionGroup($action)),
107+
->hidden(fn(ActionGroup $action) => FilamentActionHelper::isAnyVisibleActionInActionGroup($action)),
96108
]),
97109
];
98110
}
@@ -132,7 +144,7 @@ protected function handleRecordUpdate(Model $record, array $data): Model
132144
$record->fill(Arr::except($data, $translatableAttributes));
133145

134146
$currentFieldsForType = $record instanceof Content
135-
? $record->documentType?->fieldGroups->whereInstanceOf(FieldGroup::class)->mapWithKeys(fn (FieldGroup $fg) => [$fg->name => $fg->fields->pluck('name')->all()])->all()
147+
? $record->documentType?->fieldGroups->whereInstanceOf(FieldGroup::class)->mapWithKeys(fn(FieldGroup $fg) => [$fg->name => $fg->fields->pluck('name')->all()])->all()
136148
: [];
137149
// Limit the propertyData to the current fields for the type
138150
$propertyData = Arr::only($data['propertyData'] ?? [], array_keys($currentFieldsForType));
@@ -151,14 +163,7 @@ protected function handleRecordUpdate(Model $record, array $data): Model
151163
$record->setTranslation('propertyData', '', $propertyData);
152164

153165
foreach (Arr::only($data, $translatableAttributes) as $key => $value) {
154-
// Handle nested locale arrays (e.g., title.en, title.fr from Group with statePath)
155-
if (is_array($value) && $key === 'title') {
156-
foreach ($value as $locale => $localizedValue) {
157-
$record->setTranslation($key, $locale, $localizedValue);
158-
}
159-
} else {
160-
$record->setTranslation($key, $this->activeLocale, $value);
161-
}
166+
$record->setTranslation($key, $this->activeLocale, $value);
162167
}
163168

164169
$originalData = $this->data;
@@ -167,7 +172,7 @@ protected function handleRecordUpdate(Model $record, array $data): Model
167172

168173
foreach ($this->otherLocaleData as $locale => $localeData) {
169174
$existingLocales ??= collect($translatableAttributes)
170-
->map(fn (string $attribute): array => array_keys($record->getTranslations($attribute)))
175+
->map(fn(string $attribute): array => array_keys($record->getTranslations($attribute)))
171176
->flatten()
172177
->unique()
173178
->all();
@@ -196,14 +201,7 @@ protected function handleRecordUpdate(Model $record, array $data): Model
196201
$localeData = $this->mutateFormDataBeforeSave($localeData);
197202

198203
foreach (Arr::only($localeData, $translatableAttributes) as $key => $value) {
199-
// Handle nested locale arrays for otherLocaleData as well
200-
if (is_array($value) && $key === 'title') {
201-
foreach ($value as $otherLoc => $localizedValue) {
202-
$record->setTranslation($key, $otherLoc, $localizedValue);
203-
}
204-
} else {
205-
$record->setTranslation($key, $locale, $value);
206-
}
204+
$record->setTranslation($key, $locale, $value);
207205
}
208206
}
209207

src/Base/Filament/Resources/Pages/CreateContentRecord/Concerns/Translatable.php

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,7 @@ protected function handleRecordCreation(array $data): Model
4343
$record->fill(Arr::except($data, $translatableAttributes));
4444

4545
foreach (Arr::only($data, $translatableAttributes) as $key => $value) {
46-
// Handle nested locale arrays (e.g., title.en, title.fr from Group with statePath)
47-
if (is_array($value) && $key === 'title') {
48-
foreach ($value as $locale => $localizedValue) {
49-
$record->setTranslation($key, $locale, $localizedValue);
50-
}
51-
} else {
52-
$record->setTranslation($key, $this->activeLocale, $value);
53-
}
46+
$record->setTranslation($key, $this->activeLocale, $value);
5447
}
5548

5649
$originalData = $this->data;
@@ -70,14 +63,7 @@ protected function handleRecordCreation(array $data): Model
7063
$localeData = $this->mutateFormDataBeforeCreate($localeData);
7164

7265
foreach (Arr::only($localeData, $translatableAttributes) as $key => $value) {
73-
// Handle nested locale arrays for otherLocaleData as well
74-
if (is_array($value) && $key === 'title') {
75-
foreach ($value as $otherLoc => $localizedValue) {
76-
$record->setTranslation($key, $otherLoc, $localizedValue);
77-
}
78-
} else {
79-
$record->setTranslation($key, $locale, $value);
80-
}
66+
$record->setTranslation($key, $locale, $value);
8167
}
8268
}
8369

src/Filament/Resources/Contents/Schemas/ContentForm.php

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,15 @@ protected static function getTitleFormComponent()
171171
foreach ($langs as $lang) {
172172

173173
$locale = $lang->code;
174-
174+
175175
$components[] =
176176
TextInput::make($locale)
177177
->label(__('inspirecms::resources/content.title.label'))
178178
->validationAttribute(__('inspirecms::resources/content.title.validation_attribute'))
179179
->placeholder(__('inspirecms::resources/content.title.placeholder'))
180180
->helperText(__('inspirecms::resources/content.title.instructions'))
181-
->live(true, 5000)->afterStateUpdated(function ($state, $get, $set, $operation, ContractsContentForm $livewire, $locale) {
181+
->live(true, 5000)
182+
->afterStateUpdated(function ($state, $get, $set, $operation, ContractsContentForm $livewire) use ($locale) {
182183
// Fill slug if empty / operation is create
183184
if ($operation === 'create' || empty($get('slug'))) {
184185
$set('slug', ContentSlugFactory::create()->generate($state));
@@ -188,7 +189,6 @@ protected static function getTitleFormComponent()
188189
->autofocus()
189190
->required()
190191
->limitLengthWithHint(60)
191-
->formatStateUsing(fn($record) => $record?->getTranslations('title')[$locale] ?? null)
192192
->visible(fn(ContractsContentForm $livewire) => $livewire->getActiveActionsLocale() == $locale)
193193
->translatable();
194194
}
@@ -198,13 +198,20 @@ protected static function getTitleFormComponent()
198198

199199
return Group::make()
200200
->statePath($key)
201-
->dehydrated()
202-
->saveRelationshipsUsing(function (Model $record, $state, ContractsContentForm $livewire) {
201+
->afterStateHydrated(function (Group $component, ?Model $record, $state) {
202+
if ($record) {
203+
// Load all translations into the group state
204+
$component->state($record->getTranslations('title'));
205+
}
206+
})
207+
->mutateDehydratedStateUsing(function ($state, ContractsContentForm $livewire) {
208+
// When dehydrating, only return the value for the active locale
209+
// This makes it compatible with the Translatable trait's handling
203210
if (is_array($state)) {
204-
foreach ($state as $locale => $value) {
205-
$record->setTranslation('title', $locale, $value);
206-
}
211+
$activeLocale = $livewire->getActiveActionsLocale();
212+
return $state[$activeLocale] ?? '';
207213
}
214+
return $state;
208215
})
209216
->schema($configureTranslatableComponents);
210217
}

0 commit comments

Comments
 (0)