Translate pages, areas, menus, forms and posts field by field instead of rebuilding them
A site can have further languages (Settings → Languages). A page is built once; each language adds only its texts, keyed by the stable block IDs, plus its own address under /en/… (ADR 111, document schema v27, migration 20261009000100 for page_translation). - Editor: DE | EN switch, a list of all texts with original, state (missing, translated, original changed) and filter; structure stays with the main language. Undo, drafts, publishing and revisions cover all languages at once. - Website: /en and translated slugs, lang, canonical, hreflang with x-default, og:locale, sitemap; links to translated pages follow the language; a language switch block. - Header, footer and linked sections translate the same way; menu entries carry labels per language; fixed template texts come from a small dictionary. - Forms: labels, help, options, button and success message per language; messages and the step script speak the language, the submission and the email stay in the main language. - Posts, archives, category names, consent text and the 404 page follow the language. - Single-language sites see none of it and never touch the new table. The forms administration becomes an overview with one row per form and its own edit page; fields are one line each with details collapsed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c7705b7083
commit
e15b2517b1
51 files changed
+3045
-219
No files matched your search
@@ -3,6 +3,7 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Content\ButtonDesign;
|
||||
use App\Content\Languages;
|
||||
use App\Content\MenuButton;
|
||||
use App\Content\MenuRepository;
|
||||
use App\Content\PageRepository;
|
||||
@@ -17,7 +18,7 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class MenuController extends AbstractController
|
||||
{
|
||||
public function __construct(private MenuRepository $menus, private PageRepository $pages, private Theme $theme)
|
||||
public function __construct(private MenuRepository $menus, private PageRepository $pages, private Theme $theme, private Languages $languages)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -85,6 +86,7 @@ final class MenuController extends AbstractController
|
||||
'slots' => MenuRepository::SLOTS, 'slot' => $slot, 'slotName' => MenuRepository::SLOTS[$slot],
|
||||
'menu' => $menu, 'rows' => $rows,
|
||||
'menuIcons' => \App\Content\DocumentValidator::ICONS,
|
||||
'languages' => array_map(fn (string $code): array => $this->languages->describe($code), $this->languages->extra()),
|
||||
// Fuer die Button-Vorschau und die Farbwahl am Eintrag: dieselben Daten wie im Editor.
|
||||
'buttonSchema' => ['buttons' => $theme['buttons'], 'colors' => $theme['colors'], 'fonts' => $theme['fonts'], 'buttonOptions' => ButtonDesign::OPTIONS, 'mobile' => MenuButton::MOBILE],
|
||||
]);
|
||||
@@ -130,6 +132,7 @@ final class MenuController extends AbstractController
|
||||
'newTab' => $item['newTab'] ?? false,
|
||||
'icon' => $item['icon'] ?? '', 'iconPosition' => $item['iconPosition'] ?? 'before',
|
||||
'button' => $item['button'] ?? null,
|
||||
'labels' => $item['labels'] ?? [],
|
||||
];
|
||||
array_push($rows, ...$this->flatten($item['children'] ?? [], $level + 1));
|
||||
}
|
||||
@@ -160,6 +163,11 @@ final class MenuController extends AbstractController
|
||||
'level' => max(1, min(MenuRepository::MAX_DEPTH, (int) ($row['level'] ?? 1))),
|
||||
'position' => (int) ($row['position'] ?? 0),
|
||||
'button' => MenuButton::fromForm($row),
|
||||
// Je weitere Sprache ein Feld label_<sprache>; leer heißt: wie in der Hauptsprache.
|
||||
'labels' => array_filter(
|
||||
array_combine($this->languages->extra(), array_map(static fn (string $code): string => mb_substr(trim((string) ($row['label_'.$code] ?? '')), 0, 80), $this->languages->extra())) ?: [],
|
||||
static fn (string $text): bool => '' !== $text,
|
||||
),
|
||||
];
|
||||
}
|
||||
usort($flat, static fn (array $a, array $b): int => $a['position'] <=> $b['position']);
|
||||
@@ -177,6 +185,9 @@ final class MenuController extends AbstractController
|
||||
if (null !== $row['button']) {
|
||||
$item['button'] = $row['button'];
|
||||
}
|
||||
if ([] !== $row['labels']) {
|
||||
$item['labels'] = $row['labels'];
|
||||
}
|
||||
if ('url' === $row['type']) {
|
||||
$item['url'] = $row['url'];
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user