diff --git a/frontend/js/i18n/de.js b/frontend/js/i18n/de.js index d401a30..8e0435b 100644 --- a/frontend/js/i18n/de.js +++ b/frontend/js/i18n/de.js @@ -625,4 +625,66 @@ export default { 'designer.toast.export_failed': 'Export fehlgeschlagen: {error}', 'designer.toast.loaded': 'Design geladen', 'designer.toast.invalid_file': 'Ungültige Design-Datei', + + // Playlists + 'playlist.title': 'Playlists', + 'playlist.subtitle': 'Erstellen und verwalten Sie Inhaltslisten', + 'playlist.show_auto_generated': 'Auto-generierte anzeigen', + 'playlist.new_playlist_btn': '+ Neue Playlist', + 'playlist.new_playlist': 'Neue Playlist', + 'playlist.empty_title': 'Noch keine Playlists', + 'playlist.empty_desc': 'Erstellen Sie Ihre erste Playlist, um Inhalte für Ihre Bildschirme zu organisieren.', + 'playlist.all_auto_generated': 'Alle Playlists sind auto-generiert. Aktivieren Sie „Auto-generierte anzeigen", um sie zu sehen.', + 'playlist.tag_auto': 'auto', + 'playlist.tag_draft': 'Entwurf', + 'playlist.item_count_one': '1 Element', + 'playlist.item_count_other': '{n} Elemente', + 'playlist.created_at': 'Erstellt {date}', + 'playlist.display_count_one': '1 Bildschirm', + 'playlist.display_count_other': '{n} Bildschirme', + 'playlist.assigned_to_one': 'Zugewiesen an 1 Bildschirm', + 'playlist.assigned_to_other': 'Zugewiesen an {n} Bildschirme', + 'playlist.load_failed': 'Playlists konnten nicht geladen werden: {error}', + 'playlist.back_to_playlists': 'Zurück zu Playlists', + 'playlist.name_placeholder': 'Playlist-Name', + 'playlist.desc_placeholder': 'Beschreibung (optional)', + 'playlist.create_btn': 'Erstellen', + 'playlist.add_desc_placeholder': 'Beschreibung hinzufügen...', + 'playlist.click_to_rename': 'Klicken zum Umbenennen', + 'playlist.click_to_edit_desc': 'Klicken zum Bearbeiten der Beschreibung', + 'playlist.add_content': '+ Inhalt hinzufügen', + 'playlist.delete_playlist': 'Playlist löschen', + 'playlist.back': 'Zurück', + 'playlist.items_empty': 'Diese Playlist ist leer', + 'playlist.items_empty_hint': 'Klicken Sie auf „Inhalt hinzufügen", um Elemente hinzuzufügen.', + 'playlist.duration': 'Dauer', + 'playlist.sec': 'Sek', + 'playlist.move_up': 'Nach oben', + 'playlist.move_down': 'Nach unten', + 'playlist.remove_item': 'Element entfernen', + 'playlist.item_widget': 'Widget', + 'playlist.unknown_type': 'Unbekannter Typ', + 'playlist.confirm_delete': '„{name}" löschen? Dies kann nicht rückgängig gemacht werden.', + 'playlist.confirm_discard_draft': 'Alle nicht veröffentlichten Änderungen verwerfen und zur letzten veröffentlichten Version zurückkehren?', + 'playlist.draft.banner_title': 'Unveröffentlichte Änderungen', + 'playlist.draft.devices_showing_published': 'Geräte zeigen weiterhin die zuletzt veröffentlichte Version.', + 'playlist.draft.never_published': 'Diese Playlist wurde noch nie veröffentlicht. Geräte zeigen nichts an, bis Sie veröffentlichen.', + 'playlist.draft.discard_changes': 'Änderungen verwerfen', + 'playlist.draft.publish': 'Veröffentlichen', + 'playlist.draft.publishing': 'Wird veröffentlicht...', + 'playlist.toast.created': 'Playlist erstellt', + 'playlist.toast.deleted': 'Playlist gelöscht', + 'playlist.toast.published': 'Playlist veröffentlicht — Geräte aktualisiert', + 'playlist.toast.draft_discarded': 'Entwurfsänderungen verworfen', + 'playlist.toast.item_removed': 'Element entfernt', + 'playlist.add_modal_title': 'Inhalt zur Playlist hinzufügen', + 'playlist.tab_content': 'Inhalt', + 'playlist.tab_widgets': 'Widgets', + 'playlist.search_placeholder': 'Suchen...', + 'playlist.close': 'Schließen', + 'playlist.no_content_found': 'Kein Inhalt gefunden', + 'playlist.no_widgets_found': 'Keine Widgets gefunden', + 'playlist.add_btn': 'Hinzufügen', + 'playlist.adding': 'Wird hinzugefügt...', + 'playlist.added': 'Hinzugefügt', }; diff --git a/frontend/js/i18n/en.js b/frontend/js/i18n/en.js index 1839253..086c260 100644 --- a/frontend/js/i18n/en.js +++ b/frontend/js/i18n/en.js @@ -661,4 +661,66 @@ export default { 'designer.toast.export_failed': 'Export failed: {error}', 'designer.toast.loaded': 'Design loaded', 'designer.toast.invalid_file': 'Invalid design file', + + // Playlists + 'playlist.title': 'Playlists', + 'playlist.subtitle': 'Create and manage content playlists', + 'playlist.show_auto_generated': 'Show auto-generated', + 'playlist.new_playlist_btn': '+ New Playlist', + 'playlist.new_playlist': 'New Playlist', + 'playlist.empty_title': 'No playlists yet', + 'playlist.empty_desc': 'Create your first playlist to organize content for your displays.', + 'playlist.all_auto_generated': 'All playlists are auto-generated. Toggle "Show auto-generated" to see them.', + 'playlist.tag_auto': 'auto', + 'playlist.tag_draft': 'draft', + 'playlist.item_count_one': '1 item', + 'playlist.item_count_other': '{n} items', + 'playlist.created_at': 'Created {date}', + 'playlist.display_count_one': '1 display', + 'playlist.display_count_other': '{n} displays', + 'playlist.assigned_to_one': 'Assigned to 1 display', + 'playlist.assigned_to_other': 'Assigned to {n} displays', + 'playlist.load_failed': 'Failed to load playlists: {error}', + 'playlist.back_to_playlists': 'Back to Playlists', + 'playlist.name_placeholder': 'Playlist name', + 'playlist.desc_placeholder': 'Description (optional)', + 'playlist.create_btn': 'Create', + 'playlist.add_desc_placeholder': 'Add a description...', + 'playlist.click_to_rename': 'Click to rename', + 'playlist.click_to_edit_desc': 'Click to edit description', + 'playlist.add_content': '+ Add Content', + 'playlist.delete_playlist': 'Delete Playlist', + 'playlist.back': 'Back', + 'playlist.items_empty': 'This playlist is empty', + 'playlist.items_empty_hint': 'Click "Add Content" to add items.', + 'playlist.duration': 'Duration', + 'playlist.sec': 'sec', + 'playlist.move_up': 'Move up', + 'playlist.move_down': 'Move down', + 'playlist.remove_item': 'Remove item', + 'playlist.item_widget': 'Widget', + 'playlist.unknown_type': 'Unknown type', + 'playlist.confirm_delete': 'Delete "{name}"? This cannot be undone.', + 'playlist.confirm_discard_draft': 'Discard all unpublished changes and revert to the last published version?', + 'playlist.draft.banner_title': 'Unpublished changes', + 'playlist.draft.devices_showing_published': 'Devices are still showing the last published version.', + 'playlist.draft.never_published': 'This playlist has never been published. Devices will show nothing until you publish.', + 'playlist.draft.discard_changes': 'Discard Changes', + 'playlist.draft.publish': 'Publish', + 'playlist.draft.publishing': 'Publishing...', + 'playlist.toast.created': 'Playlist created', + 'playlist.toast.deleted': 'Playlist deleted', + 'playlist.toast.published': 'Playlist published — devices updated', + 'playlist.toast.draft_discarded': 'Draft changes discarded', + 'playlist.toast.item_removed': 'Item removed', + 'playlist.add_modal_title': 'Add Content to Playlist', + 'playlist.tab_content': 'Content', + 'playlist.tab_widgets': 'Widgets', + 'playlist.search_placeholder': 'Search...', + 'playlist.close': 'Close', + 'playlist.no_content_found': 'No content found', + 'playlist.no_widgets_found': 'No widgets found', + 'playlist.add_btn': 'Add', + 'playlist.adding': 'Adding...', + 'playlist.added': 'Added', }; diff --git a/frontend/js/i18n/es.js b/frontend/js/i18n/es.js index f085d54..dd98800 100644 --- a/frontend/js/i18n/es.js +++ b/frontend/js/i18n/es.js @@ -624,4 +624,66 @@ export default { 'designer.toast.export_failed': 'Falló la exportación: {error}', 'designer.toast.loaded': 'Diseño cargado', 'designer.toast.invalid_file': 'Archivo de diseño no válido', + + // Playlists + 'playlist.title': 'Listas de reproducción', + 'playlist.subtitle': 'Crea y gestiona listas de contenido', + 'playlist.show_auto_generated': 'Mostrar autogeneradas', + 'playlist.new_playlist_btn': '+ Nueva lista', + 'playlist.new_playlist': 'Nueva lista', + 'playlist.empty_title': 'Aún no hay listas', + 'playlist.empty_desc': 'Crea tu primera lista para organizar contenido para tus pantallas.', + 'playlist.all_auto_generated': 'Todas las listas son autogeneradas. Activa "Mostrar autogeneradas" para verlas.', + 'playlist.tag_auto': 'auto', + 'playlist.tag_draft': 'borrador', + 'playlist.item_count_one': '1 elemento', + 'playlist.item_count_other': '{n} elementos', + 'playlist.created_at': 'Creado {date}', + 'playlist.display_count_one': '1 pantalla', + 'playlist.display_count_other': '{n} pantallas', + 'playlist.assigned_to_one': 'Asignada a 1 pantalla', + 'playlist.assigned_to_other': 'Asignada a {n} pantallas', + 'playlist.load_failed': 'Error al cargar las listas: {error}', + 'playlist.back_to_playlists': 'Volver a listas', + 'playlist.name_placeholder': 'Nombre de la lista', + 'playlist.desc_placeholder': 'Descripción (opcional)', + 'playlist.create_btn': 'Crear', + 'playlist.add_desc_placeholder': 'Agregar una descripción...', + 'playlist.click_to_rename': 'Clic para renombrar', + 'playlist.click_to_edit_desc': 'Clic para editar descripción', + 'playlist.add_content': '+ Agregar contenido', + 'playlist.delete_playlist': 'Eliminar lista', + 'playlist.back': 'Atrás', + 'playlist.items_empty': 'Esta lista está vacía', + 'playlist.items_empty_hint': 'Haz clic en "Agregar contenido" para añadir elementos.', + 'playlist.duration': 'Duración', + 'playlist.sec': 'seg', + 'playlist.move_up': 'Subir', + 'playlist.move_down': 'Bajar', + 'playlist.remove_item': 'Quitar elemento', + 'playlist.item_widget': 'Widget', + 'playlist.unknown_type': 'Tipo desconocido', + 'playlist.confirm_delete': '¿Eliminar "{name}"? Esto no se puede deshacer.', + 'playlist.confirm_discard_draft': '¿Descartar todos los cambios no publicados y volver a la última versión publicada?', + 'playlist.draft.banner_title': 'Cambios sin publicar', + 'playlist.draft.devices_showing_published': 'Los dispositivos siguen mostrando la última versión publicada.', + 'playlist.draft.never_published': 'Esta lista nunca se ha publicado. Los dispositivos no mostrarán nada hasta que la publiques.', + 'playlist.draft.discard_changes': 'Descartar cambios', + 'playlist.draft.publish': 'Publicar', + 'playlist.draft.publishing': 'Publicando...', + 'playlist.toast.created': 'Lista creada', + 'playlist.toast.deleted': 'Lista eliminada', + 'playlist.toast.published': 'Lista publicada — dispositivos actualizados', + 'playlist.toast.draft_discarded': 'Cambios del borrador descartados', + 'playlist.toast.item_removed': 'Elemento eliminado', + 'playlist.add_modal_title': 'Agregar contenido a la lista', + 'playlist.tab_content': 'Contenido', + 'playlist.tab_widgets': 'Widgets', + 'playlist.search_placeholder': 'Buscar...', + 'playlist.close': 'Cerrar', + 'playlist.no_content_found': 'No se encontró contenido', + 'playlist.no_widgets_found': 'No se encontraron widgets', + 'playlist.add_btn': 'Agregar', + 'playlist.adding': 'Agregando...', + 'playlist.added': 'Agregado', }; diff --git a/frontend/js/i18n/fr.js b/frontend/js/i18n/fr.js index 38d039b..c0175ab 100644 --- a/frontend/js/i18n/fr.js +++ b/frontend/js/i18n/fr.js @@ -625,4 +625,66 @@ export default { 'designer.toast.export_failed': 'Échec de l\'export : {error}', 'designer.toast.loaded': 'Design chargé', 'designer.toast.invalid_file': 'Fichier de design invalide', + + // Playlists + 'playlist.title': 'Listes de lecture', + 'playlist.subtitle': 'Créez et gérez des listes de contenu', + 'playlist.show_auto_generated': 'Afficher les listes auto', + 'playlist.new_playlist_btn': '+ Nouvelle liste', + 'playlist.new_playlist': 'Nouvelle liste', + 'playlist.empty_title': 'Pas encore de listes', + 'playlist.empty_desc': 'Créez votre première liste pour organiser le contenu de vos écrans.', + 'playlist.all_auto_generated': 'Toutes les listes sont auto-générées. Cochez « Afficher les listes auto » pour les voir.', + 'playlist.tag_auto': 'auto', + 'playlist.tag_draft': 'brouillon', + 'playlist.item_count_one': '1 élément', + 'playlist.item_count_other': '{n} éléments', + 'playlist.created_at': 'Créée {date}', + 'playlist.display_count_one': '1 écran', + 'playlist.display_count_other': '{n} écrans', + 'playlist.assigned_to_one': 'Attribuée à 1 écran', + 'playlist.assigned_to_other': 'Attribuée à {n} écrans', + 'playlist.load_failed': 'Échec du chargement des listes : {error}', + 'playlist.back_to_playlists': 'Retour aux listes', + 'playlist.name_placeholder': 'Nom de la liste', + 'playlist.desc_placeholder': 'Description (facultatif)', + 'playlist.create_btn': 'Créer', + 'playlist.add_desc_placeholder': 'Ajouter une description...', + 'playlist.click_to_rename': 'Cliquer pour renommer', + 'playlist.click_to_edit_desc': 'Cliquer pour modifier la description', + 'playlist.add_content': '+ Ajouter du contenu', + 'playlist.delete_playlist': 'Supprimer la liste', + 'playlist.back': 'Retour', + 'playlist.items_empty': 'Cette liste est vide', + 'playlist.items_empty_hint': 'Cliquez sur « Ajouter du contenu » pour ajouter des éléments.', + 'playlist.duration': 'Durée', + 'playlist.sec': 'sec', + 'playlist.move_up': 'Monter', + 'playlist.move_down': 'Descendre', + 'playlist.remove_item': 'Retirer l\'élément', + 'playlist.item_widget': 'Widget', + 'playlist.unknown_type': 'Type inconnu', + 'playlist.confirm_delete': 'Supprimer « {name} » ? Cette action est irréversible.', + 'playlist.confirm_discard_draft': 'Annuler toutes les modifications non publiées et revenir à la dernière version publiée ?', + 'playlist.draft.banner_title': 'Modifications non publiées', + 'playlist.draft.devices_showing_published': 'Les appareils affichent encore la dernière version publiée.', + 'playlist.draft.never_published': 'Cette liste n\'a jamais été publiée. Les appareils n\'afficheront rien jusqu\'à publication.', + 'playlist.draft.discard_changes': 'Annuler les modifications', + 'playlist.draft.publish': 'Publier', + 'playlist.draft.publishing': 'Publication...', + 'playlist.toast.created': 'Liste créée', + 'playlist.toast.deleted': 'Liste supprimée', + 'playlist.toast.published': 'Liste publiée — appareils mis à jour', + 'playlist.toast.draft_discarded': 'Modifications du brouillon annulées', + 'playlist.toast.item_removed': 'Élément retiré', + 'playlist.add_modal_title': 'Ajouter du contenu à la liste', + 'playlist.tab_content': 'Contenu', + 'playlist.tab_widgets': 'Widgets', + 'playlist.search_placeholder': 'Rechercher...', + 'playlist.close': 'Fermer', + 'playlist.no_content_found': 'Aucun contenu trouvé', + 'playlist.no_widgets_found': 'Aucun widget trouvé', + 'playlist.add_btn': 'Ajouter', + 'playlist.adding': 'Ajout...', + 'playlist.added': 'Ajouté', }; diff --git a/frontend/js/i18n/pt.js b/frontend/js/i18n/pt.js index 8171d55..b80cbd6 100644 --- a/frontend/js/i18n/pt.js +++ b/frontend/js/i18n/pt.js @@ -625,4 +625,66 @@ export default { 'designer.toast.export_failed': 'Falha ao exportar: {error}', 'designer.toast.loaded': 'Design carregado', 'designer.toast.invalid_file': 'Arquivo de design inválido', + + // Playlists + 'playlist.title': 'Playlists', + 'playlist.subtitle': 'Crie e gerencie playlists de conteúdo', + 'playlist.show_auto_generated': 'Mostrar autogeradas', + 'playlist.new_playlist_btn': '+ Nova playlist', + 'playlist.new_playlist': 'Nova playlist', + 'playlist.empty_title': 'Sem playlists ainda', + 'playlist.empty_desc': 'Crie sua primeira playlist para organizar conteúdo para suas telas.', + 'playlist.all_auto_generated': 'Todas as playlists são autogeradas. Ative "Mostrar autogeradas" para vê-las.', + 'playlist.tag_auto': 'auto', + 'playlist.tag_draft': 'rascunho', + 'playlist.item_count_one': '1 item', + 'playlist.item_count_other': '{n} itens', + 'playlist.created_at': 'Criada {date}', + 'playlist.display_count_one': '1 tela', + 'playlist.display_count_other': '{n} telas', + 'playlist.assigned_to_one': 'Atribuída a 1 tela', + 'playlist.assigned_to_other': 'Atribuída a {n} telas', + 'playlist.load_failed': 'Falha ao carregar playlists: {error}', + 'playlist.back_to_playlists': 'Voltar para playlists', + 'playlist.name_placeholder': 'Nome da playlist', + 'playlist.desc_placeholder': 'Descrição (opcional)', + 'playlist.create_btn': 'Criar', + 'playlist.add_desc_placeholder': 'Adicionar uma descrição...', + 'playlist.click_to_rename': 'Clique para renomear', + 'playlist.click_to_edit_desc': 'Clique para editar a descrição', + 'playlist.add_content': '+ Adicionar conteúdo', + 'playlist.delete_playlist': 'Excluir playlist', + 'playlist.back': 'Voltar', + 'playlist.items_empty': 'Esta playlist está vazia', + 'playlist.items_empty_hint': 'Clique em "Adicionar conteúdo" para adicionar itens.', + 'playlist.duration': 'Duração', + 'playlist.sec': 'seg', + 'playlist.move_up': 'Mover para cima', + 'playlist.move_down': 'Mover para baixo', + 'playlist.remove_item': 'Remover item', + 'playlist.item_widget': 'Widget', + 'playlist.unknown_type': 'Tipo desconhecido', + 'playlist.confirm_delete': 'Excluir "{name}"? Isso não pode ser desfeito.', + 'playlist.confirm_discard_draft': 'Descartar todas as alterações não publicadas e voltar à última versão publicada?', + 'playlist.draft.banner_title': 'Alterações não publicadas', + 'playlist.draft.devices_showing_published': 'Os dispositivos ainda exibem a última versão publicada.', + 'playlist.draft.never_published': 'Esta playlist nunca foi publicada. Os dispositivos não exibirão nada até você publicar.', + 'playlist.draft.discard_changes': 'Descartar alterações', + 'playlist.draft.publish': 'Publicar', + 'playlist.draft.publishing': 'Publicando...', + 'playlist.toast.created': 'Playlist criada', + 'playlist.toast.deleted': 'Playlist excluída', + 'playlist.toast.published': 'Playlist publicada — dispositivos atualizados', + 'playlist.toast.draft_discarded': 'Alterações do rascunho descartadas', + 'playlist.toast.item_removed': 'Item removido', + 'playlist.add_modal_title': 'Adicionar conteúdo à playlist', + 'playlist.tab_content': 'Conteúdo', + 'playlist.tab_widgets': 'Widgets', + 'playlist.search_placeholder': 'Buscar...', + 'playlist.close': 'Fechar', + 'playlist.no_content_found': 'Nenhum conteúdo encontrado', + 'playlist.no_widgets_found': 'Nenhum widget encontrado', + 'playlist.add_btn': 'Adicionar', + 'playlist.adding': 'Adicionando...', + 'playlist.added': 'Adicionado', }; diff --git a/frontend/js/views/playlists.js b/frontend/js/views/playlists.js index e7fb222..edbc0e5 100644 --- a/frontend/js/views/playlists.js +++ b/frontend/js/views/playlists.js @@ -1,6 +1,7 @@ import { api } from '../api.js'; import { showToast } from '../components/toast.js'; import { esc } from '../utils.js'; +import { t, tn } from '../i18n.js'; function formatDate(ts) { if (!ts) return '--'; @@ -31,27 +32,25 @@ export function cleanup() { currentPlaylistId = null; } -// ==================== LIST VIEW ==================== - let showAutoGenerated = true; async function renderList(container) { container.innerHTML = `
Create your first playlist to organize content for your displays.
+${t('playlist.empty_desc')}
`; return; @@ -87,7 +86,7 @@ async function loadPlaylists() { if (!filtered.length) { grid.innerHTML = `Failed to load playlist: ${esc(err.message)}
- Back to Playlists +${t('playlist.load_failed', { error: esc(err.message) })}
+ ${t('playlist.back_to_playlists')}This playlist is empty
-Click "Add Content" to add items.
+${t('playlist.items_empty')}
+${t('playlist.items_empty_hint')}