diff --git a/app/content.php b/app/content.php index 2420533..8c8782c 100644 --- a/app/content.php +++ b/app/content.php @@ -32,28 +32,6 @@ function findAllContentFiles(string $dir): array { return array_column($contentFiles, 'path'); } -function resolveSlugToFolder(string $parentDir, string $slug): ?string { - if (!is_dir($parentDir)) return null; - - $items = scandir($parentDir) ?: []; - foreach ($items as $item) { - if ($item === '.' || $item === '..' || !is_dir("$parentDir/$item")) continue; - - // Check if folder name matches slug - if ($item === $slug) { - return $item; - } - - // Check metadata for custom slug - $metadata = loadMetadata("$parentDir/$item"); - if ($metadata && isset($metadata['slug']) && $metadata['slug'] === $slug) { - return $item; - } - } - - return null; -} - function parseRequestPath(Context $ctx): array { $requestPath = $ctx->requestPath; @@ -61,20 +39,7 @@ function parseRequestPath(Context $ctx): array { return ['type' => 'frontpage', 'path' => $ctx->contentDir]; } - // Try resolving slug to actual folder path - $pathParts = explode('/', trim($requestPath, '/')); - $resolvedPath = $ctx->contentDir; - - foreach ($pathParts as $part) { - $resolved = resolveSlugToFolder($resolvedPath, $part); - if ($resolved === null) { - // Slug not found, return not_found - return ['type' => 'not_found', 'path' => $ctx->contentDir . '/' . $requestPath]; - } - $resolvedPath .= '/' . $resolved; - } - - $contentPath = $resolvedPath; + $contentPath = $ctx->contentDir . '/' . $requestPath; // Check if it's a directory if (is_dir($contentPath)) { @@ -113,7 +78,6 @@ function loadMetadata(string $dirPath): ?array { function buildNavigation(Context $ctx): array { $items = scandir($ctx->contentDir) ?: []; $navItems = []; - $langPrefix = $ctx->get('langPrefix', ''); foreach ($items as $item) { if ($item === '.' || $item === '..' || !is_dir($ctx->contentDir . "/$item")) continue; @@ -135,7 +99,7 @@ function buildNavigation(Context $ctx): array { $navItems[] = [ 'title' => $title, - 'url' => $langPrefix . '/' . urlencode($urlSlug) . '/', + 'url' => '/' . urlencode($urlSlug) . '/', 'order' => (int)($metadata['menu_order'] ?? 999) ]; } diff --git a/app/plugins/global/languages.php b/app/plugins/global/languages.php index 588a956..2b4ded2 100644 --- a/app/plugins/global/languages.php +++ b/app/plugins/global/languages.php @@ -1,216 +1,85 @@ requestPath); - $currentLang = $defaultLang; - - // Remove language prefix from URL if present - if (!empty($pathParts[0]) && in_array($pathParts[0], $availableLangs) && $pathParts[0] !== $defaultLang) { - $currentLang = array_shift($pathParts); - $reflection = new ReflectionProperty($ctx, 'requestPath'); - $reflection->setValue($ctx, implode('/', $pathParts)); - } - - $ctx->set('currentLang', $currentLang); - $ctx->set('defaultLang', $defaultLang); - $ctx->set('availableLangs', $availableLangs); - $ctx->set('langPrefix', $currentLang !== $defaultLang ? "/$currentLang" : ''); - $ctx->set('translations', loadTranslations($currentLang)); - - return $ctx; -}); - -// Filter content and metadata by language -Hooks::add(Hook::PROCESS_CONTENT, function(mixed $data, string $dirOrType, string $extraContext = '') { - global $GLOBALS; - $ctx = $GLOBALS['ctx'] ?? null; - if (!$ctx) return $data; - - $currentLang = $ctx->get('currentLang', 'en'); - - // Merge language-specific metadata sections - if ($extraContext === 'metadata' && isset($data['_raw'][$currentLang]) && is_array($data['_raw'][$currentLang])) { - return array_merge($data, $data['_raw'][$currentLang]); - } - - // Format dates with translated month names - if ($dirOrType === 'date_format') { - return formatDate($data, $currentLang); - } - - // Filter content files by language variant - if (is_array($data) && !empty($data) && isset($data[0]['path'])) { - return filterFilesByLanguage($data, $dirOrType, $ctx); - } - - return $data; -}); - -// Add language variables to templates -Hooks::add(Hook::TEMPLATE_VARS, function(array $vars, Context $ctx) { - $currentLang = $ctx->get('currentLang', 'en'); - $defaultLang = $ctx->get('defaultLang', 'en'); - $availableLangs = $ctx->get('availableLangs', ['en']); - - $vars['currentLang'] = $currentLang; - $vars['defaultLang'] = $defaultLang; - $vars['langPrefix'] = $ctx->get('langPrefix', ''); - $vars['translations'] = $ctx->get('translations', []); - $vars['availableLangs'] = $availableLangs; - $vars['languageUrls'] = buildLanguageUrls($ctx, $currentLang, $defaultLang, $availableLangs); - - return $vars; -}); - -// --- Helper functions --- +// Languages plugin - translation loading and filtering function loadTranslations(string $lang): array { - $defaultFile = dirname(__DIR__, 2) . "/default/languages/$lang.ini"; - $customFile = dirname(__DIR__, 3) . "/custom/languages/$lang.ini"; + $defaultTranslationFile = dirname(__DIR__, 2) . "/default/languages/$lang.ini"; + $customTranslationFile = dirname(__DIR__, 3) . "/custom/languages/$lang.ini"; - $translations = file_exists($defaultFile) ? parse_ini_file($defaultFile) ?: [] : []; + $translations = []; - if (file_exists($customFile)) { - $translations = array_merge($translations, parse_ini_file($customFile) ?: []); + if (file_exists($defaultTranslationFile)) { + $translations = parse_ini_file($defaultTranslationFile) ?: []; + } + + if (file_exists($customTranslationFile)) { + $customTranslations = parse_ini_file($customTranslationFile) ?: []; + $translations = array_merge($translations, $customTranslations); } return $translations; } +function shouldHideUntranslated(): bool { + $configFile = file_exists(__DIR__ . '/../../../custom/config.ini') + ? __DIR__ . '/../../../custom/config.ini' + : __DIR__ . '/../../config.ini'; + + if (!file_exists($configFile)) return true; + + $config = parse_ini_file($configFile, true); + return !isset($config['languages']['show_untranslated']) + || $config['languages']['show_untranslated'] !== 'true'; +} + +function hasLanguageMetadata(string $dirPath, string $lang): bool { + $metadataFile = "$dirPath/metadata.ini"; + if (!file_exists($metadataFile)) return false; + + $metadata = parse_ini_file($metadataFile, true); + if (!$metadata) return false; + + if (!isset($metadata[$lang]) || !is_array($metadata[$lang])) return false; + + // Check if language section has meaningful content (title or summary) + return isset($metadata[$lang]['title']) || isset($metadata[$lang]['summary']); +} + +function hasLanguageContent(string $dirPath, string $lang, array $contentExtensions): bool { + if (!is_dir($dirPath)) return false; + + $files = scandir($dirPath) ?: []; + foreach ($files as $file) { + $ext = pathinfo($file, PATHINFO_EXTENSION); + if (!in_array($ext, $contentExtensions)) continue; + + $parts = explode('.', $file); + if (count($parts) >= 3) { + $fileLang = $parts[count($parts) - 2]; + if ($fileLang === $lang && is_file("$dirPath/$file")) { + return true; + } + } + } + return false; +} + function formatDate(string $dateString, string $lang): string { - if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})/', $dateString, $m)) { + if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})/', $dateString, $matches)) { return $dateString; } $translations = loadTranslations($lang); - $day = (int)$m[3]; - $monthIndex = (int)$m[2] - 1; - $year = $m[1]; + $day = (int)$matches[3]; + $monthIndex = (int)$matches[2] - 1; + $year = $matches[1]; - $month = $m[2]; if (isset($translations['months'])) { $months = array_map('trim', explode(',', $translations['months'])); - $month = $months[$monthIndex] ?? $m[2]; + $month = $months[$monthIndex] ?? $matches[2]; + } else { + $month = $matches[2]; } return "$day. $month $year"; } - -function filterFilesByLanguage(array $files, string $dir, Context $ctx): array { - $currentLang = $ctx->get('currentLang', 'en'); - $defaultLang = $ctx->get('defaultLang', 'en'); - $availableLangs = $ctx->get('availableLangs', ['en']); - - $filtered = []; - $seen = []; - - foreach ($files as $file) { - $parts = explode('.', $file['name']); - - // Language-specific file (name.lang.ext) - if (count($parts) >= 3 && in_array($parts[count($parts) - 2], $availableLangs)) { - $fileLang = $parts[count($parts) - 2]; - if ($fileLang === $currentLang) { - $filtered[] = $file; - $seen[$parts[0]] = true; - } - continue; - } - - // Default file - include if no language version exists - $baseName = $parts[0]; - if (!isset($seen[$baseName])) { - $hasLangVersion = $currentLang !== $defaultLang && - array_reduce(CONTENT_EXTENSIONS, - fn($found, $ext) => $found || file_exists("$dir/$baseName.$currentLang.$ext"), - false); - - if (!$hasLangVersion) { - $filtered[] = $file; - $seen[$baseName] = true; - } - } - } - - return $filtered; -} - -function buildLanguageUrls(Context $ctx, string $currentLang, string $defaultLang, array $availableLangs): array { - // Frontpage URLs - if (empty($ctx->requestPath)) { - return array_reduce($availableLangs, - fn($urls, $lang) => $urls + [$lang => $lang === $defaultLang ? '/' : "/$lang/"], - []); - } - - // Resolve current path to actual folder names - $folders = resolvePath($ctx->requestPath, $ctx->contentDir); - if (!$folders) { - // Fallback: simple language prefix - return buildSimpleUrls($ctx, $defaultLang, $availableLangs); - } - - // Build URLs with language-specific slugs - $urls = []; - foreach ($availableLangs as $lang) { - $segments = []; - $dir = $ctx->contentDir; - - foreach ($folders as $folderName) { - $metadataFile = "$dir/$folderName/metadata.ini"; - $slug = $folderName; - - if (file_exists($metadataFile)) { - $metadata = parse_ini_file($metadataFile, true) ?: []; - - // Check for language-specific slug - if (isset($metadata[$lang]['slug'])) { - $slug = $metadata[$lang]['slug']; - } elseif (isset($metadata['slug'])) { - $slug = $metadata['slug']; - } - } - - $segments[] = $slug; - $dir .= '/' . $folderName; - } - - $path = '/' . implode('/', $segments); - if ($ctx->hasTrailingSlash) $path .= '/'; - - $urls[$lang] = $lang === $defaultLang ? $path : "/$lang" . $path; - } - - return $urls; -} - -function resolvePath(string $path, string $contentDir): ?array { - $parts = explode('/', trim($path, '/')); - $folders = []; - $dir = $contentDir; - - foreach ($parts as $slug) { - $folderName = resolveSlugToFolder($dir, $slug); - if (!$folderName) return null; - - $folders[] = $folderName; - $dir .= '/' . $folderName; - } - - return $folders; -} - -function buildSimpleUrls(Context $ctx, string $defaultLang, array $availableLangs): array { - $path = '/' . $ctx->requestPath; - if ($ctx->hasTrailingSlash) $path .= '/'; - - return array_reduce($availableLangs, - fn($urls, $lang) => $urls + [$lang => $lang === $defaultLang ? $path : "/$lang" . $path], - []); -}