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
@@ -95,7 +95,11 @@ final class MenuRepository
|
||||
*/
|
||||
private ?array $pages = null;
|
||||
|
||||
public function resolve(array $items, string $currentPath, string $locale = 'de'): array
|
||||
/**
|
||||
* @param string|null $language eine weitere Sprache (ADR 111): Einträge zeigen dann ihre
|
||||
* Beschriftung in dieser Sprache, sofern sie eine haben
|
||||
*/
|
||||
public function resolve(array $items, string $currentPath, string $locale = 'de', ?string $language = null): array
|
||||
{
|
||||
if (null === $this->pages) {
|
||||
$this->pages = [];
|
||||
@@ -104,15 +108,16 @@ final class MenuRepository
|
||||
}
|
||||
}
|
||||
|
||||
return $this->resolveLevel($items, $this->pages, $currentPath, $this->settings->homePath());
|
||||
return $this->resolveLevel($items, $this->pages, $currentPath, $this->settings->homePath(), $language);
|
||||
}
|
||||
|
||||
private function resolveLevel(array $items, array $pages, string $currentPath, string $homePath): array
|
||||
private function resolveLevel(array $items, array $pages, string $currentPath, string $homePath, ?string $language = null): array
|
||||
{
|
||||
$links = [];
|
||||
foreach ($items as $item) {
|
||||
$children = $this->resolveLevel($item['children'] ?? [], $pages, $currentPath, $homePath);
|
||||
$label = $item['label'] ?? '';
|
||||
$children = $this->resolveLevel($item['children'] ?? [], $pages, $currentPath, $homePath, $language);
|
||||
$translated = null === $language ? '' : trim((string) ($item['labels'][$language] ?? ''));
|
||||
$label = '' !== $translated ? $translated : ($item['label'] ?? '');
|
||||
if ('page' === $item['type']) {
|
||||
$page = $pages[$item['pageId']] ?? null;
|
||||
if (null === $page || null === $page['published_revision_id']) {
|
||||
@@ -159,6 +164,18 @@ final class MenuRepository
|
||||
if (!is_array($item) || !is_string($item['label'] ?? null) || '' === trim($item['label']) || mb_strlen($item['label']) > 80) {
|
||||
throw new InvalidMenu('Jeder Eintrag braucht eine Beschriftung mit höchstens 80 Zeichen.');
|
||||
}
|
||||
// Beschriftungen in weiteren Sprachen (ADR 111): je Sprache ein Text, wie die
|
||||
// Beschriftung höchstens 80 Zeichen. Eine leere zeigt die Beschriftung der Hauptsprache.
|
||||
if (array_key_exists('labels', $item)) {
|
||||
if (!is_array($item['labels']) || ([] !== $item['labels'] && array_is_list($item['labels']))) {
|
||||
throw new InvalidMenu('Die übersetzten Beschriftungen sind ungültig.');
|
||||
}
|
||||
foreach ($item['labels'] as $code => $text) {
|
||||
if (!is_string($code) || !isset(Languages::CATALOG[$code]) || !is_string($text) || '' === trim($text) || mb_strlen($text) > 80) {
|
||||
throw new InvalidMenu('Eine übersetzte Beschriftung hat höchstens 80 Zeichen und gehört zu einer bekannten Sprache.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (array_key_exists('newTab', $item) && !is_bool($item['newTab'])) {
|
||||
throw new InvalidMenu('In neuem Tab öffnen ist an oder aus.');
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user