Update auf '.$e($fassung).' wird abgeschlossen …
'
+ .'Die neuen Dateien sind da. Jetzt laufen die Migrationen, danach geht es von selbst zur Systemseite.
'
+ .'Weiter, falls nichts passiert
';
+ exit;
+ }
+
#[Route('/%kant.admin_path%/system/update', name: 'admin_system_update', methods: ['POST'])]
public function update(Request $request): Response
{
diff --git a/src/Ops/ArchiveUpdate.php b/src/Ops/ArchiveUpdate.php
index f0bd126..dc26bd3 100644
--- a/src/Ops/ArchiveUpdate.php
+++ b/src/Ops/ArchiveUpdate.php
@@ -256,23 +256,28 @@ final class ArchiveUpdate
// Speicher - Klassen, die PHP schon geladen hat, laedt es nicht neu. Die Migrationen
// gehoeren deshalb in eine eigene Anfrage, die mit der neuen Fassung startet. Der
// Wartungszustand bleibt so lange an.
+ // Ein Einmalschlüssel für den Abschluss: Die Seite, die diese Anfrage noch ausgibt, ruft
+ // damit den zweiten Schritt selbst auf - ohne Knopf, und ohne dass eine fremde Seite ihn
+ // auslösen könnte (dazu braucht es zusätzlich eine Anmeldung als Administrator).
+ $token = bin2hex(random_bytes(16));
@file_put_contents($this->root.'/'.self::MARKE, json_encode([
'fassung' => $ziel,
'seit' => gmdate('c'),
'alt' => basename($arbeit),
+ 'token' => $token,
], JSON_UNESCAPED_SLASHES));
$melden($schritte, 'Dateien sind ersetzt', true, sprintf(
'Fassung %s liegt bereit. Jetzt fehlen noch die Migrationen - sie laufen im nächsten Schritt mit dem neuen Code.',
$ziel,
));
- return ['ok' => true, 'steps' => $schritte, 'migrate' => true];
+ return ['ok' => true, 'steps' => $schritte, 'migrate' => true, 'token' => $token, 'fassung' => $ziel];
}
/**
* Steht ein zweiter Schritt aus? Gibt Fassung und Zeitpunkt zurück, sonst null.
*
- * @return array{fassung: string, seit: string, alt: string}|null
+ * @return array{fassung: string, seit: string, alt: string, token?: string}|null
*/
public function pending(): ?array
{
diff --git a/src/Twig/LanguageExtension.php b/src/Twig/LanguageExtension.php
index d4c2331..acfe0cb 100644
--- a/src/Twig/LanguageExtension.php
+++ b/src/Twig/LanguageExtension.php
@@ -49,6 +49,7 @@ final class LanguageExtension extends AbstractExtension
'Navigation' => 'Navigation',
'Nach oben' => 'Back to top',
'Sprache' => 'Language',
+ 'Sprache wählen' => 'Choose language',
// Formulare
'Dieses Formular ist nicht mehr vorhanden.' => 'This form is no longer available.',
'Bitte prüfe 1 Eingabe. Die betroffenen Felder sind unten gekennzeichnet.' => 'Please check 1 entry. The field concerned is marked below.',
@@ -105,6 +106,7 @@ final class LanguageExtension extends AbstractExtension
'Alle akzeptieren' => 'Tout accepter',
'Nur notwendige' => 'Uniquement nécessaires',
'Sprache' => 'Langue',
+ 'Sprache wählen' => 'Choisir la langue',
],
'tr' => [
'Zum Inhalt springen' => 'İçeriğe geç',
@@ -118,6 +120,67 @@ final class LanguageExtension extends AbstractExtension
'Alle akzeptieren' => 'Tümünü kabul et',
'Nur notwendige' => 'Yalnızca gerekli',
'Sprache' => 'Dil',
+ 'Sprache wählen' => 'Dil seçin',
+ // Vollständig, damit eine türkische Seite nirgends auf Englisch ausweicht (09.10.2026).
+ 'Brotkrumen' => 'Sayfa yolu',
+ 'Soziale Profile' => 'Sosyal medya',
+ 'Zum Blättern seitwärts scrollen' => 'Gezinmek için yana kaydırın',
+ 'Anbieter:' => 'Sağlayıcı:',
+ 'Inhalt laden und einwilligen' => 'İçeriği yükle ve onayla',
+ 'Einwilligung ändern' => 'Onayı değiştir',
+ 'Bildergalerie' => 'Resim galerisi',
+ 'Bild' => 'Resim',
+ 'vergrößern' => 'büyüt',
+ 'Ansehen' => 'İncele',
+ 'Weitere Beiträge' => 'Diğer yazılar',
+ 'Vorheriger Beitrag' => 'Önceki yazı',
+ 'Nächster Beitrag' => 'Sonraki yazı',
+ 'Einzeln wählen' => 'Tek tek seç',
+ 'Auswahl speichern' => 'Seçimi kaydet',
+ 'Zweite Navigation' => 'İkinci menü',
+ 'Fußzeile' => 'Alt bilgi',
+ 'Rechtliches' => 'Yasal bilgiler',
+ 'Navigation' => 'Menü',
+ 'Dieses Formular ist nicht mehr vorhanden.' => 'Bu form artık mevcut değil.',
+ 'Bitte prüfe 1 Eingabe. Die betroffenen Felder sind unten gekennzeichnet.' => 'Lütfen 1 girişi kontrol edin. İlgili alan aşağıda işaretlenmiştir.',
+ 'Bitte prüfe %d Eingaben. Die betroffenen Felder sind unten gekennzeichnet.' => 'Lütfen %d girişi kontrol edin. İlgili alanlar aşağıda işaretlenmiştir.',
+ 'Pflichtfeld' => 'zorunlu alan',
+ 'in' => '',
+ 'bitte wählen' => 'lütfen seçin',
+ 'Zum Absenden dieses Formulars wird JavaScript benötigt. Schreib uns sonst gern direkt eine E-Mail.' => 'Bu formu göndermek için JavaScript gereklidir. Dilerseniz bize doğrudan e-posta gönderebilirsiniz.',
+ 'Zusammenfassung' => 'Özet',
+ 'Bitte prüfen Sie Ihre Angaben. Über „Ändern“ kommen Sie zum jeweiligen Schritt zurück.' => 'Lütfen bilgilerinizi kontrol edin. „Değiştir“ ile ilgili adıma geri dönebilirsiniz.',
+ 'Schritte des Formulars' => 'Form adımları',
+ 'Schritt' => 'Adım',
+ 'Zurück' => 'Geri',
+ 'Weiter' => 'İleri',
+ 'Ändern' => 'Değiştir',
+ 'Ja' => 'Evet',
+ 'Bitte wähle mindestens eine Option.' => 'Lütfen en az bir seçenek seçin.',
+ 'Absenden' => 'Gönder',
+ 'Vielen Dank. Deine Nachricht ist angekommen.' => 'Teşekkürler. Mesajınız bize ulaştı.',
+ 'Beiträge' => 'Yazılar',
+ 'Beitrag' => 'yazı',
+ 'Kategorie' => 'Kategori',
+ 'Schlagwort' => 'Etiket',
+ 'Alle Beiträge, die neuesten zuerst.' => 'Tüm yazılar, en yenisi önce.',
+ 'Beiträge in der Kategorie „%s“.' => '„%s“ kategorisindeki yazılar.',
+ 'Beiträge zum Schlagwort „%s“.' => '„%s“ etiketli yazılar.',
+ 'von' => 'yazan:',
+ '← Neuere' => '← Daha yeni',
+ 'Ältere →' => 'Daha eski →',
+ 'Seite %d von %d' => 'Sayfa %d / %d',
+ 'Externe Inhalte und Einwilligung' => 'Harici içerikler ve onay',
+ 'Diese Website lädt bestimmte Inhalte erst, wenn du zustimmst. Ohne Zustimmung wird die Seite vollständig angezeigt, nur eingebettete Inhalte anderer Anbieter bleiben leer.' => 'Bu web sitesi bazı içerikleri ancak onayınızdan sonra yükler. Onay vermeseniz de sayfa eksiksiz görüntülenir; yalnızca diğer sağlayıcıların yerleştirilmiş içerikleri boş kalır.',
+ 'Statistik' => 'İstatistik',
+ 'Externe Inhalte' => 'Harici içerikler',
+ 'Messung, wie die Website benutzt wird.' => 'Web sitesinin nasıl kullanıldığının ölçülmesi.',
+ 'Inhalte von anderen Anbietern, etwa Karten, Videos, Bewertungen oder ein Chat. Sie sehen die Adresse dieser Seite und deine IP-Adresse, sobald sie geladen werden.' => 'Harita, video, değerlendirme veya sohbet gibi diğer sağlayıcıların içerikleri. Yüklendiklerinde bu sayfanın adresini ve IP adresinizi görürler.',
+ 'Seite nicht gefunden' => 'Sayfa bulunamadı',
+ 'Diese Seite ist nicht mehr verfügbar.' => 'Bu sayfa artık mevcut değil.',
+ 'Die gesuchte Seite ist nicht verfügbar. Über die Startseite findest du wieder zum richtigen Inhalt.' => 'Aradığınız sayfa mevcut değil. Ana sayfadan doğru içeriğe ulaşabilirsiniz.',
+ 'Die Adresse ist möglicherweise veraltet oder wurde falsch eingegeben. Über die Startseite findest du wieder zum richtigen Inhalt.' => 'Adres eskimiş veya yanlış yazılmış olabilir. Ana sayfadan doğru içeriğe ulaşabilirsiniz.',
+ 'Zur Startseite' => 'Ana sayfaya',
],
];
diff --git a/templates/blocks/block.html.twig b/templates/blocks/block.html.twig
index 6a5676b..689ddc7 100644
--- a/templates/blocks/block.html.twig
+++ b/templates/blocks/block.html.twig
@@ -305,7 +305,7 @@
{% set sprachen = app.request.attributes.get('kant_alternates')|default([]) %}
{% if editing|default(false) and sprachen|length < 2 %}{% set sprachen = [{locale: 'de', native: 'Deutsch', href: '#', current: true}, {locale: 'en', native: 'English', href: '#', current: false}] %}{% endif %}
{% if sprachen|length > 1 %}
-