update data models
This commit is contained in:
@@ -1,7 +1,3 @@
|
||||
# Station Blueprint
|
||||
# Defines a content module/station for the media guide
|
||||
# /user/blueprints/station.yaml
|
||||
|
||||
title: Station
|
||||
'@extends':
|
||||
type: default
|
||||
@@ -14,7 +10,6 @@ form:
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
# Station Info Tab
|
||||
station_info:
|
||||
type: tab
|
||||
title: Station Info
|
||||
@@ -22,10 +17,8 @@ form:
|
||||
header.station_id:
|
||||
type: text
|
||||
label: Station ID
|
||||
help: Unique identifier for this station (used in QR codes)
|
||||
validate:
|
||||
required: true
|
||||
pattern: '^[a-z0-9-]+$'
|
||||
|
||||
header.station_type:
|
||||
type: select
|
||||
@@ -37,11 +30,6 @@ form:
|
||||
navigation: Navigation
|
||||
default: exhibit
|
||||
|
||||
header.exhibition_ref:
|
||||
type: text
|
||||
label: Exhibition Reference
|
||||
help: Reference to parent exhibition
|
||||
|
||||
header.active:
|
||||
type: toggle
|
||||
label: Active
|
||||
@@ -55,127 +43,3 @@ form:
|
||||
type: number
|
||||
label: Display Order
|
||||
default: 0
|
||||
|
||||
# Multilingual Content Tab
|
||||
content_tab:
|
||||
type: tab
|
||||
title: Content
|
||||
fields:
|
||||
header.title:
|
||||
type: multilang
|
||||
label: Title
|
||||
languages: true
|
||||
|
||||
header.description:
|
||||
type: multilang
|
||||
label: Short Description
|
||||
type: textarea
|
||||
languages: true
|
||||
|
||||
# Components Tab
|
||||
components_tab:
|
||||
type: tab
|
||||
title: Components
|
||||
fields:
|
||||
header.components:
|
||||
type: list
|
||||
label: Content Components
|
||||
style: vertical
|
||||
btnLabel: Add Component
|
||||
collapsed: true
|
||||
|
||||
fields:
|
||||
.type:
|
||||
type: select
|
||||
label: Component Type
|
||||
options:
|
||||
heading: Heading
|
||||
text: Text Block
|
||||
video: Video Player
|
||||
audio: Audio Player
|
||||
tabs: Tabbed Content
|
||||
slideshow: Slideshow
|
||||
|
||||
.id:
|
||||
type: text
|
||||
label: Component ID
|
||||
help: Unique ID for this component
|
||||
|
||||
# Heading specific
|
||||
.level:
|
||||
type: select
|
||||
label: Heading Level
|
||||
options:
|
||||
h1: H1
|
||||
h2: H2
|
||||
h3: H3
|
||||
|
||||
# Text/Heading content (multilingual)
|
||||
.content:
|
||||
type: editor
|
||||
label: Content
|
||||
|
||||
# Video specific
|
||||
.video_src:
|
||||
type: filepicker
|
||||
label: Video File
|
||||
folder: 'user://media/videos'
|
||||
accept:
|
||||
- video/*
|
||||
|
||||
.video_poster:
|
||||
type: filepicker
|
||||
label: Video Poster
|
||||
folder: 'user://media/images'
|
||||
accept:
|
||||
- image/*
|
||||
|
||||
# Audio specific
|
||||
.audio_src:
|
||||
type: filepicker
|
||||
label: Audio File
|
||||
folder: 'user://media/audio'
|
||||
accept:
|
||||
- audio/*
|
||||
|
||||
.caption:
|
||||
type: text
|
||||
label: Caption
|
||||
|
||||
# Tabs specific
|
||||
.tabs:
|
||||
type: list
|
||||
label: Tabs
|
||||
fields:
|
||||
.title:
|
||||
type: text
|
||||
label: Tab Title
|
||||
.content:
|
||||
type: editor
|
||||
label: Tab Content
|
||||
|
||||
# Slideshow specific
|
||||
.slides:
|
||||
type: list
|
||||
label: Slides
|
||||
fields:
|
||||
.image:
|
||||
type: filepicker
|
||||
label: Slide Image
|
||||
folder: 'user://media/images'
|
||||
accept:
|
||||
- image/*
|
||||
.caption:
|
||||
type: text
|
||||
label: Slide Caption
|
||||
|
||||
# Media Tab
|
||||
media_tab:
|
||||
type: tab
|
||||
title: Media Files
|
||||
fields:
|
||||
header.media_folder:
|
||||
type: text
|
||||
label: Media Folder
|
||||
help: Folder containing media files for this station
|
||||
placeholder: /media/station-id
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# Grav Site Configuration
|
||||
# /user/config/site.yaml
|
||||
|
||||
title: EU Media Guide CMS
|
||||
default_lang: en
|
||||
|
||||
@@ -10,18 +7,3 @@ author:
|
||||
|
||||
metadata:
|
||||
description: Multilingual Media Guide Content Management System
|
||||
|
||||
taxonomies:
|
||||
- category
|
||||
- tag
|
||||
- exhibition
|
||||
- station_type
|
||||
|
||||
# Custom fields for the media guide
|
||||
mediaguide:
|
||||
exhibitions: []
|
||||
station_types:
|
||||
- intro
|
||||
- exhibit
|
||||
- information
|
||||
- navigation
|
||||
|
||||
@@ -1,73 +1,45 @@
|
||||
# Grav System Configuration
|
||||
# /user/config/system.yaml
|
||||
|
||||
languages:
|
||||
supported:
|
||||
# EU Protocol Order (alphabetical by native name)
|
||||
- bg # български (Bulgarian)
|
||||
- es # español (Spanish)
|
||||
- cs # čeština (Czech)
|
||||
- da # dansk (Danish)
|
||||
- de # Deutsch (German)
|
||||
- et # eesti (Estonian)
|
||||
- el # ελληνικά (Greek)
|
||||
- en # English
|
||||
- fr # français (French)
|
||||
- ga # Gaeilge (Irish)
|
||||
- hr # hrvatski (Croatian)
|
||||
- it # italiano (Italian)
|
||||
- lv # latviešu (Latvian)
|
||||
- lt # lietuvių (Lithuanian)
|
||||
- hu # magyar (Hungarian)
|
||||
- mt # Malti (Maltese)
|
||||
- nl # Nederlands (Dutch)
|
||||
- pl # polski (Polish)
|
||||
- pt # português (Portuguese)
|
||||
- ro # română (Romanian)
|
||||
- sk # slovenčina (Slovak)
|
||||
- sl # slovenščina (Slovenian)
|
||||
- fi # suomi (Finnish)
|
||||
- sv # svenska (Swedish)
|
||||
- bg
|
||||
- cs
|
||||
- da
|
||||
- de
|
||||
- el
|
||||
- en
|
||||
- es
|
||||
- et
|
||||
- fi
|
||||
- fr
|
||||
- ga
|
||||
- hr
|
||||
- hu
|
||||
- it
|
||||
- lt
|
||||
- lv
|
||||
- mt
|
||||
- nl
|
||||
- pl
|
||||
- pt
|
||||
- ro
|
||||
- sk
|
||||
- sl
|
||||
- sv
|
||||
default_lang: en
|
||||
include_default_lang: true
|
||||
translations: true
|
||||
translations_fallback: true
|
||||
session_store_active: false
|
||||
http_accept_language: true
|
||||
override_locale: false
|
||||
|
||||
pages:
|
||||
theme: quark
|
||||
markdown:
|
||||
extra: true
|
||||
types:
|
||||
- txt
|
||||
- xml
|
||||
- html
|
||||
- htm
|
||||
- json
|
||||
- rss
|
||||
- atom
|
||||
|
||||
cache:
|
||||
enabled: false # Disable during development
|
||||
check:
|
||||
method: file
|
||||
driver: auto
|
||||
prefix: 'g'
|
||||
lifetime: 604800
|
||||
|
||||
debugger:
|
||||
enabled: false
|
||||
shutdown:
|
||||
close_connection: true
|
||||
driver: auto
|
||||
|
||||
twig:
|
||||
cache: false # Disable during development
|
||||
cache: false
|
||||
debug: true
|
||||
auto_reload: true
|
||||
autoescape: false
|
||||
|
||||
assets:
|
||||
css_pipeline: false
|
||||
js_pipeline: false
|
||||
|
||||
100
pages/stations/european-concerns/station.md
Normal file
100
pages/stations/european-concerns/station.md
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: European Concerns - Posters
|
||||
station_id: 5a0c1432bcb943c304dae4b7
|
||||
station_type: exhibit
|
||||
active: true
|
||||
order: 2
|
||||
|
||||
title_translations:
|
||||
en: Select a poster to read the message!
|
||||
fr: Faire défiler et sélectionner une affiche
|
||||
de: Blättern Sie und wählen Sie ein Poster
|
||||
nl: Blader en kies een poster
|
||||
it: Sfoglia e seleziona un manifesto
|
||||
es: Hojee y seleccione un cartel
|
||||
pt: Percorra a galeria e seleccione um cartaz
|
||||
bg: Разгледайте и изберете плакат
|
||||
cs: Vyberte si plakát z nabídky
|
||||
da: Bladr og vælg en plakat
|
||||
el: Ξεφυλλίστε και διαλέξτε μία αφίσα
|
||||
et: Lehitse ja vali plakat
|
||||
fi: Selaa ja valitse juliste
|
||||
ga: Féach tríd na postaeir agus roghnaigh ceann
|
||||
hr: Izaberite poster za čitanje poruke!
|
||||
hu: Lapozzon és válasszon ki egy plakátot!
|
||||
lt: Paslinkite kadrus ir pasirinkite plakatą
|
||||
lv: Pāršķirstiet sarakstu un izvēlieties plakātu.
|
||||
mt: Qalleb fil-posters u agħżel wieħed
|
||||
pl: Przewiń listę i wybierz plakat
|
||||
ro: Selectaţi o imagine
|
||||
sk: Listujte a vyberte si plagát
|
||||
sl: Pobrskajte in izberite poster
|
||||
sv: Bläddra och välj en affisch
|
||||
|
||||
description_translations:
|
||||
en: European concerns
|
||||
fr: Les préoccupations des européens
|
||||
de: Europäische Themen
|
||||
nl: Europese kwesties
|
||||
it: Gli affari europei
|
||||
es: Preocupaciones europeas
|
||||
pt: Temas europeus
|
||||
bg: Европейски въпроси
|
||||
cs: Evropská problematika
|
||||
da: Europæiske anliggender
|
||||
el: Προβληματισμοί των Ευρωπαίων
|
||||
et: Euroopa mured
|
||||
fi: Eurooppalaisille tärkeitä asioita
|
||||
ga: Cúiseanna imní don Eoraip
|
||||
hr: Europska pitanja
|
||||
hu: Európai gondok
|
||||
lt: Europos uždaviniai
|
||||
lv: Eiropiešiem svarīgi jautājumi
|
||||
mt: Kwistjonijiet Ewropej
|
||||
pl: Troski Europejczyków
|
||||
ro: Aspecte importante pentru Europa
|
||||
sk: Európske témy
|
||||
sl: Evropska vprašanja
|
||||
sv: Viktiga frågor för EU
|
||||
|
||||
components:
|
||||
- type: heading
|
||||
id: concerns-heading
|
||||
level: h1
|
||||
content:
|
||||
en: European concerns
|
||||
fr: Les préoccupations des européens
|
||||
de: Europäische Themen
|
||||
nl: Europese kwesties
|
||||
it: Gli affari europei
|
||||
es: Preocupaciones europeas
|
||||
|
||||
- type: text
|
||||
id: concerns-intro
|
||||
content:
|
||||
en: <p>Select a poster to read the message and learn about the issues that matter to Europeans.</p>
|
||||
fr: <p>Sélectionnez une affiche pour lire le message et découvrir les sujets qui préoccupent les Européens.</p>
|
||||
de: <p>Wählen Sie ein Poster aus, um die Botschaft zu lesen und mehr über die Themen zu erfahren, die den Europäern wichtig sind.</p>
|
||||
nl: <p>Selecteer een poster om het bericht te lezen en meer te weten te komen over de kwesties die belangrijk zijn voor Europeanen.</p>
|
||||
|
||||
- type: slideshow
|
||||
id: posters-slideshow
|
||||
slides:
|
||||
- image: /images/posters/poster1.jpg
|
||||
caption:
|
||||
en: European concerns poster 1
|
||||
fr: Affiche des préoccupations européennes 1
|
||||
de: Europäische Themen Poster 1
|
||||
- image: /images/posters/poster2.jpg
|
||||
caption:
|
||||
en: European concerns poster 2
|
||||
fr: Affiche des préoccupations européennes 2
|
||||
de: Europäische Themen Poster 2
|
||||
- image: /images/posters/poster3.jpg
|
||||
caption:
|
||||
en: European concerns poster 3
|
||||
fr: Affiche des préoccupations européennes 3
|
||||
de: Europäische Themen Poster 3
|
||||
---
|
||||
|
||||
Interactive poster exhibition about European concerns and issues.
|
||||
100
pages/stations/intro/station.md
Normal file
100
pages/stations/intro/station.md
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: Welcome - Touch to Start
|
||||
station_id: 5a0034ab86c7c57110ae0a43
|
||||
station_type: intro
|
||||
active: true
|
||||
order: 1
|
||||
|
||||
title_translations:
|
||||
en: Please touch here to start
|
||||
fr: Veuillez appuyer ici pour démarrer
|
||||
de: Wiedergabe bitte hier drücken
|
||||
nl: Druk hier om te beginnen
|
||||
it: Premete qui per iniziare
|
||||
es: Pulse aquí para comenzar
|
||||
pt: Por favor toque aqui para começar
|
||||
bg: Моля, докоснете тук, за да започнете
|
||||
cs: Zde stiskněte a spusťte přehrávání
|
||||
da: Tryk venligst her for at starte
|
||||
el: Παρακαλούμε πιέστε εδώ για να ξεκινήσετε
|
||||
et: Alustamiseks vajutage palun siia
|
||||
fi: Aloita koskettamalla tästä
|
||||
ga: Leag do mhéar anseo le tosú
|
||||
hr: Dodirnite ovdje zu početak
|
||||
hu: A kezdéshez nyomja meg ezt a gombot!
|
||||
lt: Jei norite pradėti, palieskite čia
|
||||
lv: Lūdzu, pieskarieties šeit, lai sāktu
|
||||
mt: Jekk jogħġbok agħfas hawn biex tibda
|
||||
pl: Dotknij, aby rozpocząć
|
||||
ro: Pentru a începe vă rugăm să apăsaţi aici
|
||||
sk: Dotykom na tomto mieste sa spustí prehrávanie
|
||||
sl: Za začetek pritisnite tukaj
|
||||
sv: Peka här för att starta
|
||||
|
||||
description_translations:
|
||||
en: Welcome video introduction to the European Parliament
|
||||
fr: Vidéo d'introduction au Parlement européen
|
||||
de: Einführungsvideo zum Europäischen Parlament
|
||||
nl: Introductievideo Europees Parlement
|
||||
it: Video introduttivo al Parlamento europeo
|
||||
es: Vídeo de introducción al Parlamento Europeo
|
||||
|
||||
components:
|
||||
- type: heading
|
||||
id: welcome-heading
|
||||
level: h1
|
||||
content:
|
||||
en: Please touch here to start
|
||||
fr: Veuillez appuyer ici pour démarrer
|
||||
de: Wiedergabe bitte hier drücken
|
||||
nl: Druk hier om te beginnen
|
||||
it: Premete qui per iniziare
|
||||
es: Pulse aquí para comenzar
|
||||
pt: Por favor toque aqui para começar
|
||||
bg: Моля, докоснете тук, за да започнете
|
||||
cs: Zde stiskněte a spusťte přehrávání
|
||||
da: Tryk venligst her for at starte
|
||||
el: Παρακαλούμε πιέστε εδώ για να ξεκινήσετε
|
||||
et: Alustamiseks vajutage palun siia
|
||||
fi: Aloita koskettamalla tästä
|
||||
ga: Leag do mhéar anseo le tosú
|
||||
hr: Dodirnite ovdje zu početak
|
||||
hu: A kezdéshez nyomja meg ezt a gombot!
|
||||
lt: Jei norite pradėti, palieskite čia
|
||||
lv: Lūdzu, pieskarieties šeit, lai sāktu
|
||||
mt: Jekk jogħġbok agħfas hawn biex tibda
|
||||
pl: Dotknij, aby rozpocząć
|
||||
ro: Pentru a începe vă rugăm să apăsaţi aici
|
||||
sk: Dotykom na tomto mieste sa spustí prehrávanie
|
||||
sl: Za začetek pritisnite tukaj
|
||||
sv: Peka här för att starta
|
||||
|
||||
- type: video
|
||||
id: intro-video
|
||||
src:
|
||||
en: /videos/cms_7388676871120926234.mp4
|
||||
bg: /videos/cms_3046071971567520684.mp4
|
||||
cs: /videos/cms_2771914627657443657.mp4
|
||||
da: /videos/cms_1785836764716686675.mp4
|
||||
de: /videos/cms_6408694982373705979.mp4
|
||||
el: /videos/cms_6207215930569761535.mp4
|
||||
es: /videos/cms_1390123522791732069.mp4
|
||||
et: /videos/cms_7268116320585483033.mp4
|
||||
fi: /videos/cms_340857536848363735.mp4
|
||||
fr: /videos/cms_766311708362015941.mp4
|
||||
ga: /videos/cms_157201896609093943.mp4
|
||||
hu: /videos/cms_1664578063593428062.mp4
|
||||
it: /videos/cms_8746182921133737875.mp4
|
||||
pl: /videos/cms_3435441211807278988.mp4
|
||||
pt: /videos/cms_8781957532829411669.mp4
|
||||
poster: /images/video-poster.jpg
|
||||
caption:
|
||||
en: Welcome to the European Parliament
|
||||
fr: Bienvenue au Parlement européen
|
||||
de: Willkommen im Europäischen Parlament
|
||||
nl: Welkom bij het Europees Parlement
|
||||
it: Benvenuti al Parlamento europeo
|
||||
es: Bienvenidos al Parlamento Europeo
|
||||
---
|
||||
|
||||
Welcome video content - Introduction to the European Parliament visitor center.
|
||||
@@ -4,7 +4,4 @@ description: Exports Grav content to JSON format for the React media guide app
|
||||
icon: file-code
|
||||
author:
|
||||
name: Media Guide Team
|
||||
homepage: https://github.com/your-org/mediaguide
|
||||
keywords: json, export, api, multilingual
|
||||
bugs: https://github.com/your-org/mediaguide/issues
|
||||
license: MIT
|
||||
|
||||
@@ -2,15 +2,7 @@
|
||||
namespace Grav\Plugin;
|
||||
|
||||
use Grav\Common\Plugin;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use Grav\Common\Page\Page;
|
||||
use Grav\Common\Grav;
|
||||
|
||||
/**
|
||||
* JSON Export Plugin
|
||||
*
|
||||
* Exports content from Grav CMS to JSON format for the React media guide app
|
||||
*/
|
||||
class JsonExportPlugin extends Plugin
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
@@ -22,14 +14,10 @@ class JsonExportPlugin extends Plugin
|
||||
|
||||
public function onPluginsInitialized()
|
||||
{
|
||||
// Check if we're in admin context
|
||||
if ($this->isAdmin()) {
|
||||
$this->enable([
|
||||
'onAdminTaskExecute' => ['onAdminTaskExecute', 0]
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable API endpoint
|
||||
$this->enable([
|
||||
'onPagesInitialized' => ['onPagesInitialized', 0]
|
||||
]);
|
||||
@@ -38,31 +26,24 @@ class JsonExportPlugin extends Plugin
|
||||
public function onPagesInitialized()
|
||||
{
|
||||
$uri = $this->grav['uri'];
|
||||
|
||||
// API endpoints
|
||||
if (strpos($uri->path(), '/api/') === 0) {
|
||||
$this->handleApiRequest($uri);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleApiRequest($uri)
|
||||
{
|
||||
$path = $uri->path();
|
||||
$lang = $uri->param('lang') ?? 'en';
|
||||
|
||||
if (strpos($path, '/api/') !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lang = $_GET['lang'] ?? 'en';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
// GET /api/stations - List all stations
|
||||
if ($path === '/api/stations') {
|
||||
echo json_encode($this->getStationsList($lang), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// GET /api/station/{id} - Get single station
|
||||
if (preg_match('#^/api/station/([a-z0-9-]+)$#', $path, $matches)) {
|
||||
$stationId = $matches[1];
|
||||
$station = $this->getStation($stationId, $lang);
|
||||
if (preg_match('#^/api/station/([a-zA-Z0-9-]+)$#', $path, $matches)) {
|
||||
$station = $this->getStation($matches[1], $lang);
|
||||
if ($station) {
|
||||
echo json_encode($station, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
@@ -72,18 +53,10 @@ class JsonExportPlugin extends Plugin
|
||||
exit;
|
||||
}
|
||||
|
||||
// GET /api/translations - Get UI translations
|
||||
if ($path === '/api/translations') {
|
||||
echo json_encode($this->getTranslations($lang), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// GET /api/export - Export all content to JSON files
|
||||
if ($path === '/api/export') {
|
||||
$result = $this->exportAllToJson();
|
||||
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
private function getStationsList($lang)
|
||||
@@ -92,22 +65,21 @@ class JsonExportPlugin extends Plugin
|
||||
$stations = [];
|
||||
|
||||
foreach ($pages->all() as $page) {
|
||||
if ($page->template() === 'station' && $page->header()->active) {
|
||||
if ($page->template() === 'station') {
|
||||
$header = $page->header();
|
||||
if (!($header->active ?? true)) continue;
|
||||
|
||||
$stations[] = [
|
||||
'id' => $header->station_id ?? $page->slug(),
|
||||
'type' => $header->station_type ?? 'exhibit',
|
||||
'title' => $this->getTranslatedField($header->title_translations ?? [], $lang),
|
||||
'description' => $this->getTranslatedField($header->description_translations ?? [], $lang),
|
||||
'order' => $header->order ?? 0,
|
||||
'active' => $header->active ?? true
|
||||
'title' => $this->getTranslated($header->title_translations ?? [], $lang),
|
||||
'description' => $this->getTranslated($header->description_translations ?? [], $lang),
|
||||
'order' => $header->order ?? 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by order
|
||||
usort($stations, fn($a, $b) => $a['order'] <=> $b['order']);
|
||||
|
||||
return $stations;
|
||||
}
|
||||
|
||||
@@ -121,15 +93,14 @@ class JsonExportPlugin extends Plugin
|
||||
$id = $header->station_id ?? $page->slug();
|
||||
|
||||
if ($id === $stationId) {
|
||||
return $this->formatStationForLang($page, $lang);
|
||||
return $this->formatStation($page, $lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function formatStationForLang($page, $lang)
|
||||
private function formatStation($page, $lang)
|
||||
{
|
||||
$header = $page->header();
|
||||
|
||||
@@ -137,204 +108,155 @@ class JsonExportPlugin extends Plugin
|
||||
'id' => $header->station_id ?? $page->slug(),
|
||||
'type' => $header->station_type ?? 'exhibit',
|
||||
'language' => $lang,
|
||||
'title' => $this->getTranslatedField($header->title_translations ?? [], $lang),
|
||||
'description' => $this->getTranslatedField($header->description_translations ?? [], $lang),
|
||||
'title' => $this->getTranslated($header->title_translations ?? [], $lang),
|
||||
'description' => $this->getTranslated($header->description_translations ?? [], $lang),
|
||||
'components' => []
|
||||
];
|
||||
|
||||
// Process components
|
||||
if (isset($header->components) && is_array($header->components)) {
|
||||
foreach ($header->components as $component) {
|
||||
$station['components'][] = $this->formatComponent($component, $lang);
|
||||
foreach ($header->components as $comp) {
|
||||
$station['components'][] = $this->formatComponent($comp, $lang);
|
||||
}
|
||||
}
|
||||
|
||||
return $station;
|
||||
}
|
||||
|
||||
private function formatComponent($component, $lang)
|
||||
private function formatComponent($comp, $lang)
|
||||
{
|
||||
$formatted = [
|
||||
'id' => $component['id'] ?? uniqid(),
|
||||
'type' => $component['type'] ?? 'text'
|
||||
$out = [
|
||||
'id' => $comp['id'] ?? uniqid(),
|
||||
'type' => $comp['type'] ?? 'text'
|
||||
];
|
||||
|
||||
switch ($component['type']) {
|
||||
switch ($comp['type']) {
|
||||
case 'heading':
|
||||
$formatted['level'] = $component['level'] ?? 'h2';
|
||||
$formatted['content'] = $this->getTranslatedField($component['content'] ?? [], $lang);
|
||||
$out['level'] = $comp['level'] ?? 'h2';
|
||||
$out['content'] = $this->getTranslated($comp['content'] ?? [], $lang);
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
$formatted['content'] = $this->getTranslatedField($component['content'] ?? [], $lang);
|
||||
$out['content'] = $this->getTranslated($comp['content'] ?? [], $lang);
|
||||
break;
|
||||
|
||||
case 'video':
|
||||
$formatted['src'] = $this->getTranslatedField($component['src'] ?? [], $lang);
|
||||
$formatted['poster'] = $component['poster'] ?? null;
|
||||
$formatted['caption'] = $this->getTranslatedField($component['caption'] ?? [], $lang);
|
||||
$out['src'] = $this->getTranslated($comp['src'] ?? [], $lang);
|
||||
$out['poster'] = $comp['poster'] ?? null;
|
||||
$out['caption'] = $this->getTranslated($comp['caption'] ?? [], $lang);
|
||||
break;
|
||||
|
||||
case 'audio':
|
||||
$formatted['src'] = $this->getTranslatedField($component['src'] ?? [], $lang);
|
||||
$formatted['caption'] = $this->getTranslatedField($component['caption'] ?? [], $lang);
|
||||
$out['src'] = $this->getTranslated($comp['src'] ?? [], $lang);
|
||||
$out['caption'] = $this->getTranslated($comp['caption'] ?? [], $lang);
|
||||
break;
|
||||
|
||||
case 'tabs':
|
||||
$formatted['tabs'] = [];
|
||||
if (isset($component['tabs']) && is_array($component['tabs'])) {
|
||||
foreach ($component['tabs'] as $tab) {
|
||||
$formatted['tabs'][] = [
|
||||
'title' => $this->getTranslatedField($tab['title'] ?? [], $lang),
|
||||
'content' => $this->getTranslatedField($tab['content'] ?? [], $lang)
|
||||
];
|
||||
}
|
||||
$out['tabs'] = [];
|
||||
foreach ($comp['tabs'] ?? [] as $tab) {
|
||||
$out['tabs'][] = [
|
||||
'title' => $this->getTranslated($tab['title'] ?? [], $lang),
|
||||
'content' => $this->getTranslated($tab['content'] ?? [], $lang)
|
||||
];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'slideshow':
|
||||
$formatted['slides'] = [];
|
||||
if (isset($component['slides']) && is_array($component['slides'])) {
|
||||
foreach ($component['slides'] as $slide) {
|
||||
$formatted['slides'][] = [
|
||||
'image' => $slide['image'] ?? '',
|
||||
'caption' => $this->getTranslatedField($slide['caption'] ?? [], $lang)
|
||||
];
|
||||
}
|
||||
$out['slides'] = [];
|
||||
foreach ($comp['slides'] ?? [] as $slide) {
|
||||
$out['slides'][] = [
|
||||
'image' => $slide['image'] ?? '',
|
||||
'caption' => $this->getTranslated($slide['caption'] ?? [], $lang)
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function getTranslatedField($field, $lang, $fallback = 'en')
|
||||
private function getTranslated($field, $lang)
|
||||
{
|
||||
if (is_string($field)) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
if (is_array($field)) {
|
||||
return $field[$lang] ?? $field[$fallback] ?? reset($field) ?: '';
|
||||
}
|
||||
|
||||
return '';
|
||||
if (is_string($field)) return $field;
|
||||
return $field[$lang] ?? $field['en'] ?? reset($field) ?: '';
|
||||
}
|
||||
|
||||
private function getTranslations($lang)
|
||||
{
|
||||
// UI translations - these should be stored in config or separate files
|
||||
$translations = [
|
||||
$t = [
|
||||
'en' => [
|
||||
'appTitle' => 'EU Media Guide',
|
||||
'scanQR' => 'Scan QR',
|
||||
'scanQR' => 'Scan QR Code',
|
||||
'selectLanguage' => 'Select Language',
|
||||
'contentLibrary' => 'Content Library',
|
||||
'noContent' => 'Scan a QR code or select content from the menu',
|
||||
'errorLoading' => 'Failed to load content. Please try again.',
|
||||
'playAudio' => 'Play Audio',
|
||||
'pauseAudio' => 'Pause Audio',
|
||||
'loading' => 'Loading...',
|
||||
'play' => 'Play',
|
||||
'pause' => 'Pause',
|
||||
'next' => 'Next',
|
||||
'previous' => 'Previous',
|
||||
'closeMenu' => 'Close Menu',
|
||||
'openMenu' => 'Open Menu',
|
||||
'loading' => 'Loading...'
|
||||
'menu' => 'Menu',
|
||||
'close' => 'Close'
|
||||
],
|
||||
'fr' => [
|
||||
'appTitle' => 'Guide Média UE',
|
||||
'scanQR' => 'Scanner QR',
|
||||
'scanQR' => 'Scanner le code QR',
|
||||
'selectLanguage' => 'Choisir la langue',
|
||||
'contentLibrary' => 'Bibliothèque de contenu',
|
||||
'noContent' => 'Scannez un code QR ou sélectionnez du contenu dans le menu',
|
||||
'errorLoading' => 'Échec du chargement. Veuillez réessayer.',
|
||||
'playAudio' => 'Lire l\'audio',
|
||||
'pauseAudio' => 'Pause audio',
|
||||
'contentLibrary' => 'Bibliothèque',
|
||||
'loading' => 'Chargement...',
|
||||
'play' => 'Lecture',
|
||||
'pause' => 'Pause',
|
||||
'next' => 'Suivant',
|
||||
'previous' => 'Précédent',
|
||||
'closeMenu' => 'Fermer le menu',
|
||||
'openMenu' => 'Ouvrir le menu',
|
||||
'loading' => 'Chargement...'
|
||||
'menu' => 'Menu',
|
||||
'close' => 'Fermer'
|
||||
],
|
||||
'de' => [
|
||||
'appTitle' => 'EU Media Guide',
|
||||
'scanQR' => 'QR scannen',
|
||||
'appTitle' => 'EU Medienführer',
|
||||
'scanQR' => 'QR-Code scannen',
|
||||
'selectLanguage' => 'Sprache wählen',
|
||||
'contentLibrary' => 'Inhaltsbibliothek',
|
||||
'noContent' => 'Scannen Sie einen QR-Code oder wählen Sie Inhalte aus dem Menü',
|
||||
'errorLoading' => 'Laden fehlgeschlagen. Bitte versuchen Sie es erneut.',
|
||||
'playAudio' => 'Audio abspielen',
|
||||
'pauseAudio' => 'Audio pausieren',
|
||||
'loading' => 'Laden...',
|
||||
'play' => 'Abspielen',
|
||||
'pause' => 'Pause',
|
||||
'next' => 'Weiter',
|
||||
'previous' => 'Zurück',
|
||||
'closeMenu' => 'Menü schließen',
|
||||
'openMenu' => 'Menü öffnen',
|
||||
'loading' => 'Laden...'
|
||||
'menu' => 'Menü',
|
||||
'close' => 'Schließen'
|
||||
],
|
||||
'nl' => [
|
||||
'appTitle' => 'EU Media Gids',
|
||||
'scanQR' => 'QR scannen',
|
||||
'appTitle' => 'EU Mediagids',
|
||||
'scanQR' => 'QR-code scannen',
|
||||
'selectLanguage' => 'Taal selecteren',
|
||||
'contentLibrary' => 'Inhoudsbibliotheek',
|
||||
'noContent' => 'Scan een QR-code of selecteer inhoud uit het menu',
|
||||
'errorLoading' => 'Laden mislukt. Probeer het opnieuw.',
|
||||
'playAudio' => 'Audio afspelen',
|
||||
'pauseAudio' => 'Audio pauzeren',
|
||||
'loading' => 'Laden...',
|
||||
'play' => 'Afspelen',
|
||||
'pause' => 'Pauze',
|
||||
'next' => 'Volgende',
|
||||
'previous' => 'Vorige',
|
||||
'closeMenu' => 'Menu sluiten',
|
||||
'openMenu' => 'Menu openen',
|
||||
'loading' => 'Laden...'
|
||||
'menu' => 'Menu',
|
||||
'close' => 'Sluiten'
|
||||
],
|
||||
'it' => [
|
||||
'appTitle' => 'Guida Media UE',
|
||||
'scanQR' => 'Scansiona codice QR',
|
||||
'selectLanguage' => 'Seleziona lingua',
|
||||
'contentLibrary' => 'Libreria contenuti',
|
||||
'loading' => 'Caricamento...',
|
||||
'play' => 'Riproduci',
|
||||
'pause' => 'Pausa',
|
||||
'next' => 'Successivo',
|
||||
'previous' => 'Precedente',
|
||||
'menu' => 'Menu',
|
||||
'close' => 'Chiudi'
|
||||
],
|
||||
'es' => [
|
||||
'appTitle' => 'Guía de Medios UE',
|
||||
'scanQR' => 'Escanear código QR',
|
||||
'selectLanguage' => 'Seleccionar idioma',
|
||||
'contentLibrary' => 'Biblioteca de contenido',
|
||||
'loading' => 'Cargando...',
|
||||
'play' => 'Reproducir',
|
||||
'pause' => 'Pausa',
|
||||
'next' => 'Siguiente',
|
||||
'previous' => 'Anterior',
|
||||
'menu' => 'Menú',
|
||||
'close' => 'Cerrar'
|
||||
]
|
||||
// Add more languages as needed
|
||||
];
|
||||
|
||||
return $translations[$lang] ?? $translations['en'];
|
||||
}
|
||||
|
||||
private function exportAllToJson()
|
||||
{
|
||||
$exportPath = $this->grav['locator']->findResource('user://') . '/export/';
|
||||
|
||||
if (!is_dir($exportPath)) {
|
||||
mkdir($exportPath, 0755, true);
|
||||
}
|
||||
|
||||
$languages = $this->grav['config']->get('system.languages.supported', ['en']);
|
||||
$exported = [];
|
||||
|
||||
foreach ($languages as $lang) {
|
||||
// Export stations
|
||||
$stations = $this->getStationsList($lang);
|
||||
file_put_contents(
|
||||
$exportPath . "stations.{$lang}.json",
|
||||
json_encode($stations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
|
||||
// Export each station content
|
||||
foreach ($stations as $station) {
|
||||
$content = $this->getStation($station['id'], $lang);
|
||||
if ($content) {
|
||||
file_put_contents(
|
||||
$exportPath . "{$station['id']}.{$lang}.json",
|
||||
json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Export translations
|
||||
$translations = $this->getTranslations($lang);
|
||||
file_put_contents(
|
||||
$exportPath . "translations.{$lang}.json",
|
||||
json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
|
||||
$exported[] = $lang;
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'exported_languages' => $exported,
|
||||
'path' => $exportPath
|
||||
];
|
||||
return $t[$lang] ?? $t['en'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ description: Exports Grav content to JSON format for the React media guide app
|
||||
icon: file-code
|
||||
author:
|
||||
name: Media Guide Team
|
||||
homepage: https://github.com/your-org/mediaguide
|
||||
keywords: json, export, api, multilingual
|
||||
bugs: https://github.com/your-org/mediaguide/issues
|
||||
license: MIT
|
||||
|
||||
form:
|
||||
|
||||
Reference in New Issue
Block a user