'Deutsch',
'en' => 'English',
'fr' => 'Français',
'es' => 'Español',
'it' => 'Italiano',
'pt' => 'Português',
'nl' => 'Nederlands',
'pl' => 'Polski',
'cs' => 'Čeština',
'da' => 'Dansk',
'sv' => 'Svenska',
'no' => 'Norsk',
'fi' => 'Suomi',
'hu' => 'Magyar',
'ro' => 'Română',
'hr' => 'Hrvatski',
'sk' => 'Slovenčina',
'sl' => 'Slovenščina',
'bg' => 'Български',
'el' => 'Ελληνικά',
'tr' => 'Türkçe',
'ru' => 'Русский',
'uk' => 'Українська',
'ja' => '日本語',
'zh' => '中文',
'ko' => '한국어',
'ar' => 'العربية',
];
$selectedSecondaryLang = $_POST['secondary_lang'] ?? 'de';
if ($selectedSecondaryLang !== '' && !isset($setupLanguages[$selectedSecondaryLang])) {
$selectedSecondaryLang = 'de';
}
/**
* Generate starter site files after config is created.
* Creates: language dirs, homepage + demo page templates, starter content,
* nav-config, settings, news posts, .htaccess update.
*/
function generateStarterSite($primaryLang, $secondaryLang, $siteName, $setupLanguages) {
require_once __DIR__ . '/starter-content.php';
$root = dirname(__DIR__);
$languages = [$primaryLang];
if (!empty($secondaryLang)) $languages[] = $secondaryLang;
$i18n = getStarterI18n($siteName);
$contentDir = $root . '/content/pages';
if (!is_dir($contentDir)) @mkdir($contentDir, 0755, true);
$newsDir = $root . '/content/news';
if (!is_dir($newsDir)) @mkdir($newsDir, 0755, true);
// 1. Create language directories + page templates
foreach ($languages as $lang) {
$dir = $root . '/' . $lang;
if (!is_dir($dir)) @mkdir($dir, 0755, true);
$t = $i18n[$lang] ?? $i18n['en'];
// Homepage template (renders sections from JSON)
$homeTpl = <<<'PHPTPL'
Haben Sie eine Frage, Feedback oder möchten Sie einfach Hallo sagen? Füllen Sie das Formular aus und wir melden uns so schnell wie möglich bei Ihnen.
' : ($lang === 'es' ? '¿Tienes una pregunta, comentario o simplemente quieres saludar? Rellena el formulario y te responderemos lo antes posible.
' : 'Have a question, feedback, or just want to say hello? Fill out the form below and we\'ll get back to you as soon as possible.
'); $contactContent = [ 'page' => $lang . '_' . $contactSlug, 'lang' => $lang, 'title' => $contactTitle, 'description' => $contactTitle, 'sections' => [ ['id' => 's1', 'type' => 'heading', 'text' => $contactHeadingText, 'level' => 'h1', 'subtitle' => $contactSubtitle], ['id' => 's2', 'type' => 'text', 'title' => '', 'content' => $contactIntro], ], ]; file_put_contents($contentDir . '/' . $lang . '_' . $contactSlug . '.json', json_encode($contactContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); // 3. Create demo news posts $posts = getNewsPosts($lang, $t); foreach ($posts as $post) { file_put_contents($newsDir . '/' . $post['filename'], json_encode($post['data'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } } // 4. Create footer.json $footerData = [ 'page' => 'footer', 'lastModified' => null, 'tagline' => [], 'services' => [], 'claim' => [], 'contact' => ['phone' => '', 'email' => ''], 'credit' => ['text' => '', 'link' => '', 'linkText' => ''], 'contactHeading' => [], // The [id="adminAccess"] shortcode wraps the year in a that // includes/footer.php uses as the hidden admin-login double-click target. 'copyright' => '© [id="adminAccess"]' . date('Y') . '[/id] ' . htmlspecialchars($siteName), ]; foreach ($languages as $lang) { if ($lang === 'de') { $footerData['tagline'][$lang] = 'Ein leichtes Flat-File-CMS für editierbare Websites.'; $footerData['services'][$lang] = 'Inhalte inline bearbeiten, Seiten als JSON verwalten und individuelle Layouts sauber pflegen.'; $footerData['claim'][$lang] = 'Keine Datenbank. Kein schwerer Stack. Nur Inhalte, die Kunden selbst aktualisieren können.'; } elseif ($lang === 'es') { $footerData['tagline'][$lang] = 'Un CMS ligero de archivos planos para sitios web editables.'; $footerData['services'][$lang] = 'Edita contenido en línea, gestiona páginas como JSON y mantén diseños personalizados.'; $footerData['claim'][$lang] = 'Sin base de datos. Sin stack pesado. Solo contenido que tus clientes pueden actualizar.'; } else { $footerData['tagline'][$lang] = 'A lightweight flat-file CMS for editable websites.'; $footerData['services'][$lang] = 'Edit content inline, manage pages as JSON, and keep custom layouts maintainable.'; $footerData['claim'][$lang] = 'No database. No heavy stack. Just content your clients can update.'; } $footerData['contactHeading'][$lang] = $lang === 'de' ? 'Kontakt' : ($lang === 'es' ? 'Contacto' : 'Contact'); } file_put_contents($root . '/content/pages/footer.json', json_encode($footerData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); // 4b. Create menus.json (menu registry) $menusData = ['menus' => [ 'header' => ['label' => [], 'type' => 'standard', 'weight' => 0], 'footer-pages' => ['label' => [], 'weight' => 10], 'footer-legal' => ['label' => [], 'weight' => 20], ]]; foreach ($languages as $lang) { $menusData['menus']['header']['label'][$lang] = $lang === 'de' ? 'Kopfzeile' : ($lang === 'es' ? 'Encabezado' : 'Header'); $menusData['menus']['footer-pages']['label'][$lang] = $lang === 'de' ? 'Seiten' : ($lang === 'es' ? 'Páginas' : 'Pages'); $menusData['menus']['footer-legal']['label'][$lang] = $lang === 'de' ? 'Rechtliches' : 'Info'; } file_put_contents($root . '/content/menus.json', json_encode($menusData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); // 5. Create nav-config.php (includes all demo pages) file_put_contents($root . '/includes/nav-config.php', getNavConfig($languages, $primaryLang, $setupLanguages)); // 6. Create settings.json $settings = [ 'favicon' => '/assets/images/favicon.svg', 'branding' => [ 'logo' => '', 'name' => $siteName, 'showBranding' => true, 'logoDisplay' => 'both', ], 'theme' => [ 'adminTheme' => 'light', 'primaryColor' => '#3858e9', 'accentColor' => '#3858e9', ], 'email' => [ 'method' => 'inactive', 'recipientEmail' => '', 'bccEmail' => '', 'fromEmail' => '', 'fromName' => '', 'smtpHost' => '', 'smtpPort' => 587, 'smtpUsername' => '', 'smtpPassword' => '', 'smtpEncryption' => 'tls', ], ]; file_put_contents($root . '/content/settings.json', json_encode($settings, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); // 7. Create starter events $starterEvents = getStarterEvents($languages); file_put_contents($root . '/content/events.json', json_encode($starterEvents, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); // 8. Create demo contact messages $starterMails = getStarterMails(); file_put_contents($root . '/content/mails.json', json_encode($starterMails, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); // 9. Update .htaccess primary language if not 'en' $htaccessPath = $root . '/.htaccess'; if ($primaryLang !== 'en' && file_exists($htaccessPath)) { $htaccess = file_get_contents($htaccessPath); $htaccess = str_replace( ['%{DOCUMENT_ROOT}/en/%1.php', 'en/$1.php [L]'], ['%{DOCUMENT_ROOT}/' . $primaryLang . '/%1.php', $primaryLang . '/$1.php [L]'], $htaccess ); file_put_contents($htaccessPath, $htaccess); } } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $siteName = trim($_POST['site_name'] ?? ''); $username = trim($_POST['username'] ?? ''); $email = trim($_POST['email'] ?? ''); $password = $_POST['password'] ?? ''; $passwordConfirm = $_POST['password_confirm'] ?? ''; $primaryLang = $_POST['primary_lang'] ?? 'en'; $secondaryLang = $_POST['secondary_lang'] ?? ''; // Validate language selections if (!isset($setupLanguages[$primaryLang])) { $primaryLang = 'en'; } if (!empty($secondaryLang) && !isset($setupLanguages[$secondaryLang])) { $secondaryLang = ''; } if ($secondaryLang === $primaryLang) { $secondaryLang = ''; } // Validation if (!is_string($_POST['csrf_token'] ?? null) || !hash_equals($_SESSION['setup_csrf'], $_POST['csrf_token'])) { $error = t('api.csrf'); } elseif (empty($siteName)) { $error = t('setup.error_site_name'); } elseif (empty($username)) { $error = t('setup.error_username'); } elseif (strlen($username) < 3) { $error = t('setup.error_username_short'); } elseif (empty($password)) { $error = t('setup.error_password'); } elseif ($password !== $passwordConfirm) { $error = t('setup.error_password_mismatch'); } elseif (isPasswordWeak($password)) { $error = t('setup.error_password_weak'); } else { // Generate hash and write config $hash = password_hash($password, PASSWORD_DEFAULT); $escapedSiteName = addcslashes($siteName, "'\\"); // Build $SITE_LANGUAGES array $languages = [$primaryLang => $setupLanguages[$primaryLang]]; if (!empty($secondaryLang)) { $languages[$secondaryLang] = $setupLanguages[$secondaryLang]; } // Build languages PHP code $langLines = []; foreach ($languages as $code => $name) { $langLines[] = " '" . $code . "' => '" . addcslashes($name, "'\\") . "'"; } $langArrayCode = implode(",\n", $langLines); $configContent = <<