Files
KantSites/scripts/translate-kantarci-reisen.php
kantarciandClaude Opus 5.5 47292c7266 Finish an archive update in one go and translate Kantarci Reisen into Turkish
The request that swaps the files now ends with a plain page instead of running on through the
framework with old code in memory and new code on disk - that is what answered with a 500 after
a successful update. The page calls the second step itself with a one-time key: migrations,
clean-up, maintenance off, back to the system screen (ADR 112).

Turkish is complete in the fixed template texts and form messages. Two language switches on one
page get distinct landmark names. Kantarci Reisen gets a Turkish version of every page, the
header, footer, menu and enquiry form, with a DE · TR switch; the reset script applies it.
The DM Sans 600 files are needed after all and are committed with fonts.css.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:36:25 +02:00

382 lines
26 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*
* Kantarci Reisen auf Türkisch (ADR 111).
*
* Schaltet Türkisch als weitere Sprache ein und trägt die Übersetzung jeder Seite, des Kopf- und
* Fußbereichs, des Menüs und des Anfrageformulars ein; in den Kopfbereich kommt die Sprachwahl
* DE · TR. Die Seiten werden mit ihrer Übersetzung veröffentlicht. Läuft beliebig oft: jeder Lauf
* setzt die Übersetzungen auf den Stand dieser Datei.
*
* Aufruf: php scripts/translate-kantarci-reisen.php [Datenbankdatei]
* Ohne Argument: var/kantarci-reisen.db. reset-kantarci-reisen.sh ruft es nach dem Aufbau auf.
*
* Anrede „siz“: im Türkischen für ein Reisebüro üblicher als das „du“ der deutschen Fassung.
* Impressum und Datenschutz sagen, dass die deutsche Fassung maßgeblich ist.
*/
require dirname(__DIR__).'/vendor/autoload.php';
use App\Content\DocumentValidator;
use App\Content\FormRepository;
use App\Content\Languages;
use App\Content\MediaLibrary;
use App\Content\MenuRepository;
use App\Content\PageRepository;
use App\Content\PartialRepository;
use App\Content\SiteSettings;
use App\Content\Translations;
use App\Infrastructure\ConnectionFactory;
$root = dirname(__DIR__);
$path = $argv[1] ?? $root.'/var/kantarci-reisen.db';
if (!is_file($path)) {
fwrite(STDERR, "Keine Datenbank unter {$path}.\n");
exit(1);
}
$db = ConnectionFactory::create('sqlite:///'.str_replace('\\', '/', $path));
$settings = new SiteSettings($db, new MediaLibrary($db, $root.'/var/kantarci-reisen-media'));
$validator = new DocumentValidator();
$pages = new PageRepository($db, $validator, $settings);
$partials = new PartialRepository($db, $validator);
$menus = new MenuRepository($db, $settings);
$forms = new FormRepository($db);
$languages = new Languages($db, $settings);
const SPRACHE = 'tr';
$hinweisRecht = '<em>Bu çeviri bilgilendirme amaçlıdır; hukuken bağlayıcı olan Almanca metindir.</em>';
// ---------------------------------------------------------------------------------------------
// Seiten: Adresse, Titel, Beschreibung, Suchtitel und die Texte je Block
// ---------------------------------------------------------------------------------------------
$seiten = [
'home' => [
'title' => 'Başka bir yer için zaman.',
'description' => 'Kalbimizde Türkiye. Gözümüz dünyada. Baden-Baden’de kişisel seyahat danışmanlığı: Türkiye tatili, dünya genelinde oteller ve Türkiye uçuşları.',
'seoTitle' => 'Kantarci Reisen – Türkiye tatili, oteller ve uçuşlar | Baden-Baden seyahat acentesi',
'blocks' => [
'hero-klein.text' => 'Kalbimizde Türkiye. Gözümüz dünyada.',
'hero-titel.text' => 'Başka bir yer<br>için <em>zaman.</em>',
'hero-satz.text' => 'Tende tuz. Yüzde güneş.<br>Ve size uygun bir seyahat.',
'hero-knopf.text' => 'Tatilinizi planlayın',
'hero-unten-links.text' => 'Kişisel danışmanlık.<br>Rahat seyahat.',
'hero-unten-rechts.text' => 'Baden-Baden · Oos',
'hero-foto.alt' => 'Güneşli bir plaj terasıyla turkuaz Akdeniz koyu',
'hero-etikett.text' => 'Seyahat ilhamı',
'hero-bildzeile.text' => '<strong>Yeni favori yeriniz</strong>Biraz daha fazla deniz.',
'reisen-klein.text' => 'Sizi nereye çekiyor?',
'reisen-titel.text' => 'Sizde gezme isteği var.<br>Bizde fikirler.',
'reisen-satz.text' => 'Denizde bir mola, yeni bir favori yer ya da aile ziyareti. Size uygun seyahati birlikte buluyoruz.',
'angebot-1-klein.text' => 'Uzmanlık alanımız',
'angebot-1-titel.text' => 'Türkiye.<br>Tam size göre.',
'angebot-1-satz.text' => 'Türk Rivierası’ndan Ege’ye. Misafirperverlik, sahil ve kültür arasında bir tatil keşfedin – ilk elden ipuçlarıyla.',
'angebot-1-link.text' => '<a href="#kontakt">Türkiye tatili sorun</a>',
'angebot-2-klein.text' => 'Dünya genelinde oteller',
'angebot-2-titel.text' => 'Giriş yapın.<br>Kafanızı dinleyin.',
'angebot-2-satz.text' => 'Küçük bir butik otel mi, geniş bir resort mu? Tatiliniz için doğru yeri bulmanıza yardımcı oluyoruz.',
'angebot-2-link.text' => '<a href="#kontakt">Otel sorun</a>',
'angebot-3-klein.text' => 'Türkiye uçuşları',
'angebot-3-titel.text' => 'Bazen hedef<br>evdir.',
'angebot-3-satz.text' => 'Tatil, aile ya da sadece özlem için. Size uygun uçuşu buluyoruz – Karlsruhe/Baden-Baden, Stuttgart veya Frankfurt’tan da.',
'angebot-3-link.text' => '<a href="#kontakt">Türkiye uçuşu sorun</a>',
'beratung-klein.text' => 'Seyahat acenteniz.<br>Doğrudan iletişiminiz.',
'beratung-ort-text.text' => 'Kantarci Reisen<br>Ooser Hauptstraße 51<br>76532 Baden-Baden-Oos',
'beratung-titel.text' => 'İyi seyahatler<br>bir <em>sohbetle</em> başlar.',
'beratung-satz.text' => 'Sizin için neyin önemli olduğunu anlatın. Dinliyor, birlikte düşünüyor ve sizinle planlıyoruz. Kişisel, kolay ve Türkiye’ye özel bir yakınlıkla – ister plaj tatili, ister aile ziyareti, ister İstanbul’a şehir turu.',
'beratung-knopf.text' => 'Hadi konuşalım',
'schritt-1-titel.text' => 'İsteğinizi anlatın',
'schritt-1-satz.text' => 'Form, e-posta ya da doğrudan Oos’taki ofisimizde. Kabaca bir plan yeterli.',
'schritt-2-titel.text' => 'Önerileri alın',
'schritt-2-satz.text' => 'Otelleri, uçuşları ve tarihleri karşılaştırıyor, size uygun fikirlerle dönüyoruz.',
'schritt-3-titel.text' => 'Rahatça yola çıkın',
'schritt-3-satz.text' => 'Siz karar verirsiniz, biz rezervasyon yaparız. Belgeler ve irtibat kişisi bizden.',
'kontakt-klein.text' => 'Tatile ilk adım',
'kontakt-titel.text' => 'Nereye<br><em>gidelim?</em>',
'kontakt-satz.text' => 'Bir istek. Kabaca bir plan. Ya da belli bir hedef. Bize anlatın – size kişisel olarak dönüş yapacağız.',
'kontakt-whatsapp-satz.text' => 'Kısaca yazmayı mı tercih edersiniz? WhatsApp’ta size kişisel olarak cevap veriyoruz.',
'kontakt-hinweis.text' => 'Türkiye seyahatleri · Dünya genelinde oteller · Türkiye uçuşları<br><a href="tel:+491702945935">0170 2945935</a> · <a href="mailto:info@kantarci-reisen.de">info@kantarci-reisen.de</a>',
'kontakt-karte-klein.text' => 'Kişisel seyahat danışmanlığı',
'kontakt-karte-titel.text' => 'Seyahat talebiniz',
'kontakt-karte-satz.text' => 'İsteklerinizi yazın – bir sonraki seyahatiniz burada başlıyor.',
'kontakt-karte-hinweis.text' => 'Bilgilerinizi yalnızca talebiniz için kullanıyoruz. Ayrıntılar <a href="/datenschutz">gizlilik bildiriminde</a>.',
'reisesoft-etikett.text' => 'Seyahat acenteleri için',
'reisesoft-klein.text' => 'Seyahatin diğer tarafı için',
'reisesoft-titel.text' => 'Daha az idari iş.<br>Daha çok <em>seyahat acentesi.</em>',
'reisesoft-satz.text' => 'reiseSoft, seyahat acenteleri için web platformumuz – kendi ofis günlüğümüzden doğdu. Rezervasyonlar, müşteriler, faturalar ve ödemeler tek yerde; böylece danışmanlığa daha çok zaman kalır.',
'funktion-1-text.text' => '<strong>Rezervasyonu Ctrl+V ile aktarın</strong>Amadeus’tan veya havayolu portalından kopyalayın, yapıştırın, kontrol edin – hazır.',
'funktion-2-text.text' => '<strong>Fatura ve e-fatura</strong>Ardışık fatura numaraları, ZUGFeRD ve XRechnung, e-posta ile gönderim.',
'funktion-3-text.text' => '<strong>Açık kalemler göz önünde</strong>Ödemeleri kaydedin, ciro ve kârı değerlendirin – doğrudan tarayıcıda.',
'reisesoft-plattform.text' => 'reiseSoft platformuna',
'reisesoft-anfragen.text' => 'reiseSoft’u tanıyın',
'reisesoft-bild.alt' => 'Açık kalemler, ciro ve son işlemlerle reiseSoft genel görünümü (örnek veriler) – platforma',
'reisesoft-bildzeile.text' => 'Gerçek arayüz, hayali örnek veriler.',
// Sprachneutral, aber eingetragen: sonst zeigt der Editor sie als „fehlt“.
'schritt-1-nummer.text' => '01', 'schritt-2-nummer.text' => '02', 'schritt-3-nummer.text' => '03',
'funktion-1-nummer.text' => '01', 'funktion-2-nummer.text' => '02', 'funktion-3-nummer.text' => '03',
'beratung-mail-text.text' => '<a href="mailto:info@kantarci-reisen.de">info@kantarci-reisen.de</a>',
'beratung-telefon-text.text' => '<a href="tel:+491702945935">0170 2945935</a>',
'reisesoft-name.text' => 'reise<strong>Soft</strong>',
'reisesoft-fenster-adresse.text' => 'reisesoft.kantarci-reisen.de',
],
],
'impressum' => [
'slug' => 'kunye',
'title' => 'Künye',
'description' => 'Kantarci Reisen, sahibi I. Kantarci, Baden-Baden – sağlayıcı bilgileri.',
'seoTitle' => 'Künye | Kantarci Reisen',
'blocks' => [
'impressum-label.text' => 'Yasal bilgiler',
'impressum-h1.text' => 'Künye',
'impressum-vorspann.text' => '§ 5 DDG ve § 18 (2) MStV uyarınca bilgiler. '.$hinweisRecht,
'impressum-h2-0.text' => 'Sağlayıcı',
'impressum-p-0.text' => 'Kantarci Reisen<br>Sahibi: I. Kantarci<br>Ooser Hauptstraße 51<br>76532 Baden-Baden',
'impressum-h2-1.text' => 'İletişim',
'impressum-p-1.text' => 'Telefon: <a href="tel:+491702945935">0170 2945935</a><br>E-posta: <a href="mailto:info@kantarci-reisen.de">info@kantarci-reisen.de</a><br>WhatsApp: <a href="https://wa.me/491702945935?text=Merhaba%20Kantarci%20Reisen%2C%20bir%20seyahatle%20ilgileniyorum." rel="noopener">0170 2945935</a>',
'impressum-h2-2.text' => 'İçerikten sorumlu',
'impressum-p-2.text' => 'I. Kantarci, adres yukarıdaki gibi.',
'impressum-h2-3.text' => 'Seyahat aracılığı',
'impressum-p-3.text' => 'Kantarci Reisen paket turlar, otel konaklamaları ve uçuşlar gibi seyahat hizmetlerine aracılık eder. İlgili hizmetin sözleşme tarafı tur operatörü, otel veya havayolu şirketidir; rezervasyondan önce size ilettiğimiz onların genel ve taşıma koşulları geçerlidir.',
'impressum-h2-4.text' => 'Tüketici uyuşmazlıklarının çözümü',
'impressum-p-4.text' => 'Bir tüketici hakem kurulu önündeki uyuşmazlık çözüm sürecine katılmaya hazır ve yükümlü değiliz.',
'impressum-h2-5.text' => 'İçerikler için sorumluluk',
'impressum-p-5.text' => 'Hizmet sağlayıcı olarak bu sayfalardaki kendi içeriklerimizden genel yasalar çerçevesinde sorumluyuz. Seyahat bilgilerini bilgimiz dahilinde aktarıyoruz; bağlayıcı olan ilgili teklifteki bilgilerdir. Hukuka aykırılıklardan haberdar olduğumuzda ilgili içerikleri derhal kaldırırız.',
'impressum-h2-6.text' => 'Bağlantılar için sorumluluk',
'impressum-p-6.text' => 'Bu web sitesi <a href="https://reisesoft.kantarci-reisen.de" rel="noopener">reisesoft.kantarci-reisen.de</a> adresindeki reiseSoft platformuna yönlendirir. Yabancı sayfaların içeriklerinden ilgili sağlayıcı sorumludur.',
'impressum-h2-7.text' => 'Telif hakkı',
'impressum-p-7.text' => 'Bu sayfalarda tarafımızdan oluşturulan içerik ve eserler Alman telif hakkı yasasına tabidir. Telif hakkı sınırları dışında çoğaltma, işleme, yayma ve her türlü kullanım yazılı izne bağlıdır.',
'impressum-h2-8.text' => 'Görsel kaynakları',
'impressum-p-8.text' => 'Logo: Kantarci Reisen. Ana sayfadaki seyahat fotoğrafı: yapay zekâ ile üretilmiştir. Ekran görüntüsü: hayali örnek verilerle reiseSoft.',
],
],
'datenschutz' => [
'slug' => 'gizlilik',
'title' => 'Gizlilik',
'description' => 'Kantarci Reisen web sitesini ziyaret ederken ve seyahat talebinde hangi verilerin işlendiği.',
'seoTitle' => 'Gizlilik | Kantarci Reisen',
'blocks' => [
'datenschutz-label.text' => 'Verileriniz',
'datenschutz-h1.text' => 'Gizlilik',
'datenschutz-vorspann.text' => 'Bu web sitesini ziyaret ederken ve bir talepte bulunduğunuzda hangi verilerin işlendiğini ve hangi haklara sahip olduğunuzu burada öğrenebilirsiniz. '.$hinweisRecht,
'datenschutz-h2-0.text' => '1. Sorumlu',
'datenschutz-p-0.text' => 'Kantarci Reisen, sahibi I. Kantarci, Ooser Hauptstraße 51, 76532 Baden-Baden. Telefon <a href="tel:+491702945935">0170 2945935</a>, e-posta <a href="mailto:info@kantarci-reisen.de">info@kantarci-reisen.de</a>.',
'datenschutz-h2-1.text' => '2. Bu web sitesinin ziyareti',
'datenschutz-p-1.text' => 'Sayfa açıldığında barındırma hizmeti sağlayıcımız teknik olarak gerekli bağlantı verilerini işler: IP adresi, zaman, istenen adres, tarayıcı bilgileri ve HTTP durumu. Bu, güvenli sunum ve hata ayıklama içindir. Hukuki dayanak, kesintisiz işletimdeki meşru menfaatimizdir, GVKT (DSGVO) md. 6 f. 1 b. f.<br><br>Barındırma hizmeti sağlayıcısıyla GVKT md. 28 uyarınca bir veri işleme sözleşmesi bulunmaktadır. Sunucu kayıtları, bir güvenlik olayının aydınlatılması için daha uzun süre gerekmedikçe en geç yedi gün sonra silinir veya anonimleştirilir.',
'datenschutz-h2-2.text' => '3. Çerezler ve harici hizmetler',
'datenschutz-p-2.text' => 'Bu web sitesi analiz veya reklam çerezi kullanmaz. Resimler, yazı tipleri ve tasarım kendi sunucumuzdan gelir; üçüncü taraflardan harita, video veya yazı tipi yüklenmez. Bu nedenle bir onay penceresi de yoktur.',
'datenschutz-h2-3.text' => '4. Seyahat talebi',
'datenschutz-p-3.text' => 'Bize form aracılığıyla yazdığınızda, talebinizi yanıtlamak ve uygun teklifler hazırlamak için adınızı, e-posta adresinizi, isteğe bağlı olarak telefon numaranızı, seyahat dönemini, kişi sayısını ve isteklerinizi işleriz (GVKT md. 6 f. 1 b. b). Talep sistemimizde kaydedilir ve e-posta ile bize iletilir. Talep sonuçlandığında ve yasal saklama yükümlülüğü bulunmadığında silinir.',
'datenschutz-h2-4.text' => '5. Rezervasyonlar',
'datenschutz-p-4.text' => 'Bir rezervasyon yapılırsa, bunun için gerekli bilgileri (örneğin kimlikteki yolcu adları ve seyahat tarihleri) tur operatörüne, otele veya havayolu şirketine iletiriz (GVKT md. 6 f. 1 b. b). Fatura belgelerini ticaret ve vergi hukukunun gerektirdiği süre boyunca saklarız.',
'datenschutz-h2-5.text' => '6. E-posta veya telefonla iletişim',
'datenschutz-p-5.text' => 'Bize yazdığınızda veya bizi aradığınızda, talebinizi işlemek için bilgilerinizi işleriz (GVKT md. 6 f. 1 b. b veya f).',
'datenschutz-h2-6.text' => '7. WhatsApp',
'datenschutz-p-6.text' => 'WhatsApp düğmeleri basit bağlantılardır. Yalnızca birini kullandığınızda, WhatsApp Ireland Limited (Meta) tarafından sunulan WhatsApp açılır. WhatsApp bu sırada telefon numaranızı, mesajlarınızı ve kullanım verilerinizi kendi gizlilik bildirimine göre, AB dışındaki ülkelerde de işler. Mesajınızı yalnızca talebinizi yanıtlamak için kullanırız (GVKT md. 6 f. 1 b. b). Bunu istemiyorsanız bize form, e-posta veya telefonla da ulaşabilirsiniz.',
'datenschutz-h2-7.text' => '8. reiseSoft',
'datenschutz-p-7.text' => 'reiseSoft platformuna giden bağlantı, reisesoft.kantarci-reisen.de adresindeki ayrı bir uygulamaya yönlendirir. Veriler ancak bağlantıyı takip ettiğinizde orada işlenir; kayıtlı seyahat acenteleri için platformun bildirimleri geçerlidir.',
'datenschutz-h2-8.text' => '9. Haklarınız',
'datenschutz-p-8.text' => 'Yasal koşullar çerçevesinde bilgi alma, düzeltme, silme, işlemenin kısıtlanması ve veri taşınabilirliği haklarına sahipsiniz. GVKT md. 6 f. 1 b. f’ye dayanan bir işlemeye itiraz edebilirsiniz.',
'datenschutz-h2-9.text' => '10. Şikâyet hakkı',
'datenschutz-p-9.text' => 'Bir veri koruma denetim makamına şikâyette bulunabilirsiniz; bizim için yetkili makam Baden-Württemberg Veri Koruma ve Bilgi Edinme Özgürlüğü Görevlisi’dir (Landesbeauftragter für den Datenschutz und die Informationsfreiheit Baden-Württemberg).',
'datenschutz-p-10.text' => 'Gizlilikle ilgili sorularınızı <a href="mailto:info@kantarci-reisen.de">info@kantarci-reisen.de</a> adresinden memnuniyetle yanıtlarız.',
],
],
'404' => [
'title' => 'Sayfa bulunamadı',
'description' => 'Aradığınız sayfa mevcut değil veya taşınmış.',
'blocks' => [
'fehler-label.text' => 'Hata 404',
'fehler-titel.text' => 'Maalesef burada<br><em>devam edilemiyor.</em>',
'fehler-text.text' => 'Bu sayfa mevcut değil veya taşınmış. Ana sayfadan bir sonraki hedefinizi kolayca bulabilirsiniz.',
'fehler-knopf.text' => 'Ana sayfaya',
],
],
];
// ---------------------------------------------------------------------------------------------
// Kopf, Fuß, Menü, Formular
// ---------------------------------------------------------------------------------------------
$bereiche = [
'header' => ['kopf-logo.alt' => 'Kantarci Reisen – ana sayfaya'],
'footer' => [
'fuss-logo.alt' => 'Kantarci Reisen',
'fuss-copyright.text' => '© 2026 Kantarci Reisen',
'fuss-spruch.text' => 'Kalbimizde Türkiye. Gözümüz dünyada.',
'fuss-reisen-titel.text' => 'Seyahatler',
'fuss-reisen-liste.text' => '<a href="/#reisen">Türkiye tatili</a><br><a href="/#reisen">Dünya genelinde oteller</a><br><a href="/#reisen">Türkiye uçuşları</a><br><a href="/#kontakt">Seyahat talebi</a>',
'fuss-business-titel.text' => 'Seyahat acenteleri için',
'fuss-business-liste.text' => '<a href="/#reisesoft">reiseSoft’u tanıyın</a><br><a href="https://reisesoft.kantarci-reisen.de" rel="noopener">reiseSoft platformuna</a>',
'fuss-kontakt-titel.text' => 'İletişim',
'fuss-kontakt-text.text' => 'Kantarci Reisen<br>Ooser Hauptstraße 51<br>76532 Baden-Baden<br><a href="tel:+491702945935">0170 2945935</a><br><a href="mailto:info@kantarci-reisen.de">info@kantarci-reisen.de</a><br><a href="https://wa.me/491702945935?text=Merhaba%20Kantarci%20Reisen%2C%20bir%20seyahatle%20ilgileniyorum." rel="noopener">WhatsApp</a>',
'fuss-rechtliches.label' => 'Yasal bilgiler',
'fuss-agentur.text' => '<a href="https://kant-it.de" rel="noopener">Web sitesi: Kant-IT Solutions</a>',
],
];
$menue = [
'Reisen' => 'Seyahatler',
'Über uns' => 'Hakkımızda',
'reiseSoft' => 'reiseSoft',
'Kontakt' => 'İletişim',
'Reise anfragen' => 'Seyahat talebi',
];
$formular = [
'buttonLabel' => 'Talebi gönder',
'success' => 'Teşekkürler! Talebiniz bize ulaştı. Size kişisel olarak dönüş yapacağız – genellikle bir iş günü içinde.',
'fields' => [
'name' => ['label' => 'Adınız', 'help' => 'Ad ve soyad'],
'email' => ['label' => 'E-posta adresiniz'],
'telefon' => ['label' => 'Telefon', 'help' => 'İsteğe bağlı – sizi aramamızı tercih ederseniz'],
'anliegen' => ['label' => 'Konu', 'options' => [
'Türkei-Urlaub' => 'Türkiye tatili',
'Hotels weltweit' => 'Dünya genelinde oteller',
'Flüge in die Türkei' => 'Türkiye uçuşları',
'reiseSoft für mein Reisebüro' => 'Seyahat acentem için reiseSoft',
'Allgemeine Anfrage' => 'Genel talep',
]],
'zeitraum' => ['label' => 'Seyahat dönemi', 'help' => 'ör. Pentekost tatili veya Ağustos’ta 2 hafta'],
'personen' => ['label' => 'Kişi sayısı'],
'wuensche' => ['label' => 'İstekleriniz', 'help' => 'Varış noktası, kalkış havalimanı, bütçe, sizin için önemli olanlar …'],
'datenschutz' => ['label' => 'Bilgilerimin gizlilik bildirimine uygun olarak işlenmesini kabul ediyorum.'],
],
];
// ---------------------------------------------------------------------------------------------
// Ausführen
// ---------------------------------------------------------------------------------------------
$languages->save([SPRACHE]);
echo "Sprache eingeschaltet: Türkisch\n";
/** Legt die Übersetzung auf das Dokument; meldet Schlüssel, die es im Dokument nicht gibt. */
$uebersetzen = static function (array $document, array $daten, string $ort): array {
$texte = [];
$vorhanden = [];
$walk = static function (array $blocks) use (&$walk, &$vorhanden): void {
foreach ($blocks as $block) {
foreach (Translations::FIELDS[$block['type'] ?? ''] ?? [] as $prop) {
$vorhanden[$block['id'].'.'.$prop] = $block['props'][$prop] ?? '';
}
$walk($block['children'] ?? []);
}
};
$walk($document['blocks']);
$translation = [];
$source = [];
foreach ($daten['blocks'] ?? $daten as $schluessel => $text) {
if (!array_key_exists($schluessel, $vorhanden)) {
throw new RuntimeException(sprintf('%s: „%s“ gibt es im Dokument nicht.', $ort, $schluessel));
}
[$id, $prop] = explode('.', $schluessel, 2);
$translation['blocks'][$id][$prop] = $text;
$source[$schluessel] = Translations::fingerprint((string) $vorhanden[$schluessel]);
}
foreach (['title', 'description'] as $feld) {
if (isset($daten[$feld])) {
$translation[$feld] = $daten[$feld];
$source[$feld] = Translations::fingerprint((string) $document[$feld]);
}
}
foreach (['slug', 'seoTitle'] as $feld) {
if (isset($daten[$feld])) {
$translation[$feld] = $daten[$feld];
}
}
$translation['source'] = $source;
$document['schemaVersion'] = max((int) $document['schemaVersion'], Translations::SCHEMA);
$document['translations'] = [SPRACHE => $translation];
return $document;
};
foreach ($seiten as $pfad => $daten) {
$zeile = $db->fetchAssociative('SELECT id, version FROM page WHERE path = ? AND deleted_at IS NULL', [$pfad]);
if (false === $zeile) {
throw new RuntimeException("Seite /{$pfad} fehlt.");
}
$entwurf = $pages->findForEditor($zeile['id']);
$dokument = $uebersetzen($entwurf['document'], $daten, '/'.$pfad);
$revision = $pages->saveDraft($zeile['id'], $dokument, $entwurf['version']);
$pages->publish($zeile['id'], $revision, $entwurf['version'] + 1);
$zaehlung = Translations::progress($dokument, SPRACHE);
printf("Seite /%s: %d von %d Texten übersetzt, veröffentlicht\n", $pfad, $zaehlung['done'], $zaehlung['total']);
}
foreach ($bereiche as $art => $texte) {
$bereich = $partials->findByKind($art);
$dokument = $uebersetzen($bereich['document'], $texte, $art);
if ('header' === $art) {
// Die Sprachwahl rechts neben dem Menü, als Kürzel. Auf dem Telefon bleibt sie neben dem
// Menü-Knopf stehen; das Menü selbst rückt mit margin-left:auto nach rechts.
$zeile = &$dokument['blocks'][0]['children'][0];
$zeile['children'] = array_values(array_filter($zeile['children'], static fn (array $b): bool => 'kopf-sprache' !== $b['id']));
foreach ($zeile['children'] as &$kind) {
if ('kopf-menue' === $kind['id'] && !str_contains($kind['css'] ?? '', 'margin-left:auto')) {
$kind['css'] = "&{margin-left:auto}\n".($kind['css'] ?? '');
}
}
unset($kind);
$zeile['children'][] = [
'id' => 'kopf-sprache', 'type' => 'language', 'props' => ['display' => 'code'],
// Auf dem Telefon ist neben Logo, Anfrageknopf und Menü kein Platz - dort steht die
// Sprachwahl im Fuß.
'layout' => ['visibility' => 'hide-mobile'],
'style' => [
'desktop' => ['fontSize' => '14px', 'fontWeight' => '600', 'color' => '@tinte', 'margin' => ['left' => '20px']],
'mobile' => ['margin' => ['left' => '0px']],
],
'css' => "& a{border-radius:4px;letter-spacing:.04em}\n& a[aria-current]{box-shadow:inset 0 -2px 0 #ff753d}\n& a:hover{text-decoration:none;background:#f1f5f5}",
];
unset($zeile);
}
if ('footer' === $art) {
// Unten neben der Rechtszeile, auf jedem Gerät - auf dem Telefon der Weg zur Sprache.
$sprache = [
'id' => 'fuss-sprache', 'type' => 'language', 'props' => ['display' => 'name'],
'style' => ['desktop' => ['fontSize' => '13px']],
'css' => "& a{padding:2px 6px;color:inherit}
& a[aria-current]{box-shadow:inset 0 -2px 0 #ff753d}",
];
$einsetzen = static function (array $blocks) use (&$einsetzen, $sprache): array {
foreach ($blocks as $i => $block) {
$kinder = array_values(array_filter($block['children'] ?? [], static fn (array $b): bool => 'fuss-sprache' !== $b['id']));
if ('fuss-links' === $block['id']) {
array_unshift($kinder, $sprache);
}
$blocks[$i]['children'] = $einsetzen($kinder);
}
return $blocks;
};
$dokument['blocks'] = $einsetzen($dokument['blocks']);
}
$partials->save($bereich['id'], $dokument, $bereich['version']);
$zaehlung = Translations::progress($dokument, SPRACHE);
printf("Bereich %s: %d von %d Texten übersetzt\n", $art, $zaehlung['done'], $zaehlung['total']);
}
$alle = $menus->all();
$kopfmenue = $alle['header'];
$beschriften = static function (array $items) use (&$beschriften, $menue): array {
foreach ($items as $i => $item) {
if (isset($menue[$item['label']])) {
$items[$i]['labels'] = [SPRACHE => $menue[$item['label']]];
}
$items[$i]['children'] = $beschriften($item['children'] ?? []);
}
return $items;
};
$menus->save('header', $kopfmenue['name'], $beschriften($kopfmenue['items']), $kopfmenue['version']);
echo "Menü: ".count($menue)." Beschriftungen\n";
$form = $forms->findBySlug('reiseanfrage');
$einstellungen = $form['settings'];
$einstellungen['translations'] = [SPRACHE => $formular];
$forms->save('reiseanfrage', $form['name'], array_map(static fn (array $f): array => [...$f, 'images' => $f['images'] ?: '', 'min' => $f['min'] ?? '', 'max' => $f['max'] ?? ''], $form['fields']), $einstellungen, $form['version']);
echo "Formular reiseanfrage übersetzt\n";
echo "Fertig: /tr, /tr/kunye, /tr/gizlilik\n";