Add a translation assistant to the panel

Each field's original sits beside the field to write, and a translation that
fell behind shows what the original said when it was translated and what it
says now, word by word.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 10:53:31 +02:00
parent 76d022053b
commit 6fc600e6a1
16 changed files with 837 additions and 61 deletions

View File

@@ -0,0 +1,71 @@
<x-filament-panels::page>
<style>
.ta-source { padding: .5rem .75rem; border-radius: .5rem; background: color-mix(in oklab, currentColor 5%, transparent); font-size: .875rem; line-height: 1.5; }
.ta-source p { margin: 0 0 .5rem; }
.ta-lang { display: block; font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; opacity: .6; margin-bottom: .25rem; }
.ta-diff { font-size: .875rem; line-height: 1.6; padding: .5rem .75rem; border-left: 3px solid #f59e0b; background: color-mix(in oklab, #f59e0b 8%, transparent); border-radius: .25rem; }
.ta-diff del { background: color-mix(in oklab, #dc2626 18%, transparent); text-decoration: line-through; }
.ta-diff ins { background: color-mix(in oklab, #16a34a 20%, transparent); text-decoration: none; }
.ta-table { width: 100%; border-collapse: collapse; font-size: .875rem; }
.ta-table th { text-align: left; font-size: .75rem; text-transform: uppercase; opacity: .7; padding: .5rem; }
.ta-table td { padding: .5rem; border-top: 1px solid color-mix(in oklab, currentColor 10%, transparent); vertical-align: top; }
.ta-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
</style>
@if ($this->target())
<form wire:submit="save" style="display: grid; gap: 1.5rem;">
{{ $this->form }}
<div>
<x-filament::button type="submit">
{{ __('panel.translate.save', ['language' => $this->languageName($this->locale)]) }}
</x-filament::button>
</div>
</form>
@else
@php($pending = $this->pending())
<x-filament::section :heading="__('panel.translate.pending')" :description="__('panel.translate.pending_hint')">
@if ($pending->isEmpty())
<p>{{ __('panel.translate.nothing') }}</p>
@else
<table class="ta-table">
<thead>
<tr>
<th scope="col">{{ __('panel.translate.columns.record') }}</th>
<th scope="col">{{ __('panel.translate.columns.languages') }}</th>
</tr>
</thead>
<tbody>
@foreach ($pending as $item)
<tr>
<td>
<x-filament::badge color="gray" size="sm" style="display: inline-flex">{{ __('panel.statistics.types.'.$item['type']) }}</x-filament::badge>
{{ $item['title'] }}
</td>
<td>
<div class="ta-actions">
@foreach ($this->targetLocales() as $locale)
@if (in_array($locale, $item['missing'], true) || array_key_exists($locale, $item['stale']))
<x-filament::button
size="xs"
:color="in_array($locale, $item['missing'], true) ? 'primary' : 'warning'"
tag="a"
:href="\App\Filament\Pages\TranslationAssistant::urlFor($item['record'], $locale)"
>
{{ in_array($locale, $item['missing'], true)
? __('panel.translate.translate_into', ['language' => $this->languageName($locale)])
: __('panel.translate.update_in', ['language' => $this->languageName($locale), 'since' => $item['stale'][$locale]->diffForHumans()]) }}
</x-filament::button>
@endif
@endforeach
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</x-filament::section>
@endif
</x-filament-panels::page>