append('limits'); $packageArray = $package->toArray(); $features = $packageArray['features'] ?? []; $features = $this->normaliseFeatures($features); $watermarkRemovalAllowed = in_array('no_watermark', $features, true) || in_array('watermark_removal', $features, true); $watermarkPolicy = $watermarkRemovalAllowed ? 'none' : 'basic'; $locale = app()->getLocale(); $name = $this->resolveTranslation($package->name_translations ?? null, $package->name ?? '', $locale); $descriptionTemplate = $this->resolveTranslation($package->description_translations ?? null, $package->description ?? '', $locale); $replacements = $this->buildPlaceholderReplacements($package); $description = trim($this->applyPlaceholders($descriptionTemplate, $replacements)); $table = $package->description_table ?? []; if (is_string($table)) { $decoded = json_decode($table, true); $table = is_array($decoded) ? $decoded : []; } $table = array_map(function (array $row) use ($replacements) { return [ 'title' => trim($this->applyPlaceholders($row['title'] ?? '', $replacements)), 'value' => trim($this->applyPlaceholders($row['value'] ?? '', $replacements)), ]; }, $table); $table = array_values($table); $galleryDuration = $replacements['{{gallery_duration}}'] ?? null; return [ 'id' => $package->id, 'name' => $name, 'slug' => $package->slug, 'type' => $package->type, 'included_package_slug' => $package->included_package_slug, 'price' => $package->price, 'paddle_product_id' => $package->paddle_product_id, 'paddle_price_id' => $package->paddle_price_id, 'description' => $description, 'description_breakdown' => $table, 'gallery_duration_label' => $galleryDuration, 'events' => $package->type === 'endcustomer' ? 1 : ($package->max_events_per_year ?? null), 'features' => $features, 'watermark_policy' => $watermarkPolicy, 'limits' => $package->limits, 'max_photos' => $package->max_photos, 'max_guests' => $package->max_guests, 'max_tasks' => $package->max_tasks, 'gallery_days' => $package->gallery_days, 'max_events_per_year' => $package->max_events_per_year, 'watermark_allowed' => (bool) $package->watermark_allowed, 'branding_allowed' => (bool) $package->branding_allowed, 'activates_immediately' => (bool) ($package->activates_immediately ?? true), ]; } protected function buildPlaceholderReplacements(Package $package): array { $locale = app()->getLocale(); return [ '{{max_photos}}' => $this->formatCount($package->max_photos, [ 'de' => 'unbegrenzt viele', 'en' => 'unlimited', ]), '{{max_guests}}' => $this->formatCount($package->max_guests, [ 'de' => 'beliebig viele', 'en' => 'any number of', ]), '{{max_tasks}}' => $this->formatCount($package->max_tasks, [ 'de' => 'individuelle', 'en' => 'custom', ]), '{{max_events_per_year}}' => $this->formatCount($package->max_events_per_year, [ 'de' => 'unbegrenzte', 'en' => 'unlimited', ]), '{{gallery_duration}}' => $this->formatGalleryDuration($package->gallery_days), ]; } protected function applyPlaceholders(string $template, array $replacements): string { if ($template === '') { return $template; } return str_replace(array_keys($replacements), array_values($replacements), $template); } protected function formatCount(?int $value, array $fallbackByLocale): string { $locale = app()->getLocale(); if ($value === null) { return $fallbackByLocale[$locale] ?? reset($fallbackByLocale) ?? ''; } $decimal = $locale === 'de' ? ',' : '.'; $thousands = $locale === 'de' ? '.' : ','; return number_format($value, 0, $decimal, $thousands); } protected function formatGalleryDuration(?int $days): string { $locale = app()->getLocale(); if (! $days || $days <= 0) { return $locale === 'en' ? 'permanent' : 'dauerhaft'; } if ($days % 30 === 0) { $months = (int) ($days / 30); if ($locale === 'en') { return $months === 1 ? '1 month' : $months.' months'; } return $months === 1 ? '1 Monat' : $months.' Monate'; } return $locale === 'en' ? $days.' days' : $days.' Tage'; } protected function normaliseFeatures(mixed $features): array { if (is_string($features)) { $decoded = json_decode($features, true); if (json_last_error() === JSON_ERROR_NONE) { $features = $decoded; } } if (! is_array($features)) { return []; } $list = []; foreach ($features as $key => $value) { if (is_string($value)) { $list[] = $value; continue; } if (is_string($key) && (bool) $value) { $list[] = $key; } } return array_values(array_unique(array_filter($list, fn ($item) => is_string($item) && $item !== ''))); } protected function resolveTranslation(mixed $value, string $fallback, string $locale): string { if (is_string($value)) { $decoded = json_decode($value, true); if (json_last_error() === JSON_ERROR_NONE) { $value = $decoded; } } if (is_array($value)) { return trim((string) ($value[$locale] ?? $value['en'] ?? $value['de'] ?? $fallback)); } return trim((string) ($value ?? $fallback)); } }