- {languages.map((language) => (
+ {SUPPORTED_LANGUAGES.map((language) => (
{showSortMenu && (
diff --git a/frontend/src/features/settings/tabs/GeneralTab.tsx b/frontend/src/features/settings/tabs/GeneralTab.tsx
index 2760fe5f..d5e6b4d3 100644
--- a/frontend/src/features/settings/tabs/GeneralTab.tsx
+++ b/frontend/src/features/settings/tabs/GeneralTab.tsx
@@ -4,6 +4,7 @@ import { Button, Card, Input, Loading } from '../../../components/common';
import { useTranslation } from 'react-i18next';
import type { GeneralSettings } from '../hooks/useSettingsState';
import { MAX_FILES_PER_UPLOAD_LIMIT } from '../hooks/useSettingsState';
+import { SUPPORTED_LANGUAGES } from "../../../components/common/LanguageSelector.tsx";
interface GeneralTabProps {
generalSettings: GeneralSettings;
@@ -244,11 +245,9 @@ export const GeneralTab: React.FC
= ({
onChange={(e) => setGeneralSettings(prev => ({ ...prev, default_language: e.target.value }))}
className="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
>
- English
- Deutsch
- Nederlands
- Português (Brasil)
- Русский
+ {SUPPORTED_LANGUAGES.map(lang => (
+ {lang.name}
+ ))}
{t('settings.general.defaultLanguageHelp')}
diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts
index 0e2ac578..9a8ed8f1 100644
--- a/frontend/src/hooks/index.ts
+++ b/frontend/src/hooks/index.ts
@@ -1,6 +1,5 @@
export * from './useSessionTimeout';
export * from './useOnClickOutside';
export * from './useLocalizedDate';
-export * from './useLocalizedTimeAgo';
export * from './usePermission';
export * from './usePublicSettings';
\ No newline at end of file
diff --git a/frontend/src/hooks/useLocalizedDate.ts b/frontend/src/hooks/useLocalizedDate.ts
index 9ad2b3f0..5a8c6a5f 100644
--- a/frontend/src/hooks/useLocalizedDate.ts
+++ b/frontend/src/hooks/useLocalizedDate.ts
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { format as dateFnsFormat, formatDistanceToNow as dateFnsFormatDistanceToNow } from 'date-fns';
-import { de, enUS, ptBR } from 'date-fns/locale';
+import { de, enUS, ptBR, fr } from 'date-fns/locale';
import { usePublicSettings } from './usePublicSettings';
// Convert old date format strings to new date-fns format
@@ -17,9 +17,17 @@ export const useLocalizedDate = () => {
const { data: settings } = usePublicSettings();
const getLocale = () => {
- if (i18n.language === 'de') return de;
- if (i18n.language === 'pt' || i18n.language === 'pt-BR') return ptBR;
- return enUS;
+ switch (i18n.language) {
+ case 'de':
+ return de;
+ case 'pt':
+ case 'pt-BR':
+ return ptBR;
+ case 'fr':
+ return fr;
+ default:
+ return enUS;
+ }
};
const format = (date: Date | string, formatStr?: string) => {
diff --git a/frontend/src/hooks/useLocalizedTimeAgo.ts b/frontend/src/hooks/useLocalizedTimeAgo.ts
deleted file mode 100644
index 7e798724..00000000
--- a/frontend/src/hooks/useLocalizedTimeAgo.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { useTranslation } from 'react-i18next';
-
-export const useLocalizedTimeAgo = () => {
- const { i18n } = useTranslation();
-
- const formatTimeAgo = (date: Date | string): string => {
- const dateObj = typeof date === 'string' ? new Date(date) : date;
- const now = new Date();
- const seconds = Math.floor((now.getTime() - dateObj.getTime()) / 1000);
-
- const isGerman = i18n.language === 'de';
-
- // Less than a minute
- if (seconds < 60) {
- return isGerman ? 'gerade eben' : 'just now';
- }
-
- // Minutes
- const minutes = Math.floor(seconds / 60);
- if (minutes < 60) {
- if (minutes === 1) {
- return isGerman ? 'vor 1 Minute' : '1 minute ago';
- }
- return isGerman ? `vor ${minutes} Minuten` : `${minutes} minutes ago`;
- }
-
- // Hours
- const hours = Math.floor(minutes / 60);
- if (hours < 24) {
- if (hours === 1) {
- return isGerman ? 'vor 1 Stunde' : '1 hour ago';
- }
- return isGerman ? `vor ${hours} Stunden` : `${hours} hours ago`;
- }
-
- // Days
- const days = Math.floor(hours / 24);
- if (days < 7) {
- if (days === 1) {
- return isGerman ? 'vor 1 Tag' : '1 day ago';
- }
- return isGerman ? `vor ${days} Tagen` : `${days} days ago`;
- }
-
- // Weeks
- const weeks = Math.floor(days / 7);
- if (weeks < 4) {
- if (weeks === 1) {
- return isGerman ? 'vor 1 Woche' : '1 week ago';
- }
- return isGerman ? `vor ${weeks} Wochen` : `${weeks} weeks ago`;
- }
-
- // Months
- const months = Math.floor(days / 30);
- if (months < 12) {
- if (months === 1) {
- return isGerman ? 'vor 1 Monat' : '1 month ago';
- }
- return isGerman ? `vor ${months} Monaten` : `${months} months ago`;
- }
-
- // Years
- const years = Math.floor(days / 365);
- if (years === 1) {
- return isGerman ? 'vor 1 Jahr' : '1 year ago';
- }
- return isGerman ? `vor ${years} Jahren` : `${years} years ago`;
- };
-
- return { formatTimeAgo };
-};
\ No newline at end of file
diff --git a/frontend/src/i18n/config.ts b/frontend/src/i18n/config.ts
index d1aca46e..b9087af5 100644
--- a/frontend/src/i18n/config.ts
+++ b/frontend/src/i18n/config.ts
@@ -3,11 +3,14 @@ import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import HttpBackend from 'i18next-http-backend';
-import enTranslations from './locales/en.json';
-import deTranslations from './locales/de.json';
-import ruTranslations from './locales/ru.json';
-import ptTranslations from './locales/pt.json';
-import nlTranslations from './locales/nl.json';
+const localeFiles = import.meta.glob>('./locales/*.json', { eager: true, import: 'default' });
+
+const resources = Object.fromEntries(
+ Object.entries(localeFiles).map(([path, translations]) => {
+ const lang = path.match(/\/(\w+)\.json$/)?.[1];
+ return [lang, { translation: translations }];
+ })
+);
i18n
.use(HttpBackend)
@@ -17,23 +20,7 @@ i18n
fallbackLng: 'en',
debug: false,
- resources: {
- en: {
- translation: enTranslations,
- },
- de: {
- translation: deTranslations,
- },
- ru: {
- translation: ruTranslations,
- },
- pt: {
- translation: ptTranslations,
- },
- nl: {
- translation: nlTranslations,
- },
- },
+ resources,
interpolation: {
escapeValue: false,
diff --git a/frontend/src/i18n/locales/fr.json b/frontend/src/i18n/locales/fr.json
new file mode 100644
index 00000000..c57e9751
--- /dev/null
+++ b/frontend/src/i18n/locales/fr.json
@@ -0,0 +1,2302 @@
+{
+ "userManagement": {
+ "title": "Gestion des utilisateurs",
+ "subtitle": "Gérer les administrateurs et les invitations",
+ "loading": "Chargement des utilisateurs...",
+ "loadError": "Échec du chargement des utilisateurs. Veuillez réessayer.",
+ "inviteUser": "Inviter un utilisateur",
+ "createInvitation": "Créer une invitation",
+ "email": "Adresse e-mail",
+ "emailPlaceholder": "utilisateur@exemple.com",
+ "role": "Rôle",
+ "selectRole": "Sélectionner un rôle",
+ "sendInvitation": "Envoyer l'invitation",
+ "editUser": "Modifier l'utilisateur",
+ "editingUser": "Modification de l'utilisateur",
+ "saveChanges": "Enregistrer les modifications",
+ "deactivateUser": "Désactiver l'utilisateur",
+ "cancelInvitation": "Annuler l'invitation",
+ "invitationSent": "Invitation envoyée avec succès",
+ "invitationError": "Échec de l'envoi de l'invitation",
+ "invitationCancelled": "Invitation annulée",
+ "cancelInvitationError": "Échec de l'annulation de l'invitation",
+ "userUpdated": "Utilisateur mis à jour avec succès",
+ "updateUserError": "Échec de la mise à jour de l'utilisateur",
+ "userDeactivated": "Utilisateur désactivé avec succès",
+ "deactivateUserError": "Échec de la désactivation de l'utilisateur",
+ "noRole": "Aucun rôle",
+ "neverLoggedIn": "Jamais connecté",
+ "expired": "Expiré",
+ "deactivate": "Désactiver",
+ "cancel": "Annuler",
+ "tabs": {
+ "users": "Utilisateurs",
+ "invitations": "Invitations"
+ },
+ "stats": {
+ "totalUsers": "Total Utilisateurs",
+ "activeUsers": "Utilisateurs actifs",
+ "pendingInvitations": "Invitations en attente",
+ "inactiveUsers": "Utilisateurs inactifs"
+ },
+ "status": {
+ "active": "Actif",
+ "inactive": "Inactif"
+ },
+ "table": {
+ "user": "Utilisateur",
+ "email": "E-mail",
+ "role": "Rôle",
+ "status": "Statut",
+ "lastLogin": "Dernière connexion",
+ "actions": "Actions",
+ "invitedBy": "Invité par",
+ "expires": "Expire le"
+ },
+ "validation": {
+ "emailRequired": "L'e-mail est requis",
+ "emailInvalid": "Format d'e-mail invalide",
+ "roleRequired": "Le rôle est requis"
+ },
+ "searchUsersPlaceholder": "Rechercher des utilisateurs...",
+ "searchInvitationsPlaceholder": "Rechercher des invitations...",
+ "noUsers": "Aucun utilisateur trouvé",
+ "noUsersFound": "Aucun utilisateur ne correspond à votre recherche",
+ "noInvitations": "Aucune invitation en attente",
+ "noInvitationsFound": "Aucune invitation ne correspond à votre recherche",
+ "confirmDeactivate": {
+ "title": "Désactiver l'utilisateur",
+ "message": "Êtes-vous sûr de vouloir désactiver {{name}} ? Il ne pourra plus se connecter."
+ },
+ "confirmCancelInvitation": {
+ "title": "Annuler l'invitation",
+ "message": "Êtes-vous sûr de vouloir annuler l'invitation pour {{email}} ?"
+ }
+ },
+ "common": {
+ "loading": "Chargement...",
+ "error": "Erreur",
+ "save": "Enregistrer",
+ "cancel": "Annuler",
+ "delete": "Supprimer",
+ "edit": "Modifier",
+ "add": "Ajouter",
+ "search": "Rechercher",
+ "filter": "Filtrer",
+ "sortBy": "Trier par",
+ "yes": "Oui",
+ "no": "Non",
+ "back": "Retour",
+ "next": "Suivant",
+ "previous": "Précédent",
+ "close": "Fermer",
+ "logout": "Déconnexion",
+ "menu": "Menu",
+ "change": "Modifier",
+ "remove": "Retirer",
+ "download": "Télécharger",
+ "downloadAll": "Tout télécharger",
+ "uploading": "Téléversement...",
+ "uploaded": "Téléversé",
+ "photo": "photo",
+ "photos": "photos",
+ "video": "vidéo",
+ "videos": "vidéos",
+ "media": "média",
+ "restore": "Restaurer",
+ "actions": "Actions",
+ "refresh": "Actualiser",
+ "preview": "Aperçu",
+ "processing": "Traitement...",
+ "upload": "Téléverser",
+ "days": "jours",
+ "customize": "Personnaliser",
+ "hide": "Masquer",
+ "unknown": "Inconnu",
+ "notSet": "Non défini",
+ "of": "sur",
+ "up": "Haut",
+ "select": "Sélectionner",
+ "selected": "Sélectionné",
+ "chunk": "Segment",
+ "optional": "optionnel"
+ },
+ "upload": {
+ "photoCategory": "Catégorie de photo",
+ "noCategory": "Aucune catégorie",
+ "eventSpecific": "(Spécifique à l'événement)",
+ "clickToUpload": "Cliquez pour téléverser ou glissez-déposez",
+ "fileRequirements": "JPEG, PNG ou WebP (max 50 Mo par fichier, {{limit}} fichiers par envoi)",
+ "fileRequirementsMedia": "Images JPEG, PNG ou WebP, plus vidéos MP4/MOV/WEBM (max 50 Mo par fichier, {{limit}} fichiers par envoi)",
+ "unsupportedFiles": "Certains fichiers ont été ignorés car le format n'est pas supporté (utilisez JPEG/PNG/WebP/MP4/MOV/WEBM).",
+ "selectedFiles": "Fichiers sélectionnés",
+ "uploading": "Téléversement...",
+ "uploadComplete": "Téléversement terminé !",
+ "uploadFailed": "Échec du téléversement",
+ "someFilesFailed": "Certains fichiers n'ont pas pu être téléversés",
+ "uploadPhotos": "Téléverser des photos",
+ "uploadMedia": "Téléverser photos et vidéos",
+ "importExternal": "Importer depuis un dossier externe",
+ "externalImportInfo": "Toutes les images du dossier sélectionné seront importées.",
+ "selectExternalFolder": "Sélectionnez le dossier externe sous /external-media",
+ "importFromSelectedFolder": "Importer depuis le dossier sélectionné",
+ "maxFilesReached": "Maximum de {{limit}} fichiers autorisés",
+ "someFilesSkipped": "Seuls {{allowed}} fichiers supplémentaires peuvent être ajoutés (limite de {{limit}})",
+ "tooManyFiles": "Un maximum de {{limit}} fichiers peuvent être téléversés à la fois",
+ "limitInfo": "{{selected}} sur {{limit}} fichiers sélectionnés ({{remaining}} restants)",
+ "limitReached": "Limite de téléversement atteinte ({{limit}} fichiers par lot)",
+ "uploadingChunks": "Téléversement de {{count}} fichiers en {{total}} lots...",
+ "mediaCategory": "Catégorie de média",
+ "uploadAction": "Téléverser {{count}} fichiers"
+ },
+ "navigation": {
+ "dashboard": "Tableau de bord",
+ "events": "Événements",
+ "archives": "Archives",
+ "settings": "Paramètres",
+ "eventTypes": "Types d'événements",
+ "branding": "Identité visuelle",
+ "analytics": "Analytique",
+ "emailSettings": "Paramètres e-mail",
+ "backup": "Sauvegarde et Restauration",
+ "cmsPages": "Pages CMS",
+ "users": "Utilisateurs"
+ },
+ "archives": {
+ "title": "Archives",
+ "subtitle": "Gérer les galeries photo archivées",
+ "loadingArchives": "Chargement des archives...",
+ "totalArchives": "Total des archives",
+ "storageUsed": "Espace disque utilisé",
+ "totalPhotos": "Total des photos",
+ "avgArchiveSize": "Taille moyenne d'archive",
+ "searchPlaceholder": "Rechercher des archives...",
+ "allTypes": "Tous les types",
+ "wedding": "Mariage",
+ "birthday": "Anniversaire",
+ "corporate": "Entreprise",
+ "other": "Autre",
+ "sortByDate": "Trier par date",
+ "sortByName": "Trier par nom",
+ "sortBySize": "Trier par taille",
+ "tableHeaders": {
+ "event": "Événement",
+ "type": "Type",
+ "archivedDate": "Date d'archivage",
+ "size": "Taille",
+ "photos": "Photos",
+ "actions": "Actions"
+ },
+ "noArchivesFound": "Aucune archive trouvée",
+ "eventDateNA": "Date de l'événement : N/A",
+ "processing": "Traitement...",
+ "download": "Télécharger",
+ "restore": "Restaurer",
+ "delete": "Supprimer",
+ "showing": "Affichage de {{from}} à {{to}} sur {{total}} archives",
+ "page": "Page {{current}} sur {{total}}",
+ "storageManagement": "Gestion du stockage",
+ "storageInfo": "Les archives sont conservées de façon permanente sauf suppression manuelle. Envisagez de mettre en œuvre une politique de rétention pour gérer les coûts de stockage.",
+ "confirmRestore": "Êtes-vous sûr de vouloir restaurer cette archive ? L'événement redeviendra actif.",
+ "confirmDelete": "Êtes-vous sûr de vouloir supprimer définitivement cette archive ? Cette action est irréversible.",
+ "restoreSuccess": "Archive restaurée avec succès",
+ "deleteSuccess": "Archive supprimée définitivement"
+ },
+ "auth": {
+ "login": "Connexion",
+ "password": "Mot de passe",
+ "enterPassword": "Entrer le mot de passe de la galerie",
+ "passwordPlaceholder": "Saisissez le mot de passe de la galerie",
+ "invalidPassword": "Mot de passe invalide",
+ "wrongPassword": "Mot de passe incorrect. Veuillez vérifier et réessayer.",
+ "tooManyAttempts": "Trop de tentatives de connexion échouées. Veuillez réessayer plus tard.",
+ "sessionExpired": "Session expirée",
+ "pleaseEnterPassword": "Veuillez entrer un mot de passe",
+ "passwordHint": "Le mot de passe a été fourni par l'organisateur de l'événement. Contactez-le si vous ne l'avez pas."
+ },
+ "gallery": {
+ "title": "Galerie Photo",
+ "welcomeMessage": "Message de bienvenue",
+ "expiresOn": "Expire le",
+ "expires": "Expire",
+ "expired": "Expirée",
+ "daysRemaining": "{{days}} jours restants",
+ "dayRemaining": "1 jour restant",
+ "hoursRemaining": "{{hours}} heures restantes",
+ "expiredMessage": "Cette galerie a expiré le {{date}}",
+ "contactOrganizer": "Veuillez contacter l'organisateur si vous avez besoin d'accéder à ces photos",
+ "searchPhotos": "Rechercher par nom de fichier...",
+ "sortByDate": "Trier par date",
+ "sortByName": "Trier par nom",
+ "sortBySize": "Trier par taille",
+ "allPhotos": "Toutes les photos",
+ "filter": "Filtrer",
+ "feedbackFilter": "Filtre d'avis",
+ "all": "Tout",
+ "liked": "Aimé",
+ "favorited": "Favori",
+ "favorites": "Favoris",
+ "downloadSelected": "Télécharger la sélection",
+ "shareGallery": "Partager la galerie",
+ "needHelp": "Besoin d'aide ? Contactez-nous à",
+ "noPhotosFound": "Aucune photo trouvée",
+ "failedToLoad": "Échec du chargement des photos",
+ "tryAgain": "Réessayer",
+ "loading": "Chargement de la galerie...",
+ "expiredOn": "Cette galerie a expiré le {{date}}.",
+ "expiresIn": "La galerie expire dans {{count}} jour",
+ "expiresIn_plural": "La galerie expire dans {{count}} jours",
+ "downloadBefore": "Téléchargez vos photos avant qu'elles ne soient plus disponibles.",
+ "publicGalleryTitle": "Cette galerie est accessible publiquement",
+ "publicGallerySubtitle": "Chargement des photos...",
+ "viewGallery": "Voir la galerie",
+ "downloadAll": "Tout télécharger",
+ "downloading": "Téléchargement de {{count}} photo...",
+ "downloading_plural": "Téléchargement de {{count}} photos...",
+ "downloadedPhotos": "{{count}} photo téléchargée !",
+ "downloadedPhotos_plural": "{{count}} photos téléchargées !",
+ "downloadError": "Échec du téléchargement de certaines photos",
+ "selectPhotos": "Sélectionner des photos",
+ "cancelSelection": "Annuler la sélection",
+ "photosSelected": "{{count}} sélectionnée(s)",
+ "selectAll": "Tout sélectionner",
+ "deselectAll": "Tout désélectionner",
+ "downloadSelected": "Télécharger les {{count}} sélectionnés",
+ "deleteSelected": "Supprimer la sélection",
+ "photosCount": "{{count}} photo",
+ "photosCount_plural": "{{count}} photos",
+ "searchByFilename": "Rechercher par nom de fichier...",
+ "uncategorized": "Non catégorisé",
+ "sortAscending": "Tri croissant",
+ "sortDescending": "Tri décroissant",
+ "remaining": "restant",
+ "selectPhotosHint": "Astuce : Utilisez Ctrl+Clic (Cmd+Clic sur Mac) pour sélectionner rapidement plusieurs photos",
+ "filters": "Filtres",
+ "openFilters": "Ouvrir les filtres",
+ "toggleSidebar": "Basculer la barre latérale",
+ "toggleMenu": "Basculer le menu",
+ "allCategories": "Toutes les catégories",
+ "categories": "Catégories",
+ "mediaType": "Média",
+ "allMedia": "Tous les médias",
+ "photosOnly": "Photos uniquement",
+ "videosOnly": "Vidéos uniquement",
+ "download": "Télécharger",
+ "noMedia": "Aucun média téléversé pour le moment",
+ "searchPlaceholder": "Rechercher des photos...",
+ "sortBy": "Trier par",
+ "sortByDate": "Trier par date",
+ "sortByCaptureDate": "Trier par date de capture",
+ "sortByName": "Trier par nom",
+ "sortBySize": "Trier par taille",
+ "sortByRating": "Trier par note",
+ "photoGallery": "Galerie Photo",
+ "photos": "Photos",
+ "allRightsReserved": "Tous droits réservés",
+ "searchMemories": "Rechercher des souvenirs...",
+ "thankYou": "Merci",
+ "thankYouMessage": "D'avoir fait partie de notre histoire et d'avoir rendu cette journée inoubliable.",
+ "feedback": {
+ "title": "Avis",
+ "shareThoughts": "Partagez votre avis sur \"{{name}}\"",
+ "rateThisMoment": "Notez ce moment",
+ "comments": "Commentaires",
+ "noComments": "Pas encore de commentaires. Soyez le premier !",
+ "yourName": "Votre nom",
+ "yourEmail": "Votre e-mail",
+ "writeLovelyNote": "Écrivez un petit mot...",
+ "postComment": "Publier le commentaire",
+ "anonymous": "Anonyme"
+ }
+ },
+ "categories": {
+ "title": "Catégories de photos",
+ "global": "Catégories globales",
+ "eventSpecific": "Catégories spécifiques à l'événement",
+ "addCategory": "Ajouter une catégorie",
+ "organizationInfo": "Organisez vos photos en catégories. Les catégories aident les invités à naviguer et à trouver des types de photos spécifiques.",
+ "eventSpecificCategories": "Catégories spécifiques à l'événement",
+ "noEventSpecificCategories": "Aucune catégorie spécifique. Les catégories globales sont disponibles par défaut.",
+ "globalCategoriesAlwaysAvailable": "Catégories globales (toujours disponibles) :",
+ "deleteCategoryTitle": "Supprimer la catégorie",
+ "categoryCreatedSuccess": "Catégorie créée avec succès",
+ "categoryDeletedSuccess": "Catégorie supprimée avec succès",
+ "failedToCreateCategory": "Échec de la création de la catégorie",
+ "failedToDeleteCategory": "Échec de la suppression de la catégorie",
+ "categoryName": "Nom de la catégorie",
+ "noCategory": "Aucune catégorie",
+ "noCategoriesYet": "Pas encore de catégories. Créez votre première catégorie pour organiser les photos.",
+ "deleteConfirm": "Êtes-vous sûr de vouloir supprimer \"{{name}}\" ?",
+ "cannotDelete": "Impossible de supprimer une catégorie contenant des photos. Veuillez réassigner les photos d'abord.",
+ "setCoverPhoto": "Définir comme photo de couverture",
+ "removeCoverPhoto": "Retirer la photo de couverture",
+ "coverPhotoSet": "Photo de couverture définie avec succès",
+ "coverPhotoRemoved": "Photo de couverture retirée",
+ "failedToSetCoverPhoto": "Échec de la définition de la photo de couverture",
+ "categoryHeroHint": "Si aucune photo de couverture n'est définie pour une catégorie, la photo principale par défaut sera utilisée."
+ },
+ "events": {
+ "title": "Événements",
+ "create": "Créer",
+ "createEvent": "Créer un événement",
+ "totalViews": "Total des vues",
+ "totalDownloads": "Total des téléchargements",
+ "uniqueVisitors": "Visiteurs uniques",
+ "createNewEvent": "Créer un nouvel événement",
+ "setupNewGallery": "Configurez une nouvelle galerie photo pour votre événement",
+ "createNewEventSubtitle": "Configurez une nouvelle galerie photo pour votre événement",
+ "eventNamePlaceholder": "ex: Mariage de Julie & Thomas",
+ "welcomeMessageOptional": "Message de bienvenue (Optionnel)",
+ "welcomeMessagePlaceholder": "Bienvenue à notre journée spéciale ! N'hésitez pas à télécharger et partager ces souvenirs...",
+ "hostEmailPlaceholder": "client@exemple.com",
+ "adminEmailPlaceholder": "admin@exemple.com",
+ "securityAndAccess": "Sécurité et Accès",
+ "accessAndSecurity": "Accès et Sécurité",
+ "enterPassword": "Entrer le mot de passe",
+ "passwordPlaceholder": "Entrer un mot de passe sécurisé",
+ "confirmPasswordPlaceholder": "Confirmer le mot de passe",
+ "galleryExpiresOn": "La galerie expirera le {{date}}",
+ "guestsWillReceiveWarning": "Les invités recevront un e-mail d'avertissement 7 jours avant l'expiration.",
+ "types": {
+ "wedding": "Mariage",
+ "birthday": "Anniversaire",
+ "corporate": "Entreprise",
+ "other": "Autre"
+ },
+ "themes": {
+ "default": "Par défaut",
+ "oceanBlue": "Bleu Océan",
+ "royalPurple": "Violet Royal",
+ "roseGold": "Or Rose",
+ "sunsetAmber": "Ambre Coucher de Soleil"
+ },
+ "eventDetails": "Détails de l'événement",
+ "eventName": "Nom de l'événement",
+ "eventType": "Type d'événement",
+ "eventDate": "Date de l'événement",
+ "hostEmail": "E-mail du client",
+ "hostName": "Nom du client",
+ "hostNamePlaceholder": "Jean Dupont",
+ "adminEmail": "E-mail de l'admin",
+ "adminNotificationEmail": "E-mail de notification admin",
+ "expirationDate": "Date d'expiration",
+ "active": "Actif",
+ "archived": "Archivé",
+ "photoCount": "{{count}} photos",
+ "totalSize": "Taille totale",
+ "shareLink": "Lien de partage",
+ "copyLink": "Copier le lien",
+ "linkCopied": "Lien copié !",
+ "viewGallery": "Voir la galerie",
+ "uploadPhotos": "Téléverser des photos",
+ "archiveEvent": "Archiver l'événement",
+ "archiveConfirm": "Êtes-vous sûr de vouloir archiver cet événement ? Cette action est irréversible.",
+ "extendExpiration": "Prolonger de {{days}} jours",
+ "backToEvents": "Retour aux événements",
+ "loadingEventDetails": "Chargement des détails...",
+ "saveChanges": "Enregistrer les modifications",
+ "eventExpired": "Cet événement a expiré",
+ "eventExpiresIn": "Cet événement expire dans {{days}} jours",
+ "guestsNoAccess": "Les invités ne peuvent plus accéder à la galerie. Envisagez d'archiver cet événement.",
+ "warningEmailsSent": "Des e-mails d'avertissement ont été envoyés au client.",
+ "overview": "Aperçu",
+ "photos": "Photos",
+ "categories": "Catégories",
+ "eventInformation": "Informations sur l'événement",
+ "sourceMode": "Mode source",
+ "sourceModeManaged": "Géré (téléverser sur PicPeak)",
+ "sourceModeReference": "Référence dossier externe",
+ "sourceModeHelp": "Utilisez le mode géré pour les téléversements directs ou pointez vers un dossier /external-media monté pour un stockage local.",
+ "externalFolder": "Dossier externe",
+ "externalFolderHint": "Ces dossiers sont lus depuis le montage /external-media dans votre conteneur ou hôte.",
+ "externalFolderRequired": "Veuillez sélectionner un dossier externe avant d'enregistrer.",
+ "welcomeMessage": "Message de bienvenue",
+ "noWelcomeMessage": "Aucun message de bienvenue défini",
+ "created": "Créé",
+ "expires": "Expire le",
+ "shareWithGuests": "Partagez ce lien avec vos invités. Ils auront besoin du mot de passe pour accéder à la galerie.",
+ "shareWithGuestsPublic": "Partagez ce lien avec vos invités. Aucun mot de passe n'est requis pour cette galerie.",
+ "resetGalleryPassword": "Réinitialiser le mot de passe",
+ "resendCreationEmail": "Renvoyer l'e-mail de création",
+ "creationEmailResent": "L'e-mail de création a été mis en file d'attente",
+ "failedToResendEmail": "Échec du renvoi de l'e-mail de création",
+ "photoStatistics": "Statistiques des photos",
+ "totalPhotos": "Total des photos",
+ "managePhotos": "Gérer les photos",
+ "actions": "Actions",
+ "archivingInfo": "L'archivage créera un fichier ZIP de toutes les photos et supprimera l'accès public à la galerie.",
+ "statistics": "Statistiques",
+ "views": "Vues",
+ "downloads": "Téléchargements",
+ "noStatistics": "Aucune statistique disponible pour le moment",
+ "archiveStatus": "Statut de l'archive",
+ "archivedOn": "Archivé le",
+ "downloadArchive": "Télécharger l'archive",
+ "loadingPhotos": "Chargement des photos...",
+ "photoCategories": "Catégories de photos",
+ "organizeCategoriesInfo": "Organisez vos photos en catégories. Les catégories aident les invités à naviguer.",
+ "categoriesTip": "Astuce : Les catégories sont spécifiques à chaque événement. Vous pouvez aussi créer des catégories globales dans les Paramètres.",
+ "contactInformation": "Informations de contact",
+ "hostEmailHelp": "Le client recevra les notifications de création et d'expiration de la galerie",
+ "adminEmailHelp": "Recevra les notifications système et les confirmations d'archivage",
+ "securityAccess": "Sécurité et Accès",
+ "galleryPassword": "Mot de passe de la galerie",
+ "requirePasswordToggle": "Exiger un mot de passe pour cette galerie",
+ "requirePasswordToggleHelp": "Désactivez cette option pour partager la galerie sans mot de passe. Toute personne disposant du lien pourra voir les photos.",
+ "publicGalleryWarning": "Les galeries publiques sont accessibles à tous ceux qui ont le lien. Envisagez d'activer les filigranes et de surveiller l'activité.",
+ "passwordHelperText": "Vous pouvez utiliser des dates comme \"04.07.2025\" ou n'importe quel texte de plus de 6 caractères",
+ "confirmPassword": "Confirmer le mot de passe",
+ "showPasswords": "Afficher les mots de passe",
+ "newPasswordLabel": "Nouveau mot de passe de la galerie",
+ "gallerySettings": "Paramètres de la galerie",
+ "themeAndStyle": "Thème et Style",
+ "colorTheme": "Thème de couleur",
+ "galleryExpiration": "Expiration de la galerie",
+ "galleryExpiresIn": "La galerie expire dans",
+ "daysAfterEvent": "jours après la date de l'événement",
+ "galleryWillExpireOn": "La galerie expirera le {{date}}",
+ "expirationWarning": "Les invités recevront un e-mail d'avertissement 7 jours avant l'expiration.",
+ "noExpiration": "Pas d'expiration",
+ "noExpirationHelp": "Cette galerie restera active jusqu'à son archivage manuel.",
+ "userUploads": "Paramètres de téléversement invité",
+ "allowUserUploads": "Autoriser les invités à téléverser des photos",
+ "allowUserUploadsHelp": "Permet aux invités d'ajouter leurs propres photos à cette galerie",
+ "allowUserUploadsDescription": "Permet aux invités d'ajouter leurs propres photos à cette galerie",
+ "uploadCategory": "Catégorie de téléversement",
+ "selectCategory": "Sélectionner une catégorie pour les envois invités",
+ "uploadCategoryHelp": "Toutes les photos envoyées par les invités seront ajoutées à cette catégorie",
+ "userUploadWarning": "Les envois invités seront modérés et peuvent être supprimés par les admins à tout moment.",
+ "allowDownloads": "Autoriser le téléchargement des photos",
+ "allowDownloadsHelp": "Autorise les invités à télécharger les photos de cette galerie",
+ "downloadPermissions": "Permissions de téléchargement",
+ "downloadsEnabled": "Téléchargements activés",
+ "downloadsDisabled": "Téléchargements désactivés",
+ "downloadProtection": "Protection contre le téléchargement",
+ "disableRightClick": "Bloquer le clic droit",
+ "watermarkDownloads": "Ajouter un filigrane aux téléchargements",
+ "enableDevtoolsProtection": "Détecter les outils de développement",
+ "useCanvasRendering": "Rendu Canvas (protection avancée)",
+ "protectionInfo": "Les fonctions de protection aident à prévenir les téléchargements non autorisés mais ne peuvent bloquer toutes les méthodes.",
+ "protectionLevelBasic": "Basique - Blocage clic droit uniquement",
+ "protectionLevelStandard": "Standard - Raccourcis clavier bloqués",
+ "protectionLevelEnhanced": "Amélioré - Détection de capture d'écran",
+ "protectionLevelMaximum": "Maximum - Détection DevTools et rendu Canvas",
+ "heroLogoSettings": "Paramètres du logo principal",
+ "heroLogoVisible": "Afficher le logo dans la section principale",
+ "heroLogoSize": "Taille du logo",
+ "heroLogoSizeSmall": "Petit",
+ "heroLogoSizeMedium": "Moyen",
+ "heroLogoSizeLarge": "Grand",
+ "heroLogoSizeXLarge": "Très Grand",
+ "heroLogoPosition": "Position du logo",
+ "heroLogoPositionTop": "Haut (au-dessus du titre)",
+ "heroLogoPositionCenter": "Centre (entre titre et dates)",
+ "heroLogoPositionBottom": "Bas (sous les dates)",
+ "heroLogoInfo": "Ces paramètres s'appliquent lorsque la galerie utilise la mise en page 'Hero'. Vous pouvez masquer le logo ou personnaliser sa taille et sa position.",
+ "eventCustomLogo": "Logo personnalisé de l'événement",
+ "eventCustomLogoDescription": "Téléchargez un logo spécifique pour cet événement. Il remplace le logo global pour cette galerie uniquement.",
+ "uploadEventLogo": "Téléverser le logo",
+ "replaceLogo": "Remplacer",
+ "removeLogo": "Retirer",
+ "eventLogoUploaded": "Logo de l'événement téléversé avec succès",
+ "eventLogoUploadFailed": "Échec du téléversement du logo",
+ "eventLogoRemoved": "Logo de l'événement retiré avec succès",
+ "eventLogoRemoveFailed": "Échec du retrait du logo",
+ "heroLogoVisibleLabel": "Logo visible",
+ "heroLogoSizeLabel": "Taille",
+ "heroLogoPositionLabel": "Position",
+ "heroLogoHidden": "Logo masqué",
+ "heroPhoto": "Photo principale (Hero)",
+ "heroPhotoHelp": "Sélectionnez une photo principale par défaut. Vous pouvez modifier cela par catégorie.",
+ "selectHeroPhoto": "Sélectionner la photo Hero",
+ "noHeroPhotoSelected": "Aucune photo Hero sélectionnée",
+ "heroPhotoSelected": "Photo Hero sélectionnée",
+ "heroImageAnchor": "Position de recadrage de l'image Hero",
+ "heroImageAnchorDescription": "Cliquez sur l'image pour définir le point focal du recadrage.",
+ "heroImageAnchorTop": "Haut",
+ "heroImageAnchorCenter": "Centre",
+ "heroImageAnchorBottom": "Bas",
+ "heroPreview": "Aperçu Hero",
+ "noPhotosAvailable": "Aucune photo disponible",
+ "processingRequest": "Traitement de votre demande...",
+ "eventTypeWedding": "Mariage",
+ "eventTypeBirthday": "Anniversaire",
+ "eventTypeCorporate": "Entreprise",
+ "eventTypeOther": "Autre",
+ "days30": "30 jours",
+ "days60": "60 jours",
+ "days90": "90 jours",
+ "days365": "1 an",
+ "inactive": "Inactif",
+ "daysLeft": "{{count}}j restant",
+ "daysLeft_plural": "{{count}}j restants",
+ "subtitle": "Gérez vos galeries photo et vos événements",
+ "loadingEvents": "Chargement des événements...",
+ "failedToLoadEvents": "Échec du chargement des événements",
+ "bulkArchiveSuccess": "Archivage réussi de {{count}} événements",
+ "bulkArchivePartial": "{{success}} événements archivés, {{failed}} échecs",
+ "searchEventsPlaceholder": "Rechercher des événements...",
+ "all": "Tout",
+ "expiring": "Expire bientôt",
+ "eventsSelected": "{{count}} événement sélectionné",
+ "eventsSelected_plural": "{{count}} événements sélectionnés",
+ "clear": "Effacer",
+ "archiveSelected": "Archiver la sélection",
+ "publicAccess": "Accès public",
+ "passwordProtected": "Protégé par mot de passe",
+ "newPasswordRequired": "Veuillez définir un mot de passe avant d'activer la protection.",
+ "event": "Événement",
+ "type": "Type",
+ "date": "Date",
+ "status": "Statut",
+ "noEventsFound": "Aucun événement trouvé",
+ "stats": {
+ "totalEvents": "Total Événements",
+ "activeEvents": "Événements Actifs",
+ "totalPhotos": "Total Photos",
+ "expiringEvents": "Expire Bientôt"
+ },
+ "viewDetails": "Voir les détails",
+ "archiveEventAction": "Archiver l'événement",
+ "downloadArchiveAction": "Télécharger l'archive",
+ "deleteEvent": "Supprimer l'événement",
+ "deleteEventConfirm": "Êtes-vous sûr de vouloir supprimer cet événement ?",
+ "downloadArchiveSoon": "Téléchargement d'archive bientôt disponible",
+ "eventExpiredMessage": "Cet événement a expiré",
+ "guestsCannotAccessGallery": "Les invités ne peuvent plus accéder à la galerie.",
+ "warningEmailsHaveBeenSent": "Les e-mails d'avertissement ont été envoyés au client.",
+ "extendSevenDays": "Prolonger de 7 jours",
+ "welcomeMessageLabel": "Message de bienvenue",
+ "noWelcomeMessageSet": "Aucun message de bienvenue défini",
+ "createdOn": "Créé le",
+ "daysLeft": "({{count}} jour restant)",
+ "daysLeft_plural": "({{count}} jours restants)",
+ "copy": "Copier",
+ "copied": "Copié !",
+ "organizingPhotosInfo": "Organisez vos photos en catégories pour aider vos invités.",
+ "categoriesTip": "Astuce : Créez des catégories comme \"Cérémonie\", \"Réception\", \"Portraits\", etc.",
+ "archiveStatusTitle": "Statut de l'archive",
+ "downloadingArchive": "Téléchargement de l'archive {{name}}...",
+ "downloadStarted": "Téléchargement démarré",
+ "failedToDownloadArchive": "Échec du téléchargement de l'archive",
+ "statisticsNotAvailable": "Statistiques non disponibles pour le moment",
+ "photoFilters": "Filtres photo",
+ "noStatisticsAvailableYet": "Pas encore de statistiques disponibles",
+ "addPlus": "Ajouter+",
+ "galleryTheme": "Thème de la galerie",
+ "customizeTheme": "Personnaliser le thème",
+ "noThemeSet": "Aucun thème configuré",
+ "customizingTheme": "Personnalisation du thème de la galerie",
+ "customizingThemeFor": "Personnalisation du thème pour {{event}}",
+ "customCssTemplate": "Modèle CSS personnalisé",
+ "customCssTemplateDesc": "Appliquez un modèle CSS personnalisé pour un style unique.",
+ "noTemplate": "Aucun modèle",
+ "useThemeOnly": "Utiliser uniquement le thème prédéfini",
+ "customTemplate": "Modèle personnalisé",
+ "photoCap": "Limite de photos",
+ "photoCapHelp": "Nombre maximum de photos autorisé. 0 = illimité",
+ "rename": {
+ "button": "Renommer",
+ "title": "Renommer l'événement",
+ "validating": "Validation du nouveau nom...",
+ "renamingFiles": "Renommage des fichiers...",
+ "complete": "Terminé !",
+ "failed": "Échec du renommage",
+ "filesRenamed": "{{count}} fichiers mis à jour",
+ "confirm": "Renommer l'événement"
+ }
+ },
+ "settings": {
+ "title": "Paramètres système",
+ "subtitle": "Configurer les paramètres et préférences globaux",
+ "loadingSettings": "Chargement des paramètres...",
+ "general": {
+ "title": "Général",
+ "siteConfiguration": "Configuration du site",
+ "siteUrl": "URL du site",
+ "siteUrlHelp": "Utilisé pour générer les liens des galeries dans les e-mails",
+ "defaultExpiration": "Expiration par défaut (jours)",
+ "defaultExpirationHelp": "Durée d'activation par défaut des galeries",
+ "maxFileSize": "Taille max de fichier (Mo)",
+ "maxFileSizeHelp": "Taille maximale par photo téléversée",
+ "maxFilesPerUpload": "Fichiers max par envoi",
+ "maxFilesPerUploadHelp": "Nombre maximum de photos autorisées par lot (1-{{max}}).",
+ "allowedFileTypes": "Types de fichiers autorisés",
+ "allowedFileTypesHelp": "Liste d'extensions séparées par des virgules",
+ "featureToggles": "Fonctionnalités",
+ "enableAnalytics": "Activer le suivi analytique",
+ "enableRegistration": "Autoriser l'auto-inscription des administrateurs",
+ "enableShortGalleryUrls": "Utiliser des URLs de galerie courtes",
+ "enableShortGalleryUrlsHelp": "Supprime le slug de l'événement des nouveaux liens tout en gardant les anciens fonctionnels.",
+ "maintenanceMode": "Activer le mode maintenance",
+ "language": "Langue",
+ "defaultLanguage": "Langue par défaut",
+ "defaultLanguageHelp": "Langue affichée aux invités avant connexion",
+ "defaultWelcomeMessage": "Message de bienvenue par défaut",
+ "welcomeMessage": "Message de bienvenue",
+ "welcomeMessagePlaceholder": "Entrez un message de bienvenue par défaut pour les e-mails de création",
+ "welcomeMessageHelp": "Ce message sera inclus dans tous les e-mails de création, sauf s'il est modifié lors de la création d'un événement",
+ "saveSettings": "Enregistrer les paramètres généraux",
+ "saveGeneralSettings": "Enregistrer les paramètres généraux",
+ "dateTimeFormat": "Format de date et d'heure",
+ "dateFormat": "Format de date",
+ "dateFormatHelp": "Affichage des dates dans les e-mails et l'application",
+ "accountSection": "Compte Administrateur",
+ "accountUsername": "Nom d'utilisateur admin",
+ "accountUsernameHelp": "Affiché dans l'interface et les journaux d'activité.",
+ "accountUsernameRequired": "Le nom d'utilisateur est requis",
+ "accountUsernameLength": "Le nom d'utilisateur doit faire au moins 3 caractères",
+ "accountEmail": "E-mail admin",
+ "accountEmailHelp": "Utilisé pour la connexion et les notifications de sécurité.",
+ "accountEmailRequired": "L'adresse e-mail est requise",
+ "accountEmailInvalid": "Entrez une adresse e-mail valide",
+ "accountSaveButton": "Enregistrer les détails du compte",
+ "accountSaveSuccess": "Détails du compte mis à jour"
+ },
+ "publicSite": {
+ "tabLabel": "Site Public",
+ "badge": "Page d'accueil",
+ "title": "Page d'accueil publique",
+ "subtitle": "Publiez une page d'accueil personnalisée pour les invités visitant votre domaine.",
+ "loading": "Chargement des paramètres...",
+ "enabled": "Activé",
+ "disabled": "Désactivé",
+ "htmlLabel": "HTML de la page d'accueil",
+ "htmlPlaceholder": "Saisissez le balisage HTML pour votre page (hero, sections, appels à l'action).",
+ "htmlHelp": "Le HTML brut est nettoyé à l'enregistrement. Les jetons comme {{company_name}} seront remplacés par les valeurs de l'identité visuelle.",
+ "cssLabel": "CSS personnalisé",
+ "cssPlaceholder": "Surcharges CSS optionnelles pour ajuster la mise en page.",
+ "cssHelp": "Les imports et URLs JavaScript sont retirés. Utilisez des sélecteurs CSS standard.",
+ "saveCta": "Enregistrer le site public",
+ "saving": "Enregistrement...",
+ "saveSuccess": "Paramètres du site public enregistrés.",
+ "saveError": "Échec de l'enregistrement.",
+ "resetCta": "Réinitialiser par défaut",
+ "resetting": "Réinitialisation...",
+ "resetSuccess": "Modèle réinitialisé.",
+ "resetError": "Échec de la réinitialisation.",
+ "previewTitle": "Aperçu en direct",
+ "previewSandboxed": "Aperçu sécurisé",
+ "previewDisabled": "Activez le site public pour voir l'aperçu.",
+ "sanitizationNotice": "Les scripts et balises non sécurisées sont supprimés avant publication.",
+ "htmlRequired": "Fournissez un contenu HTML avant d'activer le site."
+ },
+ "storage": {
+ "title": "Stockage",
+ "overview": "Aperçu du stockage",
+ "totalUsed": "Total utilisé",
+ "archiveStorage": "Stockage des archives",
+ "storageLimit": "Limite de stockage",
+ "storageLimitHelper": "Définissez une limite de stockage. Cette limite est indicative.",
+ "softLimitInputLabel": "Limite (Go)",
+ "softLimitHelper": "Saisissez l'usage maximum souhaité en gigaoctets.",
+ "recommendedSoftLimit": "Limite suggérée",
+ "diskCapacity": "Capacité disque",
+ "diskCapacityReported": "Capacité disque (déclarée)",
+ "diskAvailable": "Disponible",
+ "diskAvailableReported": "Disponible (déclarée)",
+ "diskFree": "Libre",
+ "diskFreeReported": "Libre (déclarée)",
+ "diskMetricsUnavailable": "Les mesures disque ne sont pas disponibles dans Docker Desktop ou les environnements virtualisés.",
+ "applyRecommended": "Utiliser la recommandation",
+ "applyAvailable": "Faire correspondre au disponible",
+ "invalidSoftLimit": "Entrez un nombre valide.",
+ "saveSoftLimit": "Enregistrer la limite",
+ "limitNotEnforced": "Cette limite est purement indicative et n'est pas appliquée automatiquement.",
+ "overrideTitle": "Surcharge manuelle de capacité",
+ "diskOverrideEnvNote": "La capacité disque est contrôlée par des variables d'environnement.",
+ "diskOverrideSettingsHelp": "Définissez des valeurs personnalisées si Docker rapporte des chiffres irréalistes.",
+ "overrideCapacityLabel": "Capacité totale (Go)",
+ "overrideCapacityHelper": "Laissez vide pour la lecture automatique.",
+ "overrideAvailableLabel": "Espace disponible (Go)",
+ "overrideAvailableHelper": "Optionnel. Laissez vide pour calculer automatiquement.",
+ "saveOverride": "Enregistrer la surcharge",
+ "capacityRequiredForAvailable": "Entrez une capacité totale avant l'espace disponible.",
+ "availableExceedsCapacity": "L'espace disponible ne peut excéder la capacité totale.",
+ "storageUsage": "Usage du stockage",
+ "storageByEvent": "Stockage par événement",
+ "storageManagement": "Gestion du stockage",
+ "storageManagementHelp": "Envisagez d'archiver ou supprimer d'anciens événements pour libérer de l'espace.",
+ "noEventsUsingStorage": "Aucun événement n'utilise de stockage",
+ "unlimited": "Illimité"
+ },
+ "security": {
+ "title": "Sécurité",
+ "passwordSettings": "Paramètres de mot de passe",
+ "minPasswordLength": "Longueur minimale du mot de passe",
+ "minPasswordLengthHelp": "Nombre minimum de caractères pour les galeries",
+ "passwordComplexity": "Complexité du mot de passe",
+ "passwordComplexityHelp": "Niveau de sécurité requis",
+ "complexitySimple": "Simple (6+ car., n'importe quel texte)",
+ "complexityModerate": "Modéré (8+ car., mélange maj/min/chiffres)",
+ "complexityStrong": "Fort (12+ car., maj/min/chiffres)",
+ "complexityVeryStrong": "Très Fort (12+ car., tous types de caractères)",
+ "sessionAuth": "Session et Authentification",
+ "sessionTimeout": "Expiration de session (minutes)",
+ "sessionTimeoutHelp": "Expiration de la session admin",
+ "maxLoginAttempts": "Tentatives de connexion max",
+ "maxLoginAttemptsHelp": "Échecs autorisés par IP avant blocage",
+ "attemptWindowMinutes": "Fenêtre de tentative (minutes)",
+ "attemptWindowMinutesHelp": "Durée de surveillance des échecs",
+ "lockoutDurationMinutes": "Durée du blocage (minutes)",
+ "lockoutDurationMinutesHelp": "Durée du verrouillage après trop d'échecs",
+ "enable2FA": "Activer l'authentification à deux facteurs pour les admins",
+ "recaptchaSettings": "Paramètres reCAPTCHA",
+ "enableRecaptcha": "Activer reCAPTCHA sur les formulaires",
+ "siteKey": "Clé du site",
+ "siteKeyHelp": "Votre clé publique reCAPTCHA v2",
+ "secretKey": "Clé secrète",
+ "secretKeyHelp": "Votre clé secrète reCAPTCHA v2 (garder privé)",
+ "recaptchaHelp": "Obtenez vos clés reCAPTCHA sur",
+ "saveSettings": "Enregistrer les paramètres de sécurité",
+ "saveSecuritySettings": "Enregistrer les paramètres de sécurité"
+ },
+ "categories": {
+ "title": "Catégories",
+ "about": "À propos des catégories",
+ "aboutText": "Les catégories globales sont disponibles pour tous les événements. Vous pouvez aussi créer des catégories spécifiques par événement."
+ },
+ "systemStatus": {
+ "title": "Statut du système",
+ "storageOverview": "Aperçu du stockage",
+ "systemInfo": "Informations système",
+ "databaseInfo": "Informations base de données",
+ "platform": "Plateforme",
+ "nodeVersion": "Version Node",
+ "uptime": "Temps de fonctionnement",
+ "cpuCores": "Cœurs CPU",
+ "memoryUsage": "Usage mémoire",
+ "memoryUsed": "Mémoire utilisée",
+ "photos": "Photos",
+ "admins": "Admins",
+ "dbSize": "Taille base de données",
+ "services": "Services d'arrière-plan",
+ "fileWatcher": "Observateur de fichiers",
+ "fileWatcherDesc": "Surveille les nouvelles photos",
+ "expirationChecker": "Vérificateur d'expiration",
+ "expirationCheckerDesc": "Archive les galeries expirées",
+ "emailProcessor": "Processeur d'e-mails",
+ "emailProcessorDesc": "Envoie les e-mails en file d'attente",
+ "emailQueue": "Statut de la file d'e-mails",
+ "pending": "En attente",
+ "sent": "Envoyés",
+ "failed": "Échoués",
+ "lastUpdate": "Dernière mise à jour"
+ },
+ "photoDimensions": {
+ "title": "Dimensions des photos",
+ "totalPhotos": "Total photos",
+ "withDimensions": "Avec dimensions",
+ "missingDimensions": "Dimensions manquantes",
+ "repairButton": "Réparer les dimensions",
+ "repairing": "Réparation...",
+ "alreadyRunning": "La réparation est déjà en cours",
+ "started": "Réparation lancée pour {{count}} photos",
+ "noneToRepair": "Toutes les photos ont déjà leurs dimensions",
+ "resultSuccess": "Dernière réparation : {{success}} mis à jour, {{failed}} échecs",
+ "description": "Complète les dimensions manquantes (largeur/hauteur) pour les photos anciennes. Requis pour les mises en page Masonry et Mosaic."
+ },
+ "updateNotifications": {
+ "title": "Notifications de mise à jour",
+ "description": "Recevez des e-mails quand une nouvelle version de PicPeak est disponible.",
+ "enableEmails": "Activer les notifications par e-mail",
+ "enableEmailsDesc": "Informer les admins des nouvelles versions",
+ "recipients": "Destinataires",
+ "recipientsPlaceholder": "admin@exemple.com, autre@exemple.com",
+ "recipientsHelper": "Adresses séparées par des virgules. Laissez vide pour tous les admins.",
+ "lastNotified": "Dernière notification pour la version : {{version}}",
+ "checkNow": "Vérifier et notifier",
+ "sendTest": "Envoyer un e-mail test",
+ "saved": "Paramètres enregistrés",
+ "saveError": "Échec de l'enregistrement",
+ "emailSent": "E-mail de notification envoyé à {{count}} destinataires",
+ "emailFailed": "Échec de l'envoi",
+ "checkSuccess": "Notification envoyée pour la nouvelle version",
+ "checkNoAction": "Aucune notification nécessaire : {{reason}}",
+ "checkError": "Échec de la vérification"
+ },
+ "events": {
+ "title": "Création d'événement",
+ "requiredFields": "Champs requis",
+ "requiredFieldsDescription": "Configurez les champs obligatoires lors de la création d'événements.",
+ "requireCustomerName": "Exiger le nom du client",
+ "requireCustomerNameHelp": "Le nom du client doit être fourni",
+ "requireCustomerEmail": "Exiger l'e-mail du client",
+ "requireCustomerEmailHelp": "L'e-mail du client doit être fourni",
+ "customerEmailWarning": "Requis pour l'envoi des invitations",
+ "requireAdminEmail": "Exiger l'e-mail admin",
+ "requireAdminEmailHelp": "L'e-mail admin doit être fourni",
+ "adminEmailWarning": "Requis pour les notifications d'événement",
+ "requireEventDate": "Exiger la date de l'événement",
+ "requireEventDateHelp": "La date doit être fournie à la création",
+ "eventDateWarning": "Les URLs utiliseront des identifiants aléatoires sans date",
+ "requireExpiration": "Exiger une date d'expiration",
+ "requireExpirationHelp": "Les galeries doivent avoir une expiration",
+ "expirationWarning": "Sans expiration, les galeries restent actives jusqu'à archivage manuel",
+ "saveSettings": "Enregistrer les paramètres d'événement",
+ "noteTitle": "Note",
+ "noteText": "Ces paramètres n'affectent que les nouveaux événements. Par défaut, tous les champs sont requis."
+ },
+ "imageSecurity": {
+ "title": "Protection de l'image",
+ "saveSuccess": "Paramètres de sécurité enregistrés",
+ "saveError": "Échec de l'enregistrement",
+ "loadError": "Échec du chargement des paramètres de sécurité",
+ "defaultProtection": "Paramètres de protection par défaut",
+ "defaultProtectionHelp": "S'appliquent à tous les nouveaux événements.",
+ "protectionLevel": "Niveau de protection par défaut",
+ "imageQuality": "Qualité d'image par défaut",
+ "fragmentationLevel": "Niveau de fragmentation",
+ "enableDevtools": "Activer la détection DevTools par défaut",
+ "enableCanvas": "Activer le rendu Canvas par défaut (protection avancée)",
+ "rateLimiting": "Limitation de débit",
+ "rateLimitingHelp": "Limite le nombre de requêtes d'images pour éviter le siphonnage.",
+ "requestsPerMinute": "Requêtes par minute",
+ "requestsPer5Minutes": "Requêtes par 5 min",
+ "requestsPerHour": "Requêtes par heure",
+ "securityMonitoring": "Surveillance de sécurité",
+ "suspiciousThreshold": "Seuil d'activité suspecte",
+ "autoBlockThreshold": "Seuil de blocage automatique",
+ "enableMonitoring": "Activer la surveillance",
+ "blockSuspiciousIps": "Bloquer automatiquement les IPs suspectes",
+ "logEvents": "Journaliser les événements de sécurité",
+ "infoTitle": "À propos de la protection",
+ "infoText": "Ces fonctionnalités freinent le téléchargement sauvage mais ne peuvent tout bloquer. Envisagez l'usage de filigranes."
+ },
+ "moderation": {
+ "title": "Modération",
+ "wordFilters": "Filtres de mots",
+ "description": "Gérer les mots à filtrer ou bloquer dans les commentaires",
+ "addFilter": "Ajouter un filtre",
+ "enterWord": "Mot à filtrer",
+ "searchFilters": "Rechercher...",
+ "filterAdded": "Filtre ajouté avec succès",
+ "filterExists": "Ce filtre existe déjà",
+ "addError": "Échec de l'ajout",
+ "filterUpdated": "Filtre mis à jour",
+ "updateError": "Échec de la mise à jour",
+ "filterDeleted": "Filtre supprimé",
+ "deleteError": "Échec de la suppression",
+ "wordRequired": "Veuillez entrer un mot",
+ "confirmDelete": "Supprimer ce filtre ?",
+ "loading": "Chargement...",
+ "noMatchingFilters": "Aucun filtre correspondant",
+ "noFilters": "Aucun filtre configuré",
+ "severityLow": "Faible",
+ "severityModerate": "Modéré",
+ "severityHigh": "Élevé",
+ "severityBlock": "Bloquer",
+ "severityLevels": "Niveaux de gravité",
+ "lowDescription": "Signalé mais non bloqué",
+ "moderateDescription": "Approbation manuelle requise",
+ "highDescription": "Masqué automatiquement, revue admin requise",
+ "blockDescription": "Rejet immédiat du commentaire"
+ },
+ "styling": {
+ "title": "CSS Personnalisé"
+ },
+ "thumbnails": {
+ "title": "Vignettes",
+ "dimensionsTitle": "Dimensions et qualité des vignettes",
+ "dimensionsHelp": "Configurez la taille et la qualité. Des valeurs plus hautes augmentent la charge et le stockage.",
+ "width": "Largeur (px)",
+ "widthHelp": "50-1000 pixels",
+ "height": "Hauteur (px)",
+ "heightHelp": "50-1000 pixels",
+ "quality": "Qualité",
+ "qualityHelp": "1-100, plus élevé = meilleure qualité",
+ "format": "Format",
+ "fit": "Mode d'ajustement",
+ "fitHelp": "Comment l'image est redimensionnée. 'Cover' remplit, 'Contain' ajuste dans le cadre.",
+ "fit_cover": "Cover (remplir et couper)",
+ "fit_contain": "Contain (ajuster à l'intérieur)",
+ "fit_fill": "Fill (étirer)",
+ "fit_inside": "Inside (réduire pour ajuster)",
+ "fit_outside": "Outside (étendre pour couvrir)",
+ "regenerateTitle": "Régénérer les vignettes",
+ "regenerateHelp": "Lancez ceci après avoir changé les réglages. S'exécute en arrière-plan.",
+ "regenerateButton": "Régénérer toutes les vignettes",
+ "regenerateStarted": "Régénération démarrée",
+ "regenerateError": "Échec du lancement",
+ "saveSuccess": "Paramètres enregistrés",
+ "saveError": "Échec de l'enregistrement",
+ "loadError": "Échec du chargement",
+ "infoTitle": "À propos des vignettes",
+ "infoText": "Ce sont des aperçus réduits de vos originaux."
+ },
+ "seo": {
+ "title": "SEO et Robots",
+ "indexingTitle": "Indexation moteurs de recherche",
+ "allowIndexing": "Autoriser l'indexation",
+ "allowIndexingHelp": "Si désactivé, les robots sont bloqués via robots.txt. Recommandé pour le privé.",
+ "sitemapUrl": "URL du Sitemap",
+ "sitemapUrlHelp": "Optionnel. Ajouté au robots.txt.",
+ "aiBlockingTitle": "Blocage IA et Robots",
+ "blockAiCrawlers": "Bloquer les robots d'IA/LLM",
+ "blockAiCrawlersHelp": "Empêche l'entraînement des IA sur vos contenus.",
+ "blockedAgents": "Agents IA bloqués",
+ "addAgentPlaceholder": "Nom de l'agent...",
+ "blockSocialBots": "Bloquer les robots de réseaux sociaux",
+ "blockSocialBotsHelp": "Empêche les aperçus sur Twitter, FB, etc.",
+ "metaTagsTitle": "Meta Tags et Règles",
+ "metaNoindex": "Ajouter meta noindex",
+ "metaNoindexHelp": "Complète le robots.txt au niveau HTML.",
+ "metaNofollow": "Ajouter meta nofollow",
+ "metaNofollowHelp": "Dit aux moteurs de ne pas suivre les liens.",
+ "metaNoai": "Ajouter meta noai/noimageai",
+ "metaNoaiHelp": "Signale que le contenu ne doit pas servir à l'IA.",
+ "customRules": "Règles robots.txt personnalisées",
+ "ruleAgentPlaceholder": "User-agent",
+ "rulePathPlaceholder": "Chemin interdit",
+ "showPreview": "Aperçu robots.txt",
+ "hidePreview": "Masquer l'aperçu",
+ "saveSettings": "Enregistrer SEO"
+ },
+ "analytics": {
+ "title": "Analytique",
+ "umamiIntegration": "Intégration Umami",
+ "enableUmami": "Activer Umami Analytics",
+ "umamiUrl": "URL Umami",
+ "umamiUrlHelp": "Ex: https://analytics.votredomaine.com",
+ "websiteId": "ID du site",
+ "websiteIdHelp": "Trouvé dans votre tableau de bord Umami",
+ "shareUrl": "URL de partage (Optionnel)",
+ "shareUrlHelp": "Pour intégrer le tableau de bord complet",
+ "umamiInfo": "À propos d'Umami",
+ "umamiInfoText": "Plateforme open-source respectueuse de la vie privée, sans cookies.",
+ "learnMore": "En savoir plus sur Umami",
+ "saveAnalyticsSettings": "Enregistrer les paramètres",
+ "backendAnalytics": "Analytique Backend",
+ "backendAnalyticsText": "Le système suit des mesures de base pour la sécurité.",
+ "tracked": "Mesures suivies",
+ "galleryViews": "Vues des galeries",
+ "photoDownloads": "Téléchargements (unité et groupe)",
+ "uniqueVisitors": "Visiteurs uniques par IP",
+ "deviceTypes": "Types d'appareils",
+ "privacy": "Vie privée",
+ "privacyText": "Les adresses IP sont hachées. Rétention : 90 jours."
+ }
+ },
+ "analytics": {
+ "title": "Tableau de bord analytique",
+ "titleSimple": "Analytique",
+ "subtitle": "Suivi des performances et de l'engagement",
+ "detailedSubtitle": "Analyses détaillées via Umami",
+ "loadingAnalytics": "Chargement...",
+ "showSummaryView": "Vue Résumé",
+ "fullDashboard": "Tableau de bord complet",
+ "refresh": "Actualiser",
+ "last7Days": "7 derniers jours",
+ "last30Days": "30 derniers jours",
+ "last90Days": "90 derniers jours",
+ "pageViews": "Vues de pages",
+ "uniqueVisitors": "Visiteurs uniques",
+ "totalDownloads": "Total téléchargements",
+ "topGallery": "Meilleure galerie",
+ "topPages": "Pages les plus vues",
+ "views": "vues",
+ "visitors": "visiteurs uniques",
+ "topDownloadsByGallery": "Téléchargements par galerie",
+ "deviceBreakdown": "Répartition par appareil",
+ "desktop": "Ordinateur",
+ "mobile": "Mobile",
+ "tablet": "Tablette",
+ "storageUsage": "Usage stockage",
+ "used": "Utilisé",
+ "of": "sur",
+ "totalPhotos": "Total photos",
+ "activeEvents": "Événements actifs",
+ "notConfigured": "Umami non configuré",
+ "configureInstructions": "Configurez Umami dans vos variables d'environnement.",
+ "noData": "Aucune donnée disponible",
+ "percentChange": "{{percent}}% par rapport à la période précédente"
+ },
+ "branding": {
+ "title": "Identité et Thèmes",
+ "titleFull": "Personnalisation de marque",
+ "subtitle": "Personnalisez l'apparence de vos galeries",
+ "loadingBranding": "Chargement...",
+ "themeAndStyle": "Thème et Style",
+ "companyInfo": "Informations entreprise",
+ "companyName": "Nom de l'entreprise",
+ "companyNameHelp": "Affiché dans les en-têtes et e-mails",
+ "companyTagline": "Slogan",
+ "companyTaglineHelp": "Courte description de votre activité",
+ "supportEmail": "E-mail de support",
+ "supportEmailHelp": "Contact pour l'aide aux invités",
+ "footerText": "Texte de pied de page",
+ "footerTextHelp": "Affiché en bas des galeries",
+ "logo": "Logo",
+ "currentLogo": "Logo actuel",
+ "uploadLogo": "Téléverser logo",
+ "removeLogo": "Retirer logo",
+ "logoHelp": "Taille recommandée : 200x60px, PNG ou JPEG",
+ "favicon": "Favicon",
+ "currentFavicon": "Favicon actuel",
+ "uploadFavicon": "Téléverser favicon",
+ "removeFavicon": "Retirer favicon",
+ "faviconHelp": "Format PNG ou ICO, 32x32px recommandé",
+ "watermark": "Filigrane",
+ "watermarkSettings": "Paramètres filigrane",
+ "enableWatermarks": "Activer les filigranes",
+ "watermarkHelp": "Ajoute le nom de votre entreprise sur les photos téléchargées",
+ "watermarkLogo": "Logo de filigrane",
+ "currentWatermark": "Filigrane actuel",
+ "uploadWatermarkLogo": "Téléverser logo filigrane",
+ "watermarkPosition": "Position filigrane",
+ "topLeft": "Haut Gauche",
+ "topRight": "Haut Droite",
+ "center": "Centre",
+ "bottomLeft": "Bas Gauche",
+ "bottomRight": "Bas Droite",
+ "watermarkOpacity": "Opacité filigrane",
+ "watermarkSize": "Taille filigrane",
+ "theme": "Thème",
+ "galleryTheme": "Thème galerie",
+ "themeCustomization": "Personnalisation thème",
+ "selectPreset": "Sélectionner un préréglage",
+ "colors": "Couleurs",
+ "primaryColor": "Couleur primaire",
+ "secondaryColor": "Couleur secondaire",
+ "accentColor": "Couleur d'accentuation",
+ "backgroundColor": "Couleur de fond",
+ "textColor": "Couleur de texte",
+ "colorMode": "Mode de couleur",
+ "colorModeLight": "Clair",
+ "colorModeDark": "Sombre",
+ "colorModeAuto": "Auto",
+ "colorModeHelp": "Auto suit les préférences système de l'invité.",
+ "customCSS": "CSS personnalisé",
+ "preview": "Aperçu",
+ "previewInNewTab": "Aperçu (nouvel onglet)",
+ "reset": "Réinitialiser",
+ "saveChanges": "Enregistrer",
+ "applyLivePreview": "Appliquer immédiatement (Aperçu direct)",
+ "eventSpecificThemes": "Thèmes spécifiques par événement",
+ "eventThemesInfo": "Vous pouvez surcharger ces paramètres globaux pour chaque événement.",
+ "themePresets": "Préréglages de thème",
+ "galleryLayout": "Mise en page",
+ "layoutDescriptions": {
+ "grid": "Grille classique, tailles uniformes",
+ "masonry": "Style Pinterest, hauteurs variables",
+ "carousel": "Diaporama plein écran",
+ "timeline": "Photos triées par date",
+ "hero": "Image mise en avant avec grille en dessous",
+ "mosaic": "Mosaïque artistique, tailles mixtes",
+ "justified": "Lignes justifiées préservant les ratios",
+ "gallery-premium": "Thème clair élégant avec hero et masonry (Beta)",
+ "gallery-story": "Thème sombre cinématique avec sections (Beta)"
+ },
+ "layoutSettings": "Paramètres de mise en page",
+ "photoSpacing": "Espacement des photos",
+ "spacing": {
+ "tight": "Serré",
+ "normal": "Normal",
+ "relaxed": "Espacé"
+ },
+ "photoAnimation": "Animations photos",
+ "animation": {
+ "none": "Aucune",
+ "fade": "Fondu",
+ "scale": "Zoom",
+ "slide": "Glissement"
+ },
+ "columns": "Colonnes",
+ "mobile": "Mobile",
+ "tablet": "Tablette",
+ "desktop": "Ordinateur",
+ "enableAutoplay": "Lecture auto",
+ "autoplayInterval": "Intervalle lecture auto (s)",
+ "groupPhotosBy": "Grouper par",
+ "grouping": {
+ "day": "Jour",
+ "week": "Semaine",
+ "month": "Mois"
+ },
+ "masonryMode": "Mode de mise en page",
+ "masonryModeOptions": {
+ "columns": "Colonnes (Pinterest)",
+ "rows": "Lignes (Justifié personnalisé)",
+ "flickr": "Flickr (Justifié robuste)",
+ "justified": "Google Photos (Algorithme Knuth-Plass)"
+ },
+ "masonryModeHint": {
+ "columns": "Colonnes verticales style Pinterest",
+ "rows": "Lignes justifiées personnalisées",
+ "flickr": "Algorithme de Flickr pour le justifié",
+ "justified": "Lignes style Google Photos pour des coupures optimales"
+ },
+ "targetRowHeight": "Hauteur de ligne cible",
+ "targetRowHeightHint": "En pixels (150-400). Les photos s'adapteront aux lignes.",
+ "lastRowBehavior": "Alignement dernière ligne",
+ "lastRowOptions": {
+ "left": "Aligné à gauche",
+ "center": "Centré",
+ "justify": "Justifié (étiré)"
+ },
+ "showHeroSection": "Afficher la section Hero",
+ "showHeroSectionHint": "Affiche une image principale au-dessus de la galerie",
+ "heroHeight": "Hauteur section Hero",
+ "heroHeightOptions": {
+ "small": "Petit (40-50%)",
+ "medium": "Moyen (50-70%)",
+ "large": "Grand (60-80%)"
+ },
+ "heroOverlayOpacity": "Opacité superposition Hero",
+ "heroOverlayHint": "Assombrit l'image pour la lisibilité du texte",
+ "typographyAndStyle": "Typographie et Style",
+ "bodyFont": "Police de corps",
+ "headingFont": "Police de titre",
+ "sameAsBody": "Identique au corps",
+ "fontSize": "Taille de police",
+ "fontSizes": {
+ "small": "Petit",
+ "normal": "Normal",
+ "large": "Grand"
+ },
+ "borderRadius": "Arrondi des coins",
+ "borderRadiusOptions": {
+ "none": "Aucun",
+ "small": "Petit",
+ "medium": "Moyen",
+ "large": "Grand"
+ },
+ "shadowStyle": "Style d'ombre",
+ "shadowOptions": {
+ "none": "Aucune",
+ "subtle": "Subtile",
+ "normal": "Normale",
+ "dramatic": "Prononcée"
+ },
+ "backgroundPattern": "Fond",
+ "backgroundOptions": {
+ "none": "Uni",
+ "dots": "Points",
+ "grid": "Grille",
+ "waves": "Vagues"
+ },
+ "customCSSHelp": "Avancé : Ajoutez du CSS pour personnaliser davantage",
+ "cssInstructions": {
+ "title": "Usage du CSS personnalisé",
+ "variables": "Variables CSS du thème",
+ "variablesDesc": "Utilisez ces variables pour correspondre au thème :",
+ "layouts": "Éléments de mise en page",
+ "layoutsDesc": "Ciblez les éléments avec ces sélecteurs :",
+ "glassEffect": "Effet Glassmorphism",
+ "glassEffectDesc": "Pour des effets de verre modernes :",
+ "tip": "Astuce",
+ "tipText": "Utilisez les modèles CSS depuis les Paramètres pour des designs comme Apple Liquid Glass."
+ },
+ "resetToDefault": "Réinitialiser",
+ "applyTheme": "Appliquer le thème",
+ "customTheme": "Thème personnalisé",
+ "customizeTheme": "Personnaliser le thème",
+ "saveTheme": "Enregistrer le thème",
+ "previewLayout": "Aperçu mise en page",
+ "livePreview": "Aperçu direct",
+ "heroPlaceholderText": "L'image Hero de l'événement apparaîtra ici",
+ "whiteLabel": "Marque blanche",
+ "hidePoweredBy": "Masquer la mention \"Powered by PicPeak\"",
+ "hidePoweredByHelp": "Retire l'attribution PicPeak du pied de page",
+ "logoCustomization": "Personnalisation du logo",
+ "changeLogo": "Changer le logo",
+ "logoSizeSmall": "Petit (32px)",
+ "logoSizeMedium": "Moyen (48px)",
+ "logoSizeLarge": "Grand (64px)",
+ "logoSizeXLarge": "Très Grand (96px)",
+ "logoSizeCustom": "Personnalisé",
+ "logoMaxHeight": "Hauteur maximale (pixels)",
+ "logoMaxHeightHelp": "Hauteur personnalisée (20-200 pixels)",
+ "logoPosition": "Position du logo dans l'en-tête",
+ "positionLeft": "Gauche",
+ "positionCenter": "Centre",
+ "positionRight": "Droite",
+ "logoDisplayMode": "Mode d'affichage",
+ "logoOnly": "Logo uniquement",
+ "textOnly": "Nom d'entreprise uniquement",
+ "logoAndText": "Logo et Nom d'entreprise",
+ "showLogoInHeader": "Logo dans l'en-tête",
+ "showLogoInHeaderHelp": "Afficher le logo dans la barre d'en-tête",
+ "showLogoInHero": "Logo dans la section Hero",
+ "showLogoInHeroHelp": "Afficher le logo dans la section principale",
+ "headerStyle": "Style d'en-tête",
+ "headerStyleDescription": "Choisissez l'apparence de l'en-tête.",
+ "headerStyleOptions": {
+ "hero": "Image Hero",
+ "standard": "Bannière standard",
+ "minimal": "Minimaliste",
+ "none": "Aucun en-tête"
+ },
+ "headerStyleDescriptions": {
+ "hero": "Image pleine hauteur avec infos superposées",
+ "standard": "Bannière classique avec détails",
+ "minimal": "En-tête compact avec infos essentielles",
+ "none": "Masquer complètement l'en-tête"
+ },
+ "heroDividerStyle": "Style de séparateur",
+ "heroDividerDescription": "Forme de la transition sous l'image Hero.",
+ "dividerOptions": {
+ "wave": "Vague",
+ "straight": "Droit",
+ "angle": "Angle",
+ "curve": "Courbe",
+ "none": "Aucun"
+ },
+ "controlsStyle": "Style des contrôles",
+ "controlsStyleDescription": "Affichage des filtres et contrôles.",
+ "controlsStyleOptions": {
+ "classic": "Classique",
+ "sidebar": "Barre latérale"
+ },
+ "controlsStyleDescriptions": {
+ "classic": "Barre de filtres sous l'en-tête",
+ "sidebar": "Bouton menu ouvrant un volet latéral"
+ },
+ "controlsStyleHeroWarning": "La barre latérale est recommandée pour les en-têtes Hero."
+ },
+ "admin": {
+ "title": "Panneau d'administration",
+ "welcome": "Bon retour, {{name}}",
+ "recentActivity": "Activité récente",
+ "systemStatus": "Statut système",
+ "totalEvents": "Total événements",
+ "activeGalleries": "Galeries actives",
+ "storageUsed": "Stockage utilisé",
+ "totalPhotos": "Total photos",
+ "storagePercent": "{{percent}}% de la limite {{limit}}",
+ "storageSoftLimitConfigured": "Limite configurée : {{limit}}",
+ "storageSoftLimitRecommended": "Limite suggérée : {{limit}}",
+ "version": "Version",
+ "archivedEvents": "Événements archivés",
+ "systemHealth": "Santé système",
+ "health": {
+ "healthy": "Sain",
+ "warning": "Attention",
+ "error": "Erreur",
+ "checking": "Vérification..."
+ },
+ "updates": {
+ "available": "Mise à jour disponible",
+ "newVersion": "La version {{version}} est disponible",
+ "currentVersion": "Actuelle : {{version}}",
+ "channel": "Canal : {{channel}}",
+ "channelStable": "Stable",
+ "channelBeta": "Beta",
+ "beta": "BETA",
+ "viewReleaseNotes": "Notes de version",
+ "updateAvailableShort": "v{{version}} disponible",
+ "checkForUpdates": "Vérifier les mises à jour",
+ "upToDate": "À jour",
+ "lastChecked": "Vérifié à : {{time}}",
+ "updateNow": "Mettre à jour",
+ "updateDialog": {
+ "title": "Mettre à jour PicPeak",
+ "detectedEnv": "Environnement détecté",
+ "beforeUpdating": "Avant de mettre à jour :",
+ "updateCommands": "Commandes :",
+ "afterUpdating": "Après mise à jour :",
+ "copyAllCommands": "Copier les commandes",
+ "completeChecklist": "Complétez la liste avant de lancer",
+ "error": "Échec du chargement des instructions"
+ }
+ },
+ "notifications": "Notifications",
+ "viewAllNotifications": "Toutes les notifications",
+ "noNotifications": "Aucune nouvelle notification",
+ "markAllRead": "Tout marquer comme lu",
+ "clearAll": "Tout effacer",
+ "close": "Fermer",
+ "noNotificationsMessage": "Pas de notifications",
+ "notificationMessages": {
+ "eventCreated": "Nouvel événement \"{{eventName}}\" créé",
+ "eventArchived": "Événement \"{{eventName}}\" archivé",
+ "eventUpdated": "Événement \"{{eventName}}\" mis à jour",
+ "eventDeleted": "Événement \"{{eventName}}\" supprimé",
+ "photosUploaded": "{{count}} photos téléversées dans \"{{eventName}}\"",
+ "photoDeleted": "Photo supprimée de \"{{eventName}}\"",
+ "photosBulkDeleted": "{{count}} photos supprimées de \"{{eventName}}\"",
+ "eventExpiring": "L'événement \"{{eventName}}\" expire dans {{days}} jours",
+ "eventExpired": "L'événement \"{{eventName}}\" a expiré",
+ "passwordChanged": "Mot de passe changé par {{actorName}}",
+ "passwordReset": "Réinitialisation du mot de passe pour \"{{eventName}}\"",
+ "settingsUpdated": "Paramètres {{type}} mis à jour",
+ "emailTemplateUpdated": "Modèle d'e-mail \"{{template}}\" mis à jour",
+ "bulkDownload": "{{count}} photos téléchargées depuis \"{{eventName}}\"",
+ "storageWarning": "Usage stockage à {{percentage}}%",
+ "adminLogout": "Déconnexion admin {{actorName}}",
+ "categoryCreated": "Catégorie \"{{name}}\" créée pour \"{{eventName}}\"",
+ "categoryUpdated": "Catégorie \"{{name}}\" mise à jour",
+ "categoryDeleted": "Catégorie \"{{name}}\" supprimée",
+ "cmsPageUpdated": "Page CMS \"{{slug}}\" mise à jour",
+ "emailConfigUpdated": "Configuration e-mail mise à jour",
+ "faviconUploaded": "Favicon téléversé",
+ "brandingUpdated": "Paramètres d'identité mis à jour",
+ "generalSettingsUpdated": "Paramètres généraux mis à jour",
+ "securitySettingsUpdated": "Paramètres de sécurité mis à jour",
+ "themeUpdated": "Thème mis à jour",
+ "archiveDownloaded": "Archive téléchargée pour \"{{eventName}}\"",
+ "archiveDeleted": "Archive supprimée pour \"{{eventName}}\"",
+ "archiveRestored": "Archive restaurée pour \"{{eventName}}\"",
+ "systemActivity": "Activité système : {{type}}",
+ "adminProfileUpdated": "Profil admin mis à jour par {{actorName}}"
+ },
+ "notificationToasts": {
+ "markedAllRead": "Toutes les notifications sont lues",
+ "clearedAll": "{{count}} notifications effacées",
+ "profileUpdated": "Profil admin mis à jour"
+ },
+ "markAsRead": "Marquer comme lu",
+ "markAllAsRead": "Tout marquer comme lu",
+ "notificationSettings": "Paramètres de notification",
+ "changePassword": "Changer le mot de passe",
+ "darkMode": "Passer au mode sombre",
+ "lightMode": "Passer au mode clair",
+ "accountSettings": {
+ "title": "Compte admin",
+ "description": "Modifier les accès de connexion à PicPeak.",
+ "username": "Nom d'utilisateur",
+ "usernamePlaceholder": "Admin",
+ "email": "E-mail",
+ "emailPlaceholder": "admin@exemple.com",
+ "updateButton": "Mettre à jour le profil"
+ },
+ "profileUpdateError": "Impossible de mettre à jour le profil. Réessayez.",
+ "loadingDashboard": "Chargement du tableau de bord...",
+ "activeEvents": "Événements actifs",
+ "expiringSoon": "Expire bientôt",
+ "next7Days": "7 prochains jours",
+ "totalViews": "Vues totales",
+ "downloads": "Téléchargements",
+ "percentFromLastWeek": "{{percent}}% depuis la semaine dernière",
+ "dashboardSubtitle": "Bon retour ! Voici l'état de vos galeries.",
+ "eventsExpiringSoon": "Événements expirant bientôt",
+ "noEventsExpiring": "Aucun événement n'expire dans les 7 prochains jours",
+ "daysLeft": "{{count}} jour restant",
+ "daysLeft_plural": "{{count}} jours restants",
+ "viewAllExpiringEvents": "Voir les {{count}} événements expirants",
+ "noRecentActivity": "Aucune activité récente",
+ "viewAllActivity": "Toute l'activité",
+ "quickActions": "Actions rapides",
+ "viewArchives": "Voir les archives",
+ "analytics": "Analytique",
+ "activities": {
+ "event_created": "Nouvel événement : {{eventName}}",
+ "photos_uploaded": "{{count}} photos téléversées : {{eventName}}",
+ "event_archived": "Événement archivé : {{eventName}}",
+ "archive_restored": "Archive restaurée : {{eventName}}",
+ "archive_deleted": "Archive supprimée : {{eventName}}",
+ "archive_downloaded": "Archive téléchargée : {{eventName}}",
+ "email_config_updated": "Configuration e-mail mise à jour",
+ "email_template_updated": "Modèle d'e-mail mis à jour : {{template}}",
+ "branding_updated": "Identité visuelle mise à jour",
+ "theme_updated": "Thème mis à jour",
+ "bulk_download": "{{count}} photos téléchargées : {{eventName}}",
+ "gallery_password_entry": "Mot de passe saisi pour {{eventName}}",
+ "expiration_warning_viewed": "Avertissement d'expiration vu pour {{eventName}}",
+ "feedback_settings_updated": "Paramètres d'avis mis à jour",
+ "feedback_moderated": "Avis modéré",
+ "feedback_deleted": "Avis supprimé",
+ "photo_like": "Photo aimée dans {{eventName}}",
+ "photo_favorite": "Photo mise en favoris dans {{eventName}}",
+ "photo_rating": "Photo notée dans {{eventName}}",
+ "photo_comment": "Commentaire sur photo dans {{eventName}}",
+ "guest_feedback_like": "Un invité a aimé une photo dans {{eventName}}",
+ "guest_feedback_favorite": "Un invité a mis une photo en favoris dans {{eventName}}",
+ "guest_feedback_rating": "Un invité a noté une photo dans {{eventName}}",
+ "guest_feedback_comment": "Un invité a commenté une photo dans {{eventName}}",
+ "word_filter_added": "Filtre de mot ajouté",
+ "external_import_completed": "Import externe terminé ({{imported}} importés, {{skipped}} ignorés)",
+ "bulk_archive_completed": "Archivage groupé terminé",
+ "event_activated": "Événement activé : {{eventName}}",
+ "event_deactivated": "Événement désactivé : {{eventName}}",
+ "photo_deleted": "Photo supprimée de {{eventName}}",
+ "photos_bulk_deleted": "{{count}} photos supprimées de {{eventName}}",
+ "settings_updated": "Paramètres mis à jour",
+ "event_updated": "Événement mis à jour : {{eventName}}",
+ "event_renamed": "Événement renommé : {{eventName}}",
+ "event_deleted": "Événement supprimé : {{eventName}}",
+ "password_changed": "Mot de passe changé",
+ "email_resent": "E-mail de création renvoyé pour : {{eventName}}",
+ "category_created": "Catégorie créée : {{categoryName}}",
+ "category_updated": "Catégorie mise à jour : {{categoryName}}",
+ "category_deleted": "Catégorie supprimée : {{categoryName}}",
+ "general_settings_updated": "Paramètres généraux mis à jour",
+ "favicon_uploaded": "Favicon téléversé",
+ "analytics_settings_updated": "Paramètres analytiques mis à jour",
+ "cms_page_updated": "Page CMS mise à jour : {{page}}",
+ "security_settings_updated": "Paramètres de sécurité mis à jour",
+ "password_reset": "Mot de passe réinitialisé pour : {{eventName}}",
+ "admin_logout": "Déconnexion admin {{actorName}}",
+ "system_activity": "Activité système : {{type}}",
+ "unknown": "Activité inconnue"
+ },
+ "userManagement": "Gestion utilisateurs",
+ "inviteUser": "Inviter",
+ "pendingInvitations": "Invitations en attente",
+ "roles": {
+ "super_admin": "Super Admin",
+ "admin": "Admin",
+ "editor": "Éditeur",
+ "viewer": "Spectateur"
+ },
+ "userStatus": {
+ "active": "Actif",
+ "inactive": "Inactif"
+ },
+ "inviteForm": {
+ "email": "Adresse e-mail",
+ "role": "Rôle",
+ "send": "Envoyer l'invitation"
+ },
+ "acceptInvite": {
+ "title": "Accepter l'invitation admin",
+ "username": "Nom d'utilisateur",
+ "password": "Mot de passe",
+ "submit": "Créer le compte"
+ }
+ },
+ "permissions": {
+ "insufficient": "Permissions insuffisantes pour cette action",
+ "viewOnly": "Lecture seule"
+ },
+ "acceptInvitation": {
+ "title": "Accepter l'invitation",
+ "subtitle": "Créez votre compte administrateur",
+ "validating": "Validation de l'invitation...",
+ "invalidToken": "Invitation invalide",
+ "invalidTokenMessage": "Ce lien est invalide ou a expiré. Contactez l'administrateur.",
+ "expiredToken": "Invitation expirée",
+ "expiredTokenMessage": "Cette invitation a expiré.",
+ "alreadyUsed": "Invitation déjà utilisée",
+ "alreadyUsedMessage": "Cette invitation a déjà servi à créer un compte.",
+ "invitedAs": "Vous avez été invité en tant que",
+ "expiresAt": "L'invitation expire",
+ "usernameLabel": "Nom d'utilisateur",
+ "usernamePlaceholder": "Choisissez un nom d'utilisateur",
+ "usernameHelp": "3-50 car., lettres, chiffres, underscores et tirets uniquement",
+ "passwordLabel": "Mot de passe",
+ "passwordPlaceholder": "Créez un mot de passe robuste",
+ "confirmPasswordLabel": "Confirmer le mot de passe",
+ "confirmPasswordPlaceholder": "Confirmez le mot de passe",
+ "passwordStrength": "Force du mot de passe",
+ "requirements": {
+ "title": "Exigences :",
+ "minLength": "Au moins 12 caractères",
+ "uppercase": "Au moins une majuscule",
+ "lowercase": "Au moins une minuscule",
+ "number": "Au moins un chiffre",
+ "special": "Au moins un caractère spécial"
+ },
+ "strength": {
+ "weak": "Faible",
+ "fair": "Passable",
+ "good": "Bon",
+ "strong": "Robuste"
+ },
+ "createAccount": "Créer le compte",
+ "creating": "Création du compte...",
+ "success": "Compte créé !",
+ "successMessage": "Compte créé avec succès. Vous pouvez maintenant vous connecter.",
+ "redirecting": "Redirection vers la connexion dans {{seconds}}...",
+ "goToLogin": "Aller à la connexion",
+ "contactAdminMessage": "Veuillez contacter l'administrateur pour une nouvelle invitation.",
+ "passwordsMatch": "Les mots de passe correspondent",
+ "alreadyHaveAccount": "Déjà un compte ?",
+ "signIn": "Se connecter",
+ "errors": {
+ "usernameRequired": "Nom d'utilisateur requis",
+ "usernameTooShort": "Minimum 3 caractères",
+ "usernameTooLong": "Maximum 50 caractères",
+ "usernameInvalid": "Caractères invalides",
+ "passwordRequired": "Mot de passe requis",
+ "passwordTooShort": "Minimum 12 caractères",
+ "passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
+ "confirmPasswordRequired": "Veuillez confirmer le mot de passe",
+ "usernameTaken": "Ce nom d'utilisateur est déjà pris",
+ "emailTaken": "Un compte existe déjà avec cet e-mail",
+ "genericError": "Échec de la création. Réessayez."
+ }
+ },
+ "errors": {
+ "notFound": "Non trouvé",
+ "galleryNotFound": "Galerie non trouvée",
+ "galleryNotFoundMessage": "Cette galerie n'existe pas ou a été supprimée.",
+ "galleryArchived": "Galerie archivée",
+ "galleryArchivedMessage": "Cette galerie a été archivée et n'est plus accessible.",
+ "unauthorized": "Non autorisé",
+ "forbidden": "Interdit",
+ "serverError": "Erreur serveur",
+ "somethingWentWrong": "Un problème est survenu",
+ "tryAgainLater": "Veuillez réessayer plus tard",
+ "refreshPage": "Actualiser la page",
+ "oopsSomethingWentWrong": "Oups ! Un problème est survenu",
+ "unexpectedError": "Erreur inattendue. Vos données sont en sécurité.",
+ "goToHomepage": "Retour à l'accueil",
+ "errorDetails": "Détails de l'erreur",
+ "requiredFields": "Veuillez remplir tous les champs requis",
+ "enterTestEmail": "Veuillez entrer une adresse e-mail de test",
+ "failedToCreateEvent": "Échec de la création de l'événement",
+ "eventCreationFailed": "Échec de la création de l'événement",
+ "networkError": "Erreur réseau. Vérifiez votre connexion.",
+ "sessionExpired": "Session expirée. Veuillez vous reconnecter."
+ },
+ "validation": {
+ "eventNameRequired": "Nom de l'événement requis",
+ "hostEmailRequired": "E-mail client requis",
+ "hostNameRequired": "Nom client requis",
+ "adminEmailRequired": "E-mail admin requis",
+ "invalidEmailFormat": "Format d'e-mail invalide",
+ "passwordRequired": "Mot de passe requis",
+ "passwordMinLength": "Le mot de passe doit faire au moins 6 caractères",
+ "passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
+ "passwordSecurityRequirements": "Le mot de passe ne respecte pas les critères de sécurité",
+ "expirationRange": "L'expiration doit être entre 1 et 365 jours"
+ },
+ "legal": {
+ "impressum": "Mentions Légales",
+ "datenschutz": "Politique de Confidentialité",
+ "termsOfService": "Conditions Générales d'Utilisation",
+ "cookiePolicy": "Politique de Cookies"
+ },
+ "toast": {
+ "saveSuccess": "Modifications enregistrées",
+ "saveError": "Échec de l'enregistrement",
+ "deleteSuccess": "Suppression réussie",
+ "deleteError": "Échec de la suppression",
+ "uploadSuccess": "Téléversement réussi",
+ "uploadError": "Échec du téléversement",
+ "loginSuccess": "Connexion réussie",
+ "loginError": "Échec de la connexion",
+ "passwordChanged": "Mot de passe modifié",
+ "linkCopied": "Lien copié dans le presse-papier",
+ "eventCreated": "Événement créé",
+ "eventUpdated": "Événement mis à jour",
+ "eventArchived": "Événement archivé",
+ "settingsSaved": "Paramètres enregistrés",
+ "themeUpdated": "Thème mis à jour",
+ "brandingUpdated": "Identité visuelle mise à jour",
+ "categoryAdded": "Catégorie ajoutée",
+ "categoryDeleted": "Catégorie supprimée",
+ "categoryUpdated": "Catégorie mise à jour",
+ "emailConfigSaved": "Configuration e-mail enregistrée",
+ "testEmailSent": "E-mail de test envoyé",
+ "pageUpdated": "Page mise à jour",
+ "archiveRestored": "Archive restaurée",
+ "archiveDeleted": "Archive supprimée définitivement"
+ },
+ "email": {
+ "title": "Configuration E-mail",
+ "subtitle": "Paramétrer les e-mails de notification",
+ "loadingSettings": "Chargement...",
+ "smtpConfiguration": "Configuration SMTP",
+ "smtpHost": "Hôte SMTP",
+ "smtpHostHelp": "Nom d'hôte du serveur e-mail",
+ "smtpPort": "Port SMTP",
+ "smtpPortHelp": "Généralement 587 (TLS), 465 (SSL) ou 25",
+ "smtpSecure": "Utiliser SSL/TLS",
+ "smtpSecureHelp": "Activer pour une transmission sécurisée",
+ "smtpUsername": "Nom d'utilisateur SMTP",
+ "smtpUsernameHelp": "Compte utilisé pour l'envoi",
+ "smtpPassword": "Mot de passe SMTP",
+ "smtpPasswordHelp": "Mot de passe du compte e-mail",
+ "fromDetails": "Expéditeur",
+ "fromEmail": "E-mail expéditeur",
+ "fromEmailHelp": "Adresse apparaissant comme expéditeur",
+ "fromName": "Nom expéditeur",
+ "fromNameHelp": "Nom apparaissant comme expéditeur",
+ "testConfiguration": "Tester la configuration",
+ "testEmail": "E-mail de test",
+ "testEmailHelp": "Envoyer un e-mail pour vérifier les paramètres",
+ "sendTestEmail": "Envoyer l'e-mail test",
+ "saveConfiguration": "Enregistrer la configuration",
+ "emailTemplates": "Modèles d'e-mails",
+ "templateVariables": "Variables disponibles",
+ "previewTemplate": "Aperçu du modèle",
+ "smtpSettings": "Paramètres SMTP",
+ "testEmailSuccess": "E-mail test envoyé",
+ "saveSmtpSettings": "Enregistrer SMTP",
+ "testEmailSection": "E-mail de test",
+ "beforeTesting": "Avant de tester :",
+ "saveSmtpFirst": "Enregistrez d'abord vos paramètres",
+ "ensureFirewall": "Vérifiez que votre pare-feu autorise le SMTP sortant",
+ "gmailAppPassword": "Pour Gmail, utilisez un mot de passe d'application",
+ "testEmailAddressLabel": "Adresse e-mail de test",
+ "sendTestEmailButton": "Envoyer e-mail test",
+ "commonSmtpSettings": "Paramètres SMTP courants :",
+ "editTemplate": "Modifier le modèle",
+ "templateName": "Nom du modèle",
+ "subjectLine": "Objet de l'e-mail",
+ "emailBody": "Corps de l'e-mail",
+ "preview": "Aperçu",
+ "saveChanges": "Enregistrer",
+ "templates": "Modèles",
+ "variableHelp": "Utilisez ces variables. Elles seront remplacées lors de l'envoi.",
+ "port": "Port",
+ "security": "Sécurité",
+ "username": "Utilisateur",
+ "password": "Mot de passe",
+ "enterPassword": "Saisir le mot de passe",
+ "required": "requis",
+ "ignoreSslErrors": "Ignorer les erreurs de certificat SSL/TLS",
+ "ignoreSslWarning": "Attention : Désactiver la vérification rend la connexion vulnérable aux attaques man-in-the-middle. N'activez ceci que si vous avez confiance en votre serveur SMTP."
+ },
+ "cms": {
+ "title": "Pages CMS",
+ "subtitle": "Gérer les pages légales et d'information",
+ "loadingPages": "Chargement...",
+ "pages": "Pages",
+ "previewLinks": "Liens d'aperçu",
+ "englishVersion": "Version Anglaise",
+ "germanVersion": "Version Allemande",
+ "editPage": "Modifier {{page}}",
+ "pageTitle": "Titre de la page",
+ "pageContent": "Contenu de la page",
+ "pageTitlePlaceholder": "Titre...",
+ "saveChanges": "Enregistrer",
+ "lastUpdated": "Dernière mise à jour :",
+ "impressum": "Mentions Légales",
+ "datenschutz": "Politique de Confidentialité",
+ "pageUpdated": "Page mise à jour"
+ },
+ "eventTypes": {
+ "title": "Types d'événements",
+ "subtitle": "Personnaliser les types d'événements et leurs thèmes par défaut",
+ "loading": "Chargement...",
+ "loadError": "Échec du chargement",
+ "createNew": "Nouveau type",
+ "edit": "Modifier le type",
+ "created": "Type créé",
+ "updated": "Type mis à jour",
+ "deleted": "Type supprimé",
+ "createError": "Échec de la création",
+ "updateError": "Échec de la mise à jour",
+ "deleteError": "Échec de la suppression",
+ "searchPlaceholder": "Rechercher...",
+ "showInactive": "Afficher inactifs",
+ "noResults": "Aucun résultat",
+ "empty": "Aucun type d'événement",
+ "system": "Système",
+ "table": {
+ "type": "Type",
+ "slugPrefix": "Préfixe URL",
+ "theme": "Thème par défaut",
+ "status": "Statut",
+ "actions": "Actions"
+ },
+ "form": {
+ "name": "Nom d'affichage",
+ "namePlaceholder": "ex: Shooting Famille",
+ "slugPrefix": "Préfixe URL",
+ "slugPrefixPlaceholder": "ex: famille",
+ "slugPreview": "Exemple d'URL :",
+ "emoji": "Icône",
+ "themePreset": "Thème par défaut",
+ "isActive": "Actif (visible à la création)"
+ },
+ "validation": {
+ "slugFormat": "Lettres, chiffres et tirets uniquement"
+ },
+ "slugInfo": {
+ "title": "Infos préfixe URL :",
+ "description": "Le préfixe sert à générer les URLs de galerie. Exemple avec 'famille' : famille-dupond-2025-01-22"
+ },
+ "deleteConfirm": {
+ "title": "Supprimer le type",
+ "message": "Voulez-vous supprimer",
+ "warning": "Action irréversible. Vérifiez qu'aucun événement ne l'utilise."
+ }
+ },
+ "backup": {
+ "external": {
+ "warning": {
+ "title": "Média externes exclus",
+ "body": "Cette installation utilise des photos de /external-media. Ces originaux sont exclus des sauvegardes. La base de données et les vignettes sont sauvegardées."
+ }
+ },
+ "title": "Gestion des sauvegardes",
+ "subtitle": "Gérer les sauvegardes système et configurer les restaurations.",
+ "tabs": {
+ "dashboard": "Tableau de bord",
+ "configuration": "Configuration",
+ "history": "Historique",
+ "restore": "Restaurer"
+ },
+ "status": {
+ "inProgress": "Sauvegarde en cours...",
+ "lastBackup": "Dernière sauvegarde",
+ "noBackups": "Aucune sauvegarde",
+ "nextBackup": "Prochaine sauvegarde",
+ "notScheduled": "Non planifiée",
+ "enabled": "Activée",
+ "disabled": "Désactivée"
+ },
+ "actions": {
+ "runBackupNow": "Lancer maintenant",
+ "starting": "Démarrage...",
+ "running": "Exécution...",
+ "testConnection": "Tester la connexion",
+ "save": "Enregistrer",
+ "delete": "Supprimer",
+ "view": "Détails",
+ "download": "Télécharger",
+ "refresh": "Actualiser"
+ },
+ "dashboard": {
+ "backupHealth": "Santé des sauvegardes",
+ "healthStatus": {
+ "excellent": "Excellente",
+ "good": "Bonne",
+ "warning": "Attention",
+ "critical": "Critique"
+ },
+ "health": {
+ "title": "Santé Sauvegarde"
+ },
+ "healthMessages": {
+ "noBackups": "Aucune sauvegarde trouvée",
+ "lastBackupFailed": "Échec de la dernière sauvegarde",
+ "upToDate": "À jour",
+ "recent": "Récente",
+ "gettingOld": "Commence à dater",
+ "outdated": "Obsolète"
+ },
+ "stats": {
+ "totalBackups": "Total sauvegardes",
+ "backupSize": "Taille sauvegarde",
+ "lastDuration": "Dernière durée",
+ "backupStatus": "Statut",
+ "last": "Dernier",
+ "files": "fichiers",
+ "minutes": "{{count}}m",
+ "active": "Actif",
+ "inactive": "Inactif",
+ "noBackupsYet": "Pas encore de sauvegardes"
+ },
+ "recentActivity": {
+ "title": "Activité récente"
+ },
+ "notConfigured": {
+ "title": "Non configuré",
+ "message": "Configurez les paramètres avant de lancer une sauvegarde."
+ },
+ "actions": {
+ "runBackupNow": "Sauvegarder maintenant",
+ "running": "En cours..."
+ },
+ "coverage": {
+ "title": "Contenu sauvegardé",
+ "database": "Base de données",
+ "photos": "Photos",
+ "archives": "Archives",
+ "systemFiles": "Fichiers système",
+ "included": "Inclus",
+ "excluded": "Exclu",
+ "optional": "Optionnel"
+ },
+ "storageDestination": "Destination",
+ "nextScheduledBackup": "Prochaine planification",
+ "backupType": "Sauvegarde {{type}}",
+ "noDestinationSet": "Pas de destination"
+ },
+ "configuration": {
+ "enableBackup": "Activer les sauvegardes auto",
+ "enableBackupHelp": "Sauvegardes automatiques selon le calendrier",
+ "destinationType": "Destination",
+ "destinationTypes": {
+ "local": {
+ "name": "Stockage local",
+ "description": "Sur le serveur de l'application"
+ },
+ "rsync": {
+ "name": "Serveur distant (Rsync)",
+ "description": "Sync via SSH/Rsync"
+ },
+ "s3": {
+ "name": "Stockage S3",
+ "description": "Amazon S3 ou compatible"
+ }
+ },
+ "fields": {
+ "destinationPath": "Chemin de destination",
+ "destinationPathHelp": "Répertoire local",
+ "destinationPathPlaceholder": "/chemin/vers/sauvegarde",
+ "rsyncHost": "Hôte distant",
+ "rsyncHostHelp": "IP ou nom d'hôte SSH",
+ "rsyncHostPlaceholder": "sauvegarde.exemple.com",
+ "rsyncUser": "Utilisateur SSH",
+ "rsyncUserHelp": "Pour la connexion SSH",
+ "rsyncUserPlaceholder": "backup-user",
+ "rsyncPath": "Chemin distant",
+ "rsyncPathHelp": "Répertoire sur le serveur distant",
+ "rsyncPathPlaceholder": "/home/backup/photos",
+ "rsyncSshKey": "Clé privée SSH",
+ "rsyncSshKeyHelp": "Optionnel",
+ "rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
+ "s3Endpoint": "Point de terminaison S3",
+ "s3EndpointHelp": "URL API S3",
+ "s3EndpointPlaceholder": "https://s3.amazonaws.com",
+ "s3Bucket": "Nom du Bucket",
+ "s3BucketHelp": "Bucket de stockage",
+ "s3BucketPlaceholder": "mon-bucket-backup",
+ "s3AccessKey": "ID Clé d'accès",
+ "s3AccessKeyHelp": "Identifiant S3",
+ "s3AccessKeyPlaceholder": "AKIA...",
+ "s3SecretKey": "Clé secrète S3",
+ "s3SecretKeyHelp": "Secret S3",
+ "s3SecretKeyPlaceholder": "wJal...",
+ "s3Region": "Région",
+ "s3RegionHelp": "Ex: us-east-1",
+ "s3RegionPlaceholder": "us-east-1"
+ },
+ "schedule": {
+ "title": "Calendrier",
+ "scheduleType": "Type de calendrier",
+ "scheduleOptions": {
+ "hourly": "Toutes les heures",
+ "daily": "Quotidien",
+ "weekly": "Hebdomadaire",
+ "custom": "Expression Cron personnalisée"
+ },
+ "options": {
+ "hourly": "Heure",
+ "daily": "Jour",
+ "weekly": "Semaine",
+ "custom": "Cron"
+ },
+ "customCron": "Expression Cron",
+ "customCronHelp": "Expression valide (ex: 0 3 * * *)",
+ "retention": "Politique de rétention",
+ "retentionDays": "Conserver pendant",
+ "retentionHelp": "jours (les plus vieux seront effacés)"
+ },
+ "whatToBackup": {
+ "title": "Éléments à sauvegarder",
+ "database": "Base de données",
+ "databaseHelp": "Événements, réglages et comptes",
+ "photos": "Photos",
+ "photosHelp": "Toutes les photos des galeries actives",
+ "archives": "Archives",
+ "archivesHelp": "Fichiers ZIP archivés",
+ "thumbnails": "Vignettes",
+ "thumbnailsHelp": "Aperçus (peuvent être régénérés)",
+ "tempFiles": "Fichiers temporaires",
+ "tempFilesHelp": "En cours de traitement"
+ },
+ "advancedOptions": {
+ "title": "Options avancées",
+ "compression": "Activer la compression",
+ "compressionHelp": "Économise de l'espace",
+ "encryption": "Activer le chiffrement",
+ "encryptionHelp": "Sécurité supplémentaire",
+ "encryptionPassphrase": "Phrase secrète de chiffrement",
+ "encryptionPassphraseHelp": "Nécessaire pour restaurer",
+ "confirmPassphrase": "Confirmer la phrase secrète",
+ "passphrasesDontMatch": "Les phrases ne correspondent pas"
+ },
+ "validation": {
+ "requiredFields": "Remplissez les champs requis",
+ "invalidCron": "Expression Cron invalide",
+ "connectionTestFailed": "Échec du test de connexion",
+ "connectionTestSuccess": "Connexion réussie !"
+ },
+ "messages": {
+ "requiredFields": "Champs requis manquants",
+ "connectionSuccess": "Connexion réussie !",
+ "connectionFailed": "La connexion a échoué"
+ },
+ "testingConnection": "Test en cours...",
+ "saveSettings": "Enregistrer la configuration",
+ "savingSettings": "Enregistrement..."
+ },
+ "history": {
+ "searchPlaceholder": "Rechercher...",
+ "allStatus": "Tous les statuts",
+ "status": {
+ "completed": "Terminé",
+ "failed": "Échoué",
+ "running": "En cours",
+ "partial": "Partiel"
+ },
+ "deleteConfirm": "Supprimer la sauvegarde du {{date}} ?",
+ "noBackups": "Aucune sauvegarde",
+ "tableHeaders": {
+ "date": "Date",
+ "type": "Type",
+ "status": "Statut",
+ "size": "Taille",
+ "duration": "Durée",
+ "actions": "Actions"
+ },
+ "columns": {
+ "status": "Statut",
+ "dateTime": "Date et Heure",
+ "type": "Type",
+ "size": "Taille",
+ "duration": "Durée",
+ "actions": "Actions"
+ },
+ "details": "Détails",
+ "statistics": "Statistiques",
+ "errors": "Erreurs",
+ "backupDetails": {
+ "backupId": "ID Sauvegarde",
+ "startTime": "Heure de début",
+ "endTime": "Heure de fin",
+ "destination": "Destination",
+ "filesProcessed": "Fichiers traités",
+ "totalSize": "Taille totale",
+ "compressionRatio": "Taux de compression",
+ "errorLog": "Journal d'erreurs",
+ "noErrors": "Aucune erreur détectée"
+ },
+ "pagination": {
+ "showing": "Affichage {{from}}-{{to}} sur {{total}}",
+ "previous": "Précédent",
+ "next": "Suivant"
+ },
+ "filter": {
+ "allStatus": "Tous",
+ "completed": "Réussis",
+ "failed": "Échoués",
+ "running": "En cours",
+ "partial": "Partiels"
+ },
+ "noBackupsFound": "Aucune sauvegarde trouvée",
+ "backupsWillAppear": "Les sauvegardes apparaîtront ici",
+ "messages": {
+ "deleteSuccess": "Sauvegarde supprimée"
+ },
+ "details": {
+ "backupDetails": "Détails de la sauvegarde",
+ "destination": "Destination",
+ "started": "Début",
+ "completed": "Fin",
+ "contentBackedUp": "Contenu sauvegardé",
+ "errorDetails": "Détails d'erreur",
+ "manifest": "Manifeste"
+ }
+ },
+ "restore": {
+ "steps": {
+ "selectSource": "Source",
+ "chooseBackup": "Sauvegarde",
+ "restoreOptions": "Options",
+ "reviewConfirm": "Confirmation",
+ "progress": "Progression"
+ },
+ "source": {
+ "title": "Source de restauration",
+ "subtitle": "D'où provient la sauvegarde ?",
+ "local": {
+ "name": "Local",
+ "description": "Fichiers sur le serveur"
+ },
+ "s3": {
+ "name": "S3",
+ "description": "Stockage S3"
+ },
+ "upload": {
+ "name": "Téléverser",
+ "description": "Envoyer un fichier",
+ "comingSoon": "Bientôt disponible"
+ },
+ "configuration": {
+ "s3": "Configuration S3",
+ "endpoint": "URL S3",
+ "bucket": "Nom du Bucket",
+ "accessKey": "Clé d'accès",
+ "secretKey": "Clé secrète"
+ }
+ },
+ "backup": {
+ "title": "Choisir la sauvegarde",
+ "subtitle": "Sélectionnez un point de restauration",
+ "noBackupsFound": "Aucune sauvegarde trouvée",
+ "encrypted": "Sauvegarde chiffrée",
+ "encryptedMessage": "Phrase secrète requise.",
+ "enterPassphrase": "Entrez la phrase secrète",
+ "at": "à"
+ },
+ "restoreTypes": {
+ "full": {
+ "name": "Complète",
+ "description": "Base, photos et archives",
+ "warning": "Remplace toutes les données actuelles"
+ },
+ "database": {
+ "name": "Base de données",
+ "description": "Paramètres, événements, comptes",
+ "warning": "La base actuelle sera remplacée"
+ },
+ "files": {
+ "name": "Fichiers",
+ "description": "Photos et archives uniquement",
+ "warning": "Les fichiers existants peuvent être écrasés"
+ },
+ "selective": {
+ "name": "Sélective",
+ "description": "Éléments au choix",
+ "warning": "Seuls les éléments choisis seront restaurés"
+ }
+ },
+ "options": {
+ "title": "Options de restauration",
+ "subtitle": "Précisez vos choix",
+ "additionalOptions": {
+ "title": "Options supplémentaires",
+ "skipPreBackup": "Ignorer sauvegarde pré-restauration",
+ "skipPreBackupHelp": "Évite de créer une sauvegarde avant l'écrasement.",
+ "force": "Forcer la restauration",
+ "forceHelp": "Outrepasser les avertissements de sécurité (prudence)"
+ }
+ },
+ "confirmation": {
+ "title": "Vérification",
+ "subtitle": "Vérifiez votre configuration",
+ "validation": {
+ "passed": "Validation réussie",
+ "failed": "Échec de validation",
+ "checking": "Vérification en cours..."
+ },
+ "spaceCheck": {
+ "title": "Espace disque",
+ "required": "Requis",
+ "available": "Disponible",
+ "insufficient": "Espace insuffisant"
+ },
+ "summary": {
+ "title": "Résumé",
+ "source": "Source",
+ "backupDate": "Date de sauvegarde",
+ "restoreType": "Type de restauration",
+ "preBackup": "Pré-sauvegarde",
+ "enabled": "Activée",
+ "skipped": "Ignorée"
+ },
+ "warning": {
+ "title": "Avis important",
+ "message": "Cette opération va écraser les données. Assurez-vous d'avoir une sauvegarde. Irréversible."
+ }
+ },
+ "progress": {
+ "title": "Progression",
+ "inProgress": "Restauration en cours...",
+ "completed": "Restauration terminée",
+ "overallProgress": "Progression globale",
+ "current": "Actuel",
+ "statusDetails": "Détails du statut",
+ "restoreLogs": "Journaux",
+ "steps": {
+ "completed": "Terminé",
+ "running": "En cours",
+ "failed": "Échoué",
+ "pending": "En attente"
+ },
+ "success": {
+ "title": "Restauration réussie",
+ "message": "Vos données ont été restaurées."
+ }
+ },
+ "actions": {
+ "back": "Retour",
+ "next": "Suivant",
+ "startRestore": "Lancer la restauration",
+ "starting": "Démarrage...",
+ "validating": "Validation...",
+ "startNewRestore": "Nouvelle restauration"
+ },
+ "messages": {
+ "restoreStarted": "Restauration lancée"
+ }
+ },
+ "messages": {
+ "backupStarted": "Sauvegarde lancée",
+ "backupFailed": "Échec du lancement",
+ "configUpdated": "Configuration mise à jour",
+ "configUpdateFailed": "Échec de mise à jour",
+ "backupDeleted": "Sauvegarde supprimée",
+ "deleteFailed": "Échec de suppression",
+ "testEmailSent": "Connexion réussie !",
+ "testEmailFailed": "La connexion a échoué"
+ }
+ },
+ "cssTemplates": {
+ "title": "Modèles CSS personnalisés",
+ "template": "Modèle",
+ "templateName": "Nom du modèle",
+ "enableTemplate": "Activer ce modèle",
+ "enableHint": "Les modèles activés seront proposées à la création d'événement",
+ "cssContent": "Contenu CSS",
+ "cssHint": "Ciblez avec .gallery-page. Variables : --gallery-bg, --gallery-text, --gallery-accent",
+ "securityNotice": "Sécurité",
+ "securityText": "Le CSS est filtré. Les URLs externes, @import et JavaScript sont interdits.",
+ "resetToDefault": "Réinitialiser",
+ "resetConfirm": "Réinitialiser par défaut ? Vos changements seront perdus.",
+ "unsavedChanges": "Changements non enregistrés",
+ "saveTemplate": "Enregistrer le modèle",
+ "lastUpdated": "Mis à jour le",
+ "saved": "Modèle enregistré",
+ "saveFailed": "Échec de l'enregistrement",
+ "sanitizationWarning": "Certains motifs CSS ont été bloqués pour sécurité",
+ "reset": "Modèle réinitialisé",
+ "resetFailed": "Échec de réinitialisation"
+ },
+ "maintenance": {
+ "title": "Maintenance système",
+ "message": "Maintenance en cours. Nous revenons bientôt.",
+ "expectedCompletion": "Heure de fin prévue :",
+ "checkBackLater": "Réessayez plus tard",
+ "urgentMatters": "Pour une urgence, contactez"
+ },
+ "passwordChange": {
+ "title": "Changer le mot de passe",
+ "currentPassword": "Mot de passe actuel",
+ "newPassword": "Nouveau mot de passe",
+ "confirmPassword": "Confirmer le nouveau mot de passe",
+ "currentPasswordPlaceholder": "Saisissez l'actuel",
+ "newPasswordPlaceholder": "Saisissez le nouveau",
+ "confirmPasswordPlaceholder": "Confirmez le nouveau",
+ "requirements": "Exigences :",
+ "minLength": "6 caractères minimum",
+ "mustDiffer": "Doit être différent de l'actuel",
+ "success": "Mot de passe changé",
+ "failed": "Échec du changement",
+ "currentRequired": "Le mot de passe actuel est requis",
+ "newRequired": "Le nouveau mot de passe est requis",
+ "minLengthError": "Minimum 6 caractères",
+ "confirmRequired": "Veuillez confirmer",
+ "noMatch": "Les mots de passe ne correspondent pas",
+ "mustBeDifferent": "Doit différer du précédent",
+ "cancel": "Annuler"
+ },
+ "mandatoryPasswordChange": {
+ "title": "Changement de mot de passe requis",
+ "description": "Par sécurité, vous devez changer votre mot de passe avant d'accéder au panneau admin.",
+ "success": "Mot de passe changé ! Vous pouvez accéder à l'administration.",
+ "minLength": "12 caractères minimum",
+ "mustContainUpperLower": "Majuscules et minuscules requises",
+ "mustContainNumbers": "Chiffres requis",
+ "mustContainSpecial": "Caractère spécial requis (!@#$%^&*)",
+ "minLengthError": "Minimum 12 caractères",
+ "mustContainLowercase": "Lettre minuscule requise",
+ "mustContainUppercase": "Lettre majuscule requise",
+ "mustContainNumbersError": "Chiffre requis",
+ "mustContainSpecialError": "Caractère spécial requis"
+ },
+ "offline": {
+ "backOnline": "De nouveau en ligne",
+ "noConnection": "Pas de connexion internet"
+ },
+ "download": {
+ "downloading": "Téléchargement...",
+ "percentComplete": "% terminé"
+ },
+ "passwordGenerator": {
+ "weak": "Faible",
+ "fair": "Passable",
+ "good": "Bon",
+ "strong": "Robuste",
+ "generating": "Génération...",
+ "generatePassword": "Générer un mot de passe",
+ "showSuggestions": "Voir suggestions",
+ "moreOptions": "Plus d'options",
+ "suggestions": "Suggestions",
+ "characters": "caractères",
+ "copyPassword": "Copier",
+ "use": "Utiliser",
+ "pattern": "Modèle :",
+ "patternDescription": "Générés selon le nom et la date. Ex: 'Venue2024$August' pour faciliter la mémoire."
+ },
+ "feedback": {
+ "comments": "Commentaires",
+ "addComment": "Ajouter un commentaire",
+ "yourName": "Votre nom",
+ "yourEmail": "Votre e-mail",
+ "writeComment": "Écrire un commentaire...",
+ "submit": "Envoyer",
+ "commentSubmitted": "Commentaire envoyé",
+ "commentError": "Échec de l'envoi",
+ "rateLimited": "Veuillez patienter avant de commenter à nouveau",
+ "commentRequired": "Le commentaire est requis",
+ "nameRequired": "Le nom est requis",
+ "emailRequired": "L'e-mail est requis",
+ "anonymous": "Anonyme",
+ "pendingApproval": "En attente d'approbation",
+ "noComments": "Soyez le premier à commenter !",
+ "rating": "Note",
+ "ratePhoto": "Noter cette photo",
+ "yourRating": "Votre note",
+ "averageRating": "Note moyenne",
+ "totalRatings": "notes",
+ "likes": "J'aime",
+ "favorites": "Favoris",
+ "likePhoto": "Aimer cette photo",
+ "favoritePhoto": "Ajouter aux favoris",
+ "photoFeedback": "Avis sur la photo",
+ "hasFeedback": "Contient des avis",
+ "hasComments": "Contient des commentaires",
+ "hasRating": "Contient des notes",
+ "settings": {
+ "title": "Paramètres des avis",
+ "enableFeedback": "Activer les avis",
+ "feedbackTypes": "Types d'avis",
+ "ratings": "Évaluation (étoiles)",
+ "ratingsDesc": "Notes de 1 à 5 étoiles",
+ "likes": "J'aime",
+ "likesDesc": "Bouton J'aime simple",
+ "comments": "Commentaires",
+ "commentsDesc": "Commentaires textuels",
+ "favorites": "Favoris",
+ "favoritesDesc": "Mise en favoris"
+ }
+ },
+ "filter": {
+ "feedbackFilters": "Filtres d'avis",
+ "clear": "Effacer",
+ "rating": "Note",
+ "allPhotos": "Toutes les photos",
+ "anyRating": "Toutes les notes",
+ "oneStarPlus": "1+ Étoile",
+ "twoStarsPlus": "2+ Étoiles",
+ "threeStarsPlus": "3+ Étoiles",
+ "fourStarsPlus": "4+ Étoiles",
+ "fiveStarsOnly": "5 Étoiles uniquement",
+ "hasLikes": "Avec J'aime",
+ "hasFavorites": "Avec Favoris",
+ "hasComments": "Avec Commentaires"
+ },
+ "adminLogin": {
+ "title": "Connexion Admin",
+ "subtitle": "Connectez-vous pour gérer les galeries",
+ "sessionExpired": "Session expirée. Reconnectez-vous.",
+ "emailLabel": "Adresse e-mail",
+ "emailPlaceholder": "admin@exemple.com",
+ "emailRequired": "L'e-mail est requis",
+ "invalidEmail": "Format invalide",
+ "passwordLabel": "Mot de passe",
+ "passwordPlaceholder": "Saisissez votre mot de passe",
+ "passwordRequired": "Le mot de passe est requis",
+ "passwordMinLength": "Minimum 6 caractères",
+ "rememberMe": "Se souvenir de moi",
+ "forgotPassword": "Mot de passe oublié ?",
+ "signIn": "Se connecter",
+ "loginSuccess": "Connexion réussie !",
+ "networkError": "Erreur réseau. Vérifiez votre connexion.",
+ "tooManyAttempts": "Trop de tentatives. Réessayez plus tard.",
+ "invalidCredentials": "E-mail ou mot de passe invalide",
+ "generalError": "Une erreur est survenue",
+ "needHelp": "Besoin d'aide ? Contactez",
+ "poweredBy": "Propulsé par PicPeak",
+ "devModeHint": "Mode Développement : admin@exemple.com / admin123"
+ },
+ "photoSort": {
+ "defaultSort": "Tri par défaut des photos",
+ "uploadDateNewest": "Date d'envoi (plus récent d'abord)",
+ "uploadDateOldest": "Date d'envoi (plus ancien d'abord)",
+ "captureDateNewest": "Date de prise de vue (plus récente d'abord)",
+ "captureDateOldest": "Date de prise de vue (plus ancienne d'abord)",
+ "filenameAZ": "Nom de fichier (A-Z)",
+ "filenameZA": "Nom de fichier (Z-A)",
+ "dateTaken": "Date de prise de vue"
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/pages/admin/EmailConfigPage.tsx b/frontend/src/pages/admin/EmailConfigPage.tsx
index 60814535..e7d06a6b 100644
--- a/frontend/src/pages/admin/EmailConfigPage.tsx
+++ b/frontend/src/pages/admin/EmailConfigPage.tsx
@@ -23,14 +23,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { emailService, type EmailConfig, type EmailTemplate, type EmailTemplateTranslation } from '../../services/email.service';
import { settingsService } from '../../services/settings.service';
import { useTranslation } from 'react-i18next';
-
-const SUPPORTED_LANGUAGES = [
- { code: 'en', name: 'English', flag: '🇬🇧' },
- { code: 'de', name: 'Deutsch', flag: '🇩🇪' },
- { code: 'nl', name: 'Nederlands', flag: '🇳🇱' },
- { code: 'pt', name: 'Português', flag: '🇧🇷' },
- { code: 'ru', name: 'Русский', flag: '🇷🇺' },
-];
+import { SUPPORTED_LANGUAGES } from "../../components/common/LanguageSelector.tsx";
const defaultTemplateKeys = [
{
@@ -795,7 +788,7 @@ export const EmailConfigPage: React.FC = () => {
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200'
}`}
>
- {lang.flag}
+
{lang.name}
{!hasContent && lang.code !== 'en' && (
diff --git a/frontend/src/pages/admin/UserManagementPage.tsx b/frontend/src/pages/admin/UserManagementPage.tsx
index ead1906f..deab0a35 100644
--- a/frontend/src/pages/admin/UserManagementPage.tsx
+++ b/frontend/src/pages/admin/UserManagementPage.tsx
@@ -17,11 +17,12 @@ import {
CheckCircle,
XCircle,
} from 'lucide-react';
-import { parseISO, formatDistanceToNow, isPast } from 'date-fns';
+import { parseISO, isPast } from 'date-fns';
import { Button, Input, Card, Loading } from '../../components/common';
import { userManagementService } from '../../services/userManagement.service';
import type { AdminUser, AdminRole, AdminInvitation } from '../../types';
+import { useLocalizedDate } from "../../hooks";
type TabType = 'users' | 'invitations';
@@ -368,6 +369,7 @@ const ConfirmDialog: React.FC = ({
export const UserManagementPage: React.FC = () => {
const { t } = useTranslation();
const queryClient = useQueryClient();
+ const { formatDistanceToNow } = useLocalizedDate()
// State
const [activeTab, setActiveTab] = useState('users');
From 74e87b968b3152603dbfca72fae06372b7c7f519 Mon Sep 17 00:00:00 2001
From: PiR1
Date: Fri, 8 May 2026 16:17:07 +0200
Subject: [PATCH 015/169] feat(localization): add i18next configuration and CLI
commands for localization management
---
frontend/i18next.config.ts | 23 +
frontend/package-lock.json | 1653 ++++++++++++++++++++++++++++-
frontend/package.json | 6 +-
frontend/src/i18n/locales/en.json | 1006 ++++++++----------
4 files changed, 2085 insertions(+), 603 deletions(-)
create mode 100644 frontend/i18next.config.ts
diff --git a/frontend/i18next.config.ts b/frontend/i18next.config.ts
new file mode 100644
index 00000000..38c090be
--- /dev/null
+++ b/frontend/i18next.config.ts
@@ -0,0 +1,23 @@
+import { defineConfig } from 'i18next-cli';
+
+export default defineConfig({
+ locales: ['en', 'de', 'nl', 'pt', 'ru', 'fr'],
+
+ extract: {
+ input: ['src/**/*.{ts,tsx,js,jsx}', '!src/**/*.{test,spec,d}.{ts,tsx}'],
+ output: 'src/i18n/locales/{{language}}.json',
+ defaultNS: false,
+
+ primaryLanguage: 'en',
+
+ removeUnusedKeys: true,
+
+ // Dynamic keys to preserve (e.g.: t(`errors.${code}`))
+ preservePatterns: [],
+
+ preserveContextVariants: true,
+
+ indentation: 2,
+ sort:false
+ },
+});
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 27a686eb..57f7f305 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "picpeak-frontend",
- "version": "3.42.2-beta.0",
+ "version": "3.42.2-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "picpeak-frontend",
- "version": "3.42.2-beta.0",
+ "version": "3.42.2-beta.1",
"dependencies": {
"@tanstack/react-query": "^5.0.0",
"@tiptap/extension-character-count": "^2.26.1",
@@ -62,6 +62,7 @@
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.2.0",
+ "i18next-cli": "^1.56.11",
"jsdom": "^25.0.1",
"postcss": "^8.5.10",
"tailwindcss": "^3.3.0",
@@ -146,7 +147,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -351,9 +351,9 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
- "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
+ "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -407,6 +407,23 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@croct/json": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@croct/json/-/json-2.1.0.tgz",
+ "integrity": "sha512-UrWfjNQVlBxN+OVcFwHmkjARMW55MBN04E9KfGac8ac8z1QnFVuiOOFtMWXCk3UwsyRqhsNaFoYLZC+xxqsVjQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@croct/json5-parser": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@croct/json5-parser/-/json5-parser-0.2.2.tgz",
+ "integrity": "sha512-0NJMLrbeLbQ0eCVj3UoH/kG2QckUgOASfwmfDTjyW1xAYPyTNJXcWVT/dssJdTJd0pRchW+qF0VFWQHcxs1OVw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@croct/json": "^2.1.0"
+ }
+ },
"node_modules/@csstools/color-helpers": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
@@ -495,7 +512,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
},
@@ -519,7 +535,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1182,6 +1197,377 @@
"url": "https://github.com/sponsors/nzakas"
}
},
+ "node_modules/@inquirer/ansi": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.5.tgz",
+ "integrity": "sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ }
+ },
+ "node_modules/@inquirer/checkbox": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.1.4.tgz",
+ "integrity": "sha512-w6KF8ZYRvqHhROkOTHXYC3qIV/KYEu5o12oLqQySvch61vrYtRxNSHTONSdJqWiFJPlCUQAHT5OgOIyuTr+MHQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.5",
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/figures": "^2.0.5",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.12.tgz",
+ "integrity": "sha512-h9FgGun3QwVYNj5TWIZZ+slii73bMoBFjPfVIGtnFuL4t8gBiNDV9PcSfIzkuxvgquJKt9nr1QzszpBzTbH8Og==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "11.1.9",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.9.tgz",
+ "integrity": "sha512-BDE4fG22uYh1bGSifcj7JSx119TVYNViMhMu85usp4Fswrzh6M0DV3yld64jA98uOAa2GSQ4Bg4bZRm2d2cwSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.5",
+ "@inquirer/figures": "^2.0.5",
+ "@inquirer/type": "^4.0.5",
+ "cli-width": "^4.1.0",
+ "fast-wrap-ansi": "^0.2.0",
+ "mute-stream": "^3.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/editor": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.1.1.tgz",
+ "integrity": "sha512-6y11LgmNpmn5D2aB5FgnCfBUBK8ZstwLCalyJmORcJZ/WrhOjm16mu6eSqIx8DnErxDqSLr+Jkp+GP8/Nwd5tA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/external-editor": "^3.0.0",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/expand": {
+ "version": "5.0.13",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.13.tgz",
+ "integrity": "sha512-dF2zvrFo9LshkcB23/O1il13kBkBltWIXzut1evfbuBLXMiGIuC45c+ZQ0uukjCDsvI8OWqun4FRYMnzFCQa3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.0.tgz",
+ "integrity": "sha512-lDSwMgg+M5rq6JKBYaJwSX6T9e/HK2qqZ1oxmOwn4AQoJE5D+7TumsxLGC02PWS//rkIVqbZv3XA3ejsc9FYvg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^2.1.1",
+ "iconv-lite": "^0.7.2"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor/node_modules/iconv-lite": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.5.tgz",
+ "integrity": "sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ }
+ },
+ "node_modules/@inquirer/input": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.12.tgz",
+ "integrity": "sha512-uiMFBl4LqFzJClh80Q3f9hbOFJ6kgkDWI4LjAeBuyO6EanVVMF69AgOvpi1qdqjDSjDN6578B6nky9ceEpI+1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/number": {
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.12.tgz",
+ "integrity": "sha512-/vrwhEf7Xsuh+YlHF4IjSy3g1cyrQuPaSiHIxCEbLu8qnfvrcvJyCkoktOOF+xV9gSb77/G0n3h04RbMDW2sIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/password": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.12.tgz",
+ "integrity": "sha512-CBh7YHju623lxJRcAOo498ZUwIuMy63bqW/vVq0tQAZVv+lkWlHkP9ealYE1utWSisEShY5VMdzIXRmyEODzcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.5",
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/prompts": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.4.2.tgz",
+ "integrity": "sha512-XJmn/wY4AX56l1BRU+ZjDrFtg9+2uBEi4JvJQj82kwJDQKiPgSn4CEsbfGGygS4Gw6rkL4W18oATjfVfaqub2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/checkbox": "^5.1.4",
+ "@inquirer/confirm": "^6.0.12",
+ "@inquirer/editor": "^5.1.1",
+ "@inquirer/expand": "^5.0.13",
+ "@inquirer/input": "^5.0.12",
+ "@inquirer/number": "^4.0.12",
+ "@inquirer/password": "^5.0.12",
+ "@inquirer/rawlist": "^5.2.8",
+ "@inquirer/search": "^4.1.8",
+ "@inquirer/select": "^5.1.4"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/rawlist": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.2.8.tgz",
+ "integrity": "sha512-Su7FQvp5buZmCymN3PPoYv31ZQQX4ve2j02k7piGgKAWgE+AQRB5YoYVveGXcl3TZ9ldgRMSxj56YfDFmmaqLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/search": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.8.tgz",
+ "integrity": "sha512-fGiHKGD6DyPIYUWxoXnQTeXeyYqSOUrasDMABBmMHUalH/LxkuzY0xVRtimXAt1sUeeyYkVuKQx1bebMuN11Kw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/figures": "^2.0.5",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/select": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.1.4.tgz",
+ "integrity": "sha512-2kWcGKPMLAXAWRp1AH1SLsQmX+j0QjeljyXMUji9WMZC8nRDO0b7qquIGr6143E7KMLt3VAIGNXzwa/6PXQs4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.5",
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/figures": "^2.0.5",
+ "@inquirer/type": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.5.tgz",
+ "integrity": "sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
+ "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -1651,6 +2037,288 @@
"win32"
]
},
+ "node_modules/@sec-ant/readable-stream": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@swc/core": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.33.tgz",
+ "integrity": "sha512-jOlwnFV2xhuuZeAUILGFULeR6vDPfijEJ57evfocwznQldLU3w2cZ9bSDryY9ip+AsM3r1NJKzf47V2NXebkeQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3",
+ "@swc/types": "^0.1.26"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/swc"
+ },
+ "optionalDependencies": {
+ "@swc/core-darwin-arm64": "1.15.33",
+ "@swc/core-darwin-x64": "1.15.33",
+ "@swc/core-linux-arm-gnueabihf": "1.15.33",
+ "@swc/core-linux-arm64-gnu": "1.15.33",
+ "@swc/core-linux-arm64-musl": "1.15.33",
+ "@swc/core-linux-ppc64-gnu": "1.15.33",
+ "@swc/core-linux-s390x-gnu": "1.15.33",
+ "@swc/core-linux-x64-gnu": "1.15.33",
+ "@swc/core-linux-x64-musl": "1.15.33",
+ "@swc/core-win32-arm64-msvc": "1.15.33",
+ "@swc/core-win32-ia32-msvc": "1.15.33",
+ "@swc/core-win32-x64-msvc": "1.15.33"
+ },
+ "peerDependencies": {
+ "@swc/helpers": ">=0.5.17"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@swc/core-darwin-arm64": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.33.tgz",
+ "integrity": "sha512-N+L0uXhuO7FIfzqwgxmzv0zIpV0qEp8wPX3QQs2p4atjMoywup2JTeDlXPw+z9pWJGCae3JjM+tZ6myclI+2gA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-darwin-x64": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.33.tgz",
+ "integrity": "sha512-/Il4QHSOhV4FekbsDtkrNmKbsX26oSysvgrRswa/RYOHXAkwXDbB4jaeKq6PsJLSPkzJ2KzQ061gtBnk0vNHfA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.33.tgz",
+ "integrity": "sha512-C64hBnBxq4viOPQ8hlx+2lJ23bzZBGnjw7ryALmS+0Q3zHmwO8lw1/DArLENw4Q18/0w5wdEO1k3m1wWNtKGqQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-gnu": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.33.tgz",
+ "integrity": "sha512-TRJfnJbX3jqpxRDRoieMzRiCBS5jOmXNb3iQXmcgjFEHKLnAgK1RZRU8Cq1MsPqO4jAJp/ld1G4O3fXuxv85uw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-musl": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.33.tgz",
+ "integrity": "sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-ppc64-gnu": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.33.tgz",
+ "integrity": "sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-s390x-gnu": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.33.tgz",
+ "integrity": "sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-gnu": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.33.tgz",
+ "integrity": "sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-musl": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.33.tgz",
+ "integrity": "sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-arm64-msvc": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.33.tgz",
+ "integrity": "sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-ia32-msvc": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.33.tgz",
+ "integrity": "sha512-gtyvzSNR8DHKfFEA2uqb8Ld1myqi6uEg2jyeUq3ikn5ytYs7H8RpZYC8mdy4NXr8hfcdJfCLXPlYaqqfBXpoEQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.15.33",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.33.tgz",
+ "integrity": "sha512-d6fRqQSkJI+kmMEBWaDQ7TMl8+YjLYbwRUPZQ9DY0ORBJeTzOrG0twvfvlZ2xgw6jA0ScQKgfBm4vHLSLl5Hqg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@swc/types": {
+ "version": "0.1.26",
+ "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz",
+ "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3"
+ }
+ },
"node_modules/@tanstack/query-core": {
"version": "5.90.16",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.16.tgz",
@@ -1704,6 +2372,7 @@
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -1713,7 +2382,8 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@testing-library/jest-dom": {
"version": "6.9.1",
@@ -1782,7 +2452,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.27.1.tgz",
"integrity": "sha512-nkerkl8syHj44ZzAB7oA2GPmmZINKBKCa79FuNvmGJrJ4qyZwlkDzszud23YteFZEytbc87kVd/fP76ROS6sLg==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -1879,7 +2548,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.27.1.tgz",
"integrity": "sha512-wCI5VIOfSAdkenCWFvh4m8FFCJ51EOK+CUmOC/PWUjyo2Dgn8QC8HMi015q8XF7886T0KvYVVoqxmxJSUDAYNg==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -2158,7 +2826,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.27.1.tgz",
"integrity": "sha512-ijKo3+kIjALthYsnBmkRXAuw2Tswd9gd7BUR5OMfIcjGp8v576vKxOxrRfuYiUM78GPt//P0sVc1WV82H5N0PQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"prosemirror-changeset": "^2.3.0",
"prosemirror-collab": "^1.3.1",
@@ -2245,7 +2912,8 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -2381,7 +3049,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2"
@@ -2393,7 +3060,6 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@types/react": "^18.0.0"
}
@@ -2471,7 +3137,6 @@
"integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.48.0",
"@typescript-eslint/types": "8.48.0",
@@ -2838,7 +3503,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2889,6 +3553,7 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -3104,7 +3769,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -3217,6 +3881,13 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chardet": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
+ "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/check-error": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
@@ -3265,6 +3936,45 @@
"node": ">= 6"
}
},
+ "node_modules/cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz",
+ "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
@@ -3543,6 +4253,7 @@
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=6"
}
@@ -3732,7 +4443,6 @@
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -3914,6 +4624,33 @@
"node": ">=0.10.0"
}
},
+ "node_modules/execa": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
+ "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "figures": "^6.1.0",
+ "get-stream": "^9.0.0",
+ "human-signals": "^8.0.1",
+ "is-plain-obj": "^4.1.0",
+ "is-stream": "^4.0.1",
+ "npm-run-path": "^6.0.0",
+ "pretty-ms": "^9.2.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^4.0.0",
+ "yoctocolors": "^2.1.1"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.5.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
"node_modules/expect-type": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
@@ -3974,6 +4711,33 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-string-truncated-width": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz",
+ "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-string-width": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz",
+ "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-truncated-width": "^3.0.2"
+ }
+ },
+ "node_modules/fast-wrap-ansi": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz",
+ "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-width": "^3.0.2"
+ }
+ },
"node_modules/fastq": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
@@ -4015,6 +4779,22 @@
}
}
},
+ "node_modules/figures": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+ "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-unicode-supported": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -4099,6 +4879,23 @@
}
}
},
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
@@ -4198,6 +4995,19 @@
"node": ">=6.9.0"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
+ "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -4235,6 +5045,48 @@
"node": ">= 0.4"
}
},
+ "node_modules/get-stream": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sec-ant/readable-stream": "^0.4.1",
+ "is-stream": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
+ "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "foreground-child": "^3.3.1",
+ "jackspeak": "^4.1.1",
+ "minimatch": "^10.1.1",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^2.0.0"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -4248,6 +5100,45 @@
"node": ">=10.13.0"
}
},
+ "node_modules/glob/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/globals": {
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
@@ -4334,7 +5225,6 @@
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz",
"integrity": "sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==",
"license": "BSD-3-Clause",
- "peer": true,
"engines": {
"node": ">=12.0.0"
}
@@ -4398,6 +5288,16 @@
"node": ">= 14"
}
},
+ "node_modules/human-signals": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
+ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
"node_modules/i18next": {
"version": "25.7.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.7.3.tgz",
@@ -4417,7 +5317,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4"
},
@@ -4439,6 +5338,194 @@
"@babel/runtime": "^7.23.2"
}
},
+ "node_modules/i18next-cli": {
+ "version": "1.56.11",
+ "resolved": "https://registry.npmjs.org/i18next-cli/-/i18next-cli-1.56.11.tgz",
+ "integrity": "sha512-SGYBCVtU8GrO08WCuxLFcySzQXRROEDFcfToywPiqicD8jUSF6qsqMA7wv5uO2KFnCSTCj+iEO4G2JD5XeEpkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@croct/json5-parser": "^0.2.2",
+ "@swc/core": "^1.15.26",
+ "chokidar": "^5.0.0",
+ "commander": "^14.0.3",
+ "execa": "^9.6.1",
+ "glob": "^13.0.6",
+ "i18next-resources-for-ts": "^2.1.0",
+ "inquirer": "^13.4.1",
+ "jiti": "^2.6.1",
+ "jsonc-parser": "^3.3.1",
+ "magic-string": "^0.30.21",
+ "minimatch": "^10.2.5",
+ "ora": "^9.3.0",
+ "react": "^19.2.5",
+ "react-i18next": "^17.0.7",
+ "yaml": "^2.8.3"
+ },
+ "bin": {
+ "i18next-cli": "dist/esm/cli.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/chokidar": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/commander": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
+ "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/i18next": {
+ "version": "26.0.10",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.0.10.tgz",
+ "integrity": "sha512-k3yGPAlWR2RdMYoVXJoDZDT87qeHIWKH7gVksdZMpRty7QX/D9QZeYGvN08KGbKHke9wn01eYT+EEsrqX/YTlw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://www.locize.com/i18next"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.locize.com"
+ }
+ ],
+ "license": "MIT",
+ "peer": true,
+ "peerDependencies": {
+ "typescript": "^5 || ^6"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/i18next-cli/node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/react": {
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
+ "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/i18next-cli/node_modules/react-i18next": {
+ "version": "17.0.7",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.7.tgz",
+ "integrity": "sha512-rwtPXsb/zwzDafN+gytcjF5YnqGQQIRmCQ6DctBC1VSipRB8GD/MWEVrFP42vjMyuYydxWxM8CZRt+yiNuuoHg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.29.2",
+ "html-parse-stringify": "^3.0.1",
+ "use-sync-external-store": "^1.6.0"
+ },
+ "peerDependencies": {
+ "i18next": ">= 26.0.10",
+ "react": ">= 16.8.0",
+ "typescript": "^5 || ^6"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/i18next-cli/node_modules/readdirp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+ "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/i18next-http-backend": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.6.tgz",
@@ -4448,6 +5535,52 @@
"cross-fetch": "4.1.0"
}
},
+ "node_modules/i18next-resources-for-ts": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/i18next-resources-for-ts/-/i18next-resources-for-ts-2.1.0.tgz",
+ "integrity": "sha512-n5UexwEVt0OoIAhG2MWpSnAVJW1U8mQrQTmXyxc5DMAx+NLhcLZhSMJo/FnUsA5JQ3obTYqTgB7YIuZKWpDgow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.6",
+ "@swc/core": "^1.15.18",
+ "chokidar": "^5.0.0",
+ "yaml": "^2.8.2"
+ },
+ "bin": {
+ "i18next-resources-for-ts": "bin/i18next-resources-for-ts.js"
+ }
+ },
+ "node_modules/i18next-resources-for-ts/node_modules/chokidar": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/i18next-resources-for-ts/node_modules/readdirp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+ "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -4508,6 +5641,33 @@
"node": ">=8"
}
},
+ "node_modules/inquirer": {
+ "version": "13.4.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-13.4.2.tgz",
+ "integrity": "sha512-ziXEKBO6nxsX9Z3XEh7LNiUvYN/o5PYuYK+27l69NpjSUOh6JXQsQAKEw2AnZq5xvHeb3ZwkpzOxvNOswIX1fg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.5",
+ "@inquirer/core": "^11.1.9",
+ "@inquirer/prompts": "^8.4.2",
+ "@inquirer/type": "^4.0.5",
+ "mute-stream": "^3.0.0",
+ "run-async": "^4.0.6",
+ "rxjs": "^7.8.2"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -4560,6 +5720,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-interactive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+ "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -4570,6 +5743,19 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -4577,6 +5763,32 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/is-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -4584,13 +5796,28 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/jackspeak": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
+ "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^9.0.0"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/jiti": {
"version": "1.21.7",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -4739,6 +5966,13 @@
"node": ">=6"
}
},
+ "node_modules/jsonc-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+ "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/justified-layout": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/justified-layout/-/justified-layout-4.1.0.tgz",
@@ -4833,6 +6067,23 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/log-symbols": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz",
+ "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-unicode-supported": "^2.0.0",
+ "yoctocolors": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -4857,7 +6108,6 @@
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-2.9.0.tgz",
"integrity": "sha512-OpcaUTCLmHuVuBcyNckKfH5B0oA4JUavb/M/8n9iAvanJYNQkrVm4pvyX0SUaqkBG4dnWHKt7p50B3ngAG2Rfw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/hast": "^2.0.0",
"fault": "^2.0.0",
@@ -4893,6 +6143,7 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -4997,6 +6248,19 @@
"node": ">= 0.6"
}
},
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -5020,6 +6284,16 @@
"node": "*"
}
},
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
"node_modules/motion-dom": {
"version": "12.33.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.33.0.tgz",
@@ -5042,6 +6316,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/mute-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz",
+ "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
"node_modules/mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
@@ -5117,6 +6401,36 @@
"node": ">=0.10.0"
}
},
+ "node_modules/npm-run-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+ "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^4.0.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/nwsapi": {
"version": "2.2.22",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz",
@@ -5143,6 +6457,22 @@
"node": ">= 6"
}
},
+ "node_modules/onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -5161,6 +6491,42 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/ora": {
+ "version": "9.4.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.0.tgz",
+ "integrity": "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.6.2",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^3.2.0",
+ "is-interactive": "^2.0.0",
+ "is-unicode-supported": "^2.1.0",
+ "log-symbols": "^7.0.1",
+ "stdin-discarder": "^0.3.2",
+ "string-width": "^8.1.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
"node_modules/orderedmap": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
@@ -5199,6 +6565,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0"
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -5212,6 +6585,19 @@
"node": ">=6"
}
},
+ "node_modules/parse-ms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+ "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/parse5": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
@@ -5265,6 +6651,33 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+ "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
@@ -5304,7 +6717,6 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -5352,7 +6764,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -5512,6 +6923,7 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -5527,6 +6939,7 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=10"
},
@@ -5539,7 +6952,24 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/pretty-ms": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",
+ "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parse-ms": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/prop-types": {
"version": "15.8.1",
@@ -5664,7 +7094,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz",
"integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"orderedmap": "^2.0.0"
}
@@ -5694,7 +7123,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"prosemirror-model": "^1.0.0",
"prosemirror-transform": "^1.0.0",
@@ -5743,7 +7171,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.3.tgz",
"integrity": "sha512-SqMiYMUQNNBP9kfPhLO8WXEk/fon47vc52FQsUiJzTBuyjKgEcoAwMyF04eQ4WZ2ArMn7+ReypYL60aKngbACQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"prosemirror-model": "^1.20.0",
"prosemirror-state": "^1.0.0",
@@ -5804,7 +7231,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -5843,7 +7269,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -6078,6 +7503,23 @@
"node": ">=4"
}
},
+ "node_modules/restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -6147,6 +7589,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/run-async": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz",
+ "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -6171,6 +7623,16 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -6240,6 +7702,19 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -6264,6 +7739,78 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/stdin-discarder": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz",
+ "integrity": "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz",
+ "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-east-asian-width": "^1.5.0",
+ "strip-ansi": "^7.1.2"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+ "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
@@ -6623,7 +8170,6 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -6662,6 +8208,19 @@
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT"
},
+ "node_modules/unicorn-magic": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
@@ -6725,7 +8284,6 @@
"integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -7047,6 +8605,22 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yaml": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz",
+ "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
+ }
+ },
"node_modules/yet-another-react-lightbox": {
"version": "3.28.0",
"resolved": "https://registry.npmjs.org/yet-another-react-lightbox/-/yet-another-react-lightbox-3.28.0.tgz",
@@ -7085,6 +8659,19 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/yoctocolors": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz",
+ "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
}
}
}
diff --git a/frontend/package.json b/frontend/package.json
index 28f5af44..bcf50c7e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -9,7 +9,10 @@
"build:check": "tsc -b && node ./scripts/build.js",
"lint": "eslint .",
"preview": "vite preview",
- "test": "vitest run src/components/admin/__tests__/ThemeCustomizerEnhanced.test.tsx"
+ "test": "vitest run src/components/admin/__tests__/ThemeCustomizerEnhanced.test.tsx",
+ "i18n:extract": "i18next-cli extract",
+ "i18n:status": "i18next-cli status",
+ "i18n:ci": "i18next-cli extract --ci --dry-run"
},
"dependencies": {
"@tanstack/react-query": "^5.0.0",
@@ -66,6 +69,7 @@
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.2.0",
+ "i18next-cli": "^1.56.11",
"jsdom": "^25.0.1",
"postcss": "^8.5.10",
"tailwindcss": "^3.3.0",
diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json
index dde48779..5c83fcbd 100644
--- a/frontend/src/i18n/locales/en.json
+++ b/frontend/src/i18n/locales/en.json
@@ -81,8 +81,6 @@
"delete": "Delete",
"edit": "Edit",
"add": "Add",
- "search": "Search",
- "filter": "Filter",
"sortBy": "Sort by",
"yes": "Yes",
"no": "No",
@@ -91,35 +89,41 @@
"previous": "Previous",
"close": "Close",
"logout": "Logout",
- "menu": "Menu",
"change": "Change",
"remove": "Remove",
"download": "Download",
"downloadAll": "Download All",
- "uploading": "Uploading...",
- "uploaded": "Uploaded",
"photo": "photo",
"photos": "photos",
"video": "video",
- "videos": "videos",
"media": "media",
- "restore": "Restore",
- "actions": "Actions",
- "refresh": "Refresh",
- "preview": "Preview",
- "processing": "Processing...",
"upload": "Upload",
- "days": "days",
"customize": "Customize",
"hide": "Hide",
"unknown": "Unknown",
"notSet": "Not set",
"of": "of",
- "up": "Up",
- "select": "Select",
"selected": "Selected",
"chunk": "Chunk",
- "optional": "optional"
+ "optional": "optional",
+ "tryAgain": "Try Again",
+ "active": "Active",
+ "inactive": "Inactive",
+ "create": "Create",
+ "unknownDate": "Unknown date",
+ "pageOf": "Page {{current}} of {{total}}",
+ "collapse": "Collapse",
+ "expand": "Expand",
+ "submitting": "Submitting...",
+ "copy": "Copy",
+ "copied": "Copied!",
+ "applying": "Applying...",
+ "done": "Done",
+ "retry": "Retry",
+ "characters": "characters",
+ "saveChanges": "Save Changes",
+ "resetChanges": "Reset Changes",
+ "dismiss": "Dismiss"
},
"upload": {
"photoCategory": "Photo Category",
@@ -127,48 +131,34 @@
"eventSpecific": "(Event specific)",
"clickToUpload": "Click to upload or drag and drop",
"fileRequirements": "JPEG, PNG or WebP (max 50MB per file, {{limit}} files per upload)",
- "fileRequirementsMedia": "JPEG, PNG or WebP images, plus MP4/MOV/WEBM videos (max 50MB per file, {{limit}} files per upload)",
- "unsupportedFiles": "Some files were skipped because the format is not supported (use JPEG/PNG/WebP/MP4/MOV/WEBM).",
"selectedFiles": "Selected files",
"uploading": "Uploading...",
"transferring": "Transferring",
"processing": "Processing photos...",
"processingHint": "Files are uploaded. PicPeak is now generating thumbnails and reading metadata. You can leave this page — work continues in the background.",
"processingProgress": "{{complete}} of {{total}} done",
- "processingFailed": "{{count}} photo(s) failed to process",
"retryFailed": "Retry failed",
"uploadComplete": "Upload complete!",
- "uploadFailed": "Upload failed",
"someFilesFailed": "Some files failed to upload",
"replaceByName": "Replace existing photos with same name",
- "replacedFiles": "{{count}} photo(s) replaced",
"uploadPhotos": "Upload Photos",
"uploadMedia": "Upload Photos & Videos",
- "importExternal": "Import from External Folder",
- "externalImportInfo": "All pictures from the selected folder will be imported.",
- "selectExternalFolder": "Select external folder under /external-media",
- "importFromSelectedFolder": "Import from selected folder",
"maxFilesReached": "Maximum {{limit}} files allowed",
"someFilesSkipped": "Only {{allowed}} more files can be added (limit {{limit}})",
"tooManyFiles": "Maximum {{limit}} files can be uploaded at once",
"limitInfo": "{{selected}} of {{limit}} files selected ({{remaining}} remaining)",
"limitReached": "Upload limit reached ({{limit}} files per batch)",
- "uploadingChunks": "Uploading {{count}} files in {{total}} batches...",
- "mediaCategory": "Media category",
- "uploadAction": "Upload {{count}} files"
+ "replacedFiles_one": "{{count}} photo replaced",
+ "replacedFiles_other": "{{count}} photos replaced",
+ "processingFailed_one": "{{count}} photo failed to process",
+ "processingFailed_other": "{{count}} photos failed to process",
+ "uploadingChunks_one": "{{count}} chunk uploading",
+ "uploadingChunks_other": "{{count}} chunks uploading"
},
"navigation": {
"dashboard": "Dashboard",
"events": "Events",
- "archives": "Archives",
- "settings": "Settings",
- "eventTypes": "Event Types",
- "branding": "Branding",
- "analytics": "Analytics",
- "emailSettings": "Email Settings",
- "backup": "Backup & Restore",
- "cmsPages": "CMS Pages",
- "users": "Users"
+ "settings": "Settings"
},
"archives": {
"title": "Archives",
@@ -211,67 +201,44 @@
"deleteSuccess": "Archive deleted permanently"
},
"auth": {
- "login": "Login",
"password": "Password",
"enterPassword": "Enter Gallery Password",
"passwordPlaceholder": "Enter the gallery password",
"invalidPassword": "Invalid password",
"wrongPassword": "Incorrect password. Please check your password and try again.",
"tooManyAttempts": "Too many failed login attempts. Please try again later.",
- "sessionExpired": "Session expired",
"pleaseEnterPassword": "Please enter a password",
"passwordHint": "The password was provided by the event organizer. Contact them if you don't have it."
},
"gallery": {
- "title": "Photo Gallery",
- "welcomeMessage": "Welcome Message",
- "expiresOn": "Expires on",
"expires": "Expires",
"expired": "Expired",
- "daysRemaining": "{{days}} days remaining",
- "dayRemaining": "1 day remaining",
- "hoursRemaining": "{{hours}} hours remaining",
- "expiredMessage": "This gallery expired on {{date}}",
"contactOrganizer": "Please contact the event organizer if you need access to these photos.",
"searchPhotos": "Search photos by filename...",
"sortByDate": "Sort by Date",
"sortByName": "Sort by Name",
"sortBySize": "Sort by Size",
"allPhotos": "All Photos",
- "filter": "Filter",
"feedbackFilter": "Feedback Filter",
"all": "All",
"liked": "Liked",
"favorited": "Favorited",
"favorites": "Favorites",
- "downloadSelected": "Download {{count}} Selected",
- "shareGallery": "Share Gallery",
"needHelp": "Need help? Contact us at",
"noPhotosFound": "No photos found",
"failedToLoad": "Failed to load photos",
"tryAgain": "Try Again",
"loading": "Loading gallery...",
"expiredOn": "This gallery expired on {{date}}.",
- "expiresIn": "Gallery expires in {{count}} day",
- "expiresIn_plural": "Gallery expires in {{count}} days",
"downloadBefore": "Download your photos before they're no longer available.",
- "publicGalleryTitle": "This gallery is publicly accessible",
- "publicGallerySubtitle": "Loading the photos now...",
"viewGallery": "View Gallery",
"downloadAll": "Download All",
- "downloading": "Downloading {{count}} photo...",
- "downloading_plural": "Downloading {{count}} photos...",
- "downloadedPhotos": "Downloaded {{count}} photo!",
- "downloadedPhotos_plural": "Downloaded {{count}} photos!",
"downloadError": "Some photos failed to download",
"selectPhotos": "Select Photos",
"cancelSelection": "Cancel Selection",
- "photosSelected": "{{count}} selected",
"selectAll": "Select All",
"deselectAll": "Deselect All",
"deleteSelected": "Delete Selected",
- "photosCount": "{{count}} photo",
- "photosCount_plural": "{{count}} photos",
"searchByFilename": "Search by filename...",
"uncategorized": "Uncategorized",
"sortAscending": "Sort ascending",
@@ -279,8 +246,6 @@
"remaining": "remaining",
"selectPhotosHint": "Tip: Use Ctrl+Click (Cmd+Click on Mac) to quickly select multiple photos",
"filters": "Filters",
- "openFilters": "Open filters",
- "toggleSidebar": "Toggle sidebar",
"toggleMenu": "Toggle menu",
"allCategories": "All Categories",
"categories": "Categories",
@@ -313,14 +278,56 @@
"anonymous": "Anonymous"
},
"rated": "Rated",
- "commented": "Commented"
+ "commented": "Commented",
+ "expiresIn_one": "Gallery expires in {{count}} day",
+ "expiresIn_other": "Gallery expires in {{count}} days",
+ "downloading_one": "Downloading 1 photo...",
+ "downloading_other": "Downloading {{count}} photos...",
+ "guestRecovery": {
+ "invalidEmail": "Enter a valid email address",
+ "codeSent": "Check your inbox for a verification code.",
+ "requestError": "Could not send code. Try again.",
+ "invalidCode": "Enter the 6-digit code",
+ "verifyError": "Invalid or expired code.",
+ "back": "Back",
+ "title": "Recover your picks",
+ "emailStepDescription": "Enter the email you used before. We will send a 6-digit verification code.",
+ "codeStepDescription": "Enter the 6-digit code we sent to your email.",
+ "emailLabel": "Email",
+ "sendCode": "Send code",
+ "codeLabel": "Verification code",
+ "verifyCode": "Verify and continue"
+ },
+ "guestPrompt": {
+ "nameRequired": "Name is required",
+ "invalidEmail": "Invalid email address",
+ "emailRequired": "Email is required",
+ "error": "Registration failed",
+ "title": "Welcome — what's your name?",
+ "description": "Your picks will be saved under this name so the photographer knows which photos you love.",
+ "nameLabel": "Your name",
+ "namePlaceholder": "Enter your name",
+ "emailLabelRequired": "Email",
+ "emailLabel": "Email (optional)",
+ "emailPlaceholder": "you@example.com",
+ "submit": "Continue",
+ "alreadyHere": "I've been here before"
+ },
+ "footer": {
+ "forgetMeConfirm": "Your name and selections will be removed from this gallery.",
+ "forgetMe": "Forget me ({{name}})"
+ },
+ "photosCount_one": "{{count}} photo",
+ "photosCount_other": "{{count}} photos",
+ "poweredBy": "Powered by PicPeak",
+ "photosSelected_one": "gallery.photosSelected",
+ "photosSelected_other": "gallery.photosSelected",
+ "downloadSelected_one": "gallery.downloadSelected",
+ "downloadSelected_other": "gallery.downloadSelected"
},
"categories": {
"title": "Photo Categories",
- "global": "Global Categories",
- "eventSpecific": "Event-Specific Categories",
"addCategory": "Add Category",
- "organizationInfo": "Organize your photos into categories. Categories help guests navigate and find specific types of photos.",
"eventSpecificCategories": "Event-Specific Categories",
"noEventSpecificCategories": "No event-specific categories. Global categories are available by default.",
"globalCategoriesAlwaysAvailable": "Global Categories (always available):",
@@ -330,10 +337,8 @@
"failedToCreateCategory": "Failed to create category",
"failedToDeleteCategory": "Failed to delete category",
"categoryName": "Category name",
- "noCategory": "No category",
"noCategoriesYet": "No categories yet. Create your first category to organize photos.",
"deleteConfirm": "Are you sure you want to delete \"{{name}}\"?",
- "cannotDelete": "Cannot delete category with photos. Please reassign photos first.",
"setCoverPhoto": "Set Cover Photo",
"removeCoverPhoto": "Remove Cover Photo",
"coverPhotoSet": "Cover photo set successfully",
@@ -348,36 +353,16 @@
"totalViews": "Total Views",
"totalDownloads": "Total Downloads",
"uniqueVisitors": "Unique Visitors",
- "createNewEvent": "Create New Event",
- "setupNewGallery": "Set up a new photo gallery for your event",
- "createNewEventSubtitle": "Set up a new photo gallery for your event",
"eventNamePlaceholder": "e.g., John & Jane's Wedding",
- "welcomeMessageOptional": "Welcome Message (Optional)",
"welcomeMessagePlaceholder": "Welcome to our special day! Feel free to download and share these memories...",
"hostEmailPlaceholder": "customer@example.com",
"adminEmailPlaceholder": "admin@example.com",
"adminEmailPickFromAdmins": "Pick from admins:",
"adminEmailCustom": "Custom email",
- "securityAndAccess": "Security & Access",
"accessAndSecurity": "Access & Security",
"enterPassword": "Enter password",
"passwordPlaceholder": "Enter a secure password",
"confirmPasswordPlaceholder": "Confirm password",
- "galleryExpiresOn": "Gallery will expire on {{date}}",
- "guestsWillReceiveWarning": "Guests will receive a warning email 7 days before expiration.",
- "types": {
- "wedding": "Wedding",
- "birthday": "Birthday",
- "corporate": "Corporate",
- "other": "Other"
- },
- "themes": {
- "default": "Default",
- "oceanBlue": "Ocean Blue",
- "royalPurple": "Royal Purple",
- "roseGold": "Rose Gold",
- "sunsetAmber": "Sunset Amber"
- },
"eventDetails": "Event Details",
"eventName": "Event Name",
"eventType": "Event Type",
@@ -386,11 +371,9 @@
"hostName": "Customer Name",
"hostNamePlaceholder": "John Smith",
"adminEmail": "Admin Email",
- "adminNotificationEmail": "Admin Notification Email",
"expirationDate": "Expiration Date",
"active": "Active",
"archived": "Archived",
- "photoCount": "{{count}} photos",
"totalSize": "Total Size",
"shareLink": "Share Link",
"copyLink": "Copy Link",
@@ -403,10 +386,7 @@
"backToEvents": "Back to Events",
"loadingEventDetails": "Loading event details...",
"saveChanges": "Save Changes",
- "eventExpired": "This event has expired",
"eventExpiresIn": "This event expires in {{days}} days",
- "guestsNoAccess": "Guests can no longer access the gallery. Consider archiving this event.",
- "warningEmailsSent": "Warning emails have been sent to the customer.",
"overview": "Overview",
"photos": "Photos",
"categories": "Categories",
@@ -421,7 +401,6 @@
"externalFolderEmpty": "No subfolders",
"clearSelection": "Clear",
"welcomeMessage": "Welcome Message",
- "noWelcomeMessage": "No welcome message set",
"created": "Created",
"expires": "Expires",
"shareWithGuests": "Share this link with guests. They'll need the password to access the gallery.",
@@ -435,28 +414,18 @@
"managePhotos": "Manage Photos",
"actions": "Actions",
"archivingInfo": "Archiving will create a ZIP file of all photos and remove the gallery from public access.",
- "statistics": "Statistics",
- "views": "Views",
- "downloads": "Downloads",
- "noStatistics": "No statistics available yet",
- "archiveStatus": "Archive Status",
"archivedOn": "Archived On",
"downloadArchive": "Download Archive",
"loadingPhotos": "Loading photos...",
"photoCategories": "Photo Categories",
"organizeCategoriesInfo": "Organize your photos into categories. Categories help guests navigate and find specific types of photos.",
"categoriesTip": "Tip: Categories are specific to each event. You can create custom categories like \"Ceremony\", \"Reception\", \"Portraits\", etc.",
- "contactInformation": "Contact Information",
- "hostEmailHelp": "Customer will receive gallery creation and expiration notifications",
- "adminEmailHelp": "Will receive system notifications and archive confirmations",
- "securityAccess": "Security & Access",
"galleryPassword": "Gallery Password",
"requirePasswordToggle": "Require password for this gallery",
"requirePasswordToggleHelp": "Disable this if you want to share the gallery without a password. Anyone with the link will be able to view the photos.",
"publicGalleryWarning": "Public galleries are accessible to anyone with the link. Consider enabling download watermarks and monitoring activity.",
"passwordHelperText": "You can use dates like \"04.07.2025\" or any text with 6+ characters",
"confirmPassword": "Confirm Password",
- "showPasswords": "Show passwords",
"newPasswordLabel": "New Gallery Password",
"passwordReset": {
"title": "Reset Gallery Password",
@@ -481,15 +450,10 @@
"errorMinLength": "Password must be at least 6 characters",
"errorMismatch": "Passwords do not match"
},
- "gallerySettings": "Gallery Settings",
"themeAndStyle": "Theme & Style",
- "colorTheme": "Color Theme",
"galleryExpiration": "Gallery Expiration",
- "galleryExpiresIn": "Gallery Expires In",
"daysAfterEvent": "days after event date",
"expiresOn": "Expires on",
- "galleryWillExpireOn": "Gallery will expire on {{date}}",
- "expirationWarning": "Guests will receive a warning email 7 days before expiration.",
"noExpiration": "No Expiration",
"noExpirationHelp": "This gallery will remain active until manually archived.",
"photoCap": "Photo Limit",
@@ -501,11 +465,7 @@
"uploadCategory": "Upload Category",
"selectCategory": "Select a category for user uploads",
"uploadCategoryHelp": "All user-uploaded photos will be added to this category",
- "userUploadWarning": "User uploads will be moderated and can be removed by admins at any time.",
"allowDownloads": "Allow photo downloads",
- "allowDownloadsHelp": "Allow guests to download photos from this gallery",
- "downloadPermissions": "Download Permissions",
- "downloadsEnabled": "Downloads Enabled",
"downloadsDisabled": "Downloads Disabled",
"downloadProtection": "Download Protection",
"disableRightClick": "Block right-click menu",
@@ -554,15 +514,6 @@
"heroImageAnchorBottom": "Bottom",
"heroPreview": "Hero preview",
"noPhotosAvailable": "No photos available",
- "processingRequest": "Processing your request...",
- "eventTypeWedding": "Wedding",
- "eventTypeBirthday": "Birthday",
- "eventTypeCorporate": "Corporate",
- "eventTypeOther": "Other",
- "days30": "30 days",
- "days60": "60 days",
- "days90": "90 days",
- "days365": "1 year",
"inactive": "Inactive",
"expired": "Expired",
"draft": "Draft",
@@ -570,31 +521,36 @@
"publishConfirm": "This will make the gallery accessible and send the notification email to the client. Continue?",
"publishSuccess": "Gallery published and client notified!",
"draftBanner": "This gallery is in draft mode. Upload your photos, then publish when ready.",
- "daysLeft": "({{count}} day left)",
- "daysLeft_plural": "({{count}} days left)",
"subtitle": "Manage your photo galleries and events",
- "loadingEvents": "Loading events...",
"failedToLoadEvents": "Failed to load events",
"tryAgain": "Try Again",
- "bulkArchiveSuccess": "Successfully archived {{count}} events",
"bulkArchivePartial": "Archived {{success}} events, {{failed}} failed",
"deleteSelected": "Delete Selected",
"bulkDelete": {
- "title": "Permanently delete {{count}} events?",
"warning": "This will permanently delete the selected events, all their photos, archives, and audit logs. This action cannot be undone.",
+ "passwordLabel": "Re-enter your password to confirm",
+ "passwordPlaceholder": "Your admin password",
+ "passwordHelp": "We require your password as a safeguard against accidental bulk deletions.",
+ "incorrectPassword": "Incorrect password. No events were deleted.",
"confirmLabel": "Type {{literal}} to confirm",
"confirmHelp": "A typed confirmation prevents accidental deletions and isn't affected by browser autofill or passkey shortcuts.",
"submit": "Delete {{count}} events",
"processing": "Deleting {{count}} events. This may take a few minutes — please don't close this window.",
"successAll": "Permanently deleted {{count}} events",
"successPartial": "Deleted {{success}} events, {{failed}} failed",
- "errorGeneric": "Failed to delete events"
+ "errorGeneric": "Failed to delete events",
+ "successAll_one": "events.bulkDelete.successAll",
+ "successAll_other": "events.bulkDelete.successAll",
+ "title_one": "Permanently delete {{count}} events?",
+ "title_other": "Permanently delete {{count}} events?",
+ "processing_one": "Deleting {{count}} events. This may take a few minutes — please don't close this window.",
+ "processing_other": "Deleting {{count}} events. This may take a few minutes — please don't close this window.",
+ "submit_one": "Delete {{count}} events",
+ "submit_other": "Delete {{count}} events"
},
"searchEventsPlaceholder": "Search events...",
"all": "All",
"expiring": "Expiring",
- "eventsSelected": "{{count}} event selected",
- "eventsSelected_plural": "{{count}} events selected",
"clear": "Clear",
"archiveSelected": "Archive Selected",
"publicAccess": "Public access",
@@ -623,22 +579,14 @@
"extendSevenDays": "Extend 7 Days",
"welcomeMessageLabel": "Welcome Message",
"noWelcomeMessageSet": "No welcome message set",
- "createdOn": "Created",
"copy": "Copy",
"copied": "Copied!",
- "organizingPhotosInfo": "Organize your photos into categories. Categories help guests navigate and find specific types of photos.",
"archiveStatusTitle": "Archive Status",
"downloadingArchive": "Downloading {{name}} archive...",
"downloadStarted": "Download started",
"failedToDownloadArchive": "Failed to download archive",
- "statisticsNotAvailable": "No statistics available yet",
- "photoFilters": "Photo Filters",
- "noStatisticsAvailableYet": "No statistics available yet",
- "addPlus": "Add+",
"galleryTheme": "Gallery Theme",
- "customizeTheme": "Customize Theme",
"noThemeSet": "No theme configured",
- "customizingTheme": "Customizing gallery theme",
"customizingThemeFor": "Customizing theme for {{event}}",
"customCssTemplate": "Custom CSS Template",
"customCssTemplateDesc": "Apply a custom CSS template to style the gallery with unique visual effects.",
@@ -652,26 +600,44 @@
"renamingFiles": "Renaming files...",
"complete": "Complete!",
"failed": "Rename failed",
- "filesRenamed": "{{count}} files updated",
- "confirm": "Rename Event"
+ "confirm": "Rename Event",
+ "success": "Event renamed successfully!",
+ "filesRenamed_one": "{{count}} files updated",
+ "filesRenamed_other": "{{count}} files updated",
+ "newLink": "New Gallery Link",
+ "currentName": "Current name:",
+ "newName": "New Event Name",
+ "enterNewName": "Enter new event name",
+ "newUrl": "New URL:",
+ "checkingAvailability": "Checking availability...",
+ "resendEmail": "Resend invitation email with new gallery link",
+ "emailTo": "Send updated gallery access email to",
+ "warningTitle": "Please note:",
+ "warning1": "The gallery URL will change",
+ "warning2": "Old URLs will automatically redirect to the new URL",
+ "warning3": "Photo files may be renamed"
},
- "activeFilter": "Active",
- "archivedFilter": "Archived",
- "sortByName": "By Name",
- "sortByDate": "By Date",
- "sortByExpiration": "By Expiration",
- "photosCount": "Photos",
- "moreActions": "More Actions",
- "copyLinkTooltip": "Copy Link",
- "viewGalleryTooltip": "View Gallery",
- "uploadPhotosTooltip": "Upload Photos",
- "editTooltip": "Edit",
- "archiveTooltip": "Archive",
- "noEvents": "No events found",
- "noEventsDescription": "Create your first event to get started.",
- "bulkArchive": "Archive",
- "confirmBulkArchive": "Are you sure you want to archive {{count}} event(s)?",
- "confirmBulkArchiveDescription": "This action cannot be undone. Archived events will no longer be publicly accessible."
+ "bulkArchiveSuccess_one": "Successfully archived {{count}} event",
+ "bulkArchiveSuccess_other": "Successfully archived {{count}} events",
+ "daysLeft_one": "({{count}} day left)",
+ "daysLeft_other": "({{count}} days left)",
+ "eventsSelected_one": "{{count}} event selected",
+ "eventsSelected_other": "{{count}} events selected",
+ "paginationLabel": "{{from}}–{{to}} of {{total}}",
+ "filtered": "filtered",
+ "pageOf": "Page {{page}} of {{totalPages}}",
+ "notFound": "Event not found",
+ "customerPhone": "Customer Phone",
+ "customerPhonePlaceholder": "+1 555 555 1234",
+ "allowPresignedDownload": "Allow direct S3 download (no watermark, S3 mode only)",
+ "neverExpires": "Never",
+ "rightClickBlocked": "Right-click blocked",
+ "devtoolsDetection": "DevTools detection",
+ "watermarked": "Watermarked",
+ "importExternal": "Import from External Folder",
+ "externalImportInfo": "All pictures from the selected folder will be imported.",
+ "selectExternalFolder": "Select external folder under /external-media",
+ "importFromSelectedFolder": "Import from selected folder"
},
"settings": {
"title": "System Settings",
@@ -683,9 +649,7 @@
"siteUrl": "Site URL",
"siteUrlHelp": "Used for generating gallery links in emails",
"defaultExpiration": "Default Expiration (days)",
- "defaultExpirationHelp": "How long galleries remain active by default",
"maxFileSize": "Max File Size (MB)",
- "maxFileSizeHelp": "Maximum size per uploaded photo",
"maxFilesPerUpload": "Max Files per Upload",
"maxFilesPerUploadHelp": "Maximum number of photos allowed in a single upload batch (1-{{max}}).",
"allowedFileTypes": "Allowed File Types",
@@ -697,13 +661,7 @@
"enableShortGalleryUrlsHelp": "Removes the event slug from new share links while keeping existing links working.",
"maintenanceMode": "Enable maintenance mode",
"language": "Language",
- "defaultLanguage": "Default Language",
"defaultLanguageHelp": "Language shown to guests before login",
- "defaultWelcomeMessage": "Default Welcome Message",
- "welcomeMessage": "Welcome Message",
- "welcomeMessagePlaceholder": "Enter a default welcome message that will be included in gallery creation emails",
- "welcomeMessageHelp": "This message will be included in all gallery creation emails unless overridden when creating an event",
- "saveSettings": "Save General Settings",
"saveGeneralSettings": "Save General Settings",
"dateTimeFormat": "Date & Time Format",
"dateFormat": "Date Format",
@@ -721,7 +679,6 @@
"accountSaveSuccess": "Account details updated"
},
"publicSite": {
- "tabLabel": "Public Site",
"badge": "Public Landing",
"title": "Public Landing Page",
"subtitle": "Publish a customized landing page for guests when they visit your domain.",
@@ -749,8 +706,6 @@
"htmlRequired": "Provide HTML content before enabling the public site."
},
"storage": {
- "title": "Storage",
- "overview": "Storage Overview",
"totalUsed": "Total Used",
"archiveStorage": "Archive Storage",
"storageLimit": "Storage Limit",
@@ -762,7 +717,6 @@
"diskCapacityReported": "Disk Capacity (reported)",
"diskAvailable": "Available",
"diskAvailableReported": "Available (reported)",
- "diskFree": "Free",
"diskFreeReported": "Free (reported)",
"diskMetricsUnavailable": "Disk metrics are not available in Docker Desktop or virtualized environments.",
"applyRecommended": "Use recommended",
@@ -781,17 +735,12 @@
"capacityRequiredForAvailable": "Enter a total capacity before setting available space.",
"availableExceedsCapacity": "Available space cannot exceed the total capacity.",
"storageUsage": "Storage Usage",
- "storageByEvent": "Storage by Event",
- "storageManagement": "Storage Management",
- "storageManagementHelp": "Consider archiving or deleting old events to free up storage space. Archived events are compressed and use less storage than active galleries.",
- "noEventsUsingStorage": "No events using storage",
"unlimited": "Unlimited"
},
"security": {
"title": "Security",
"passwordSettings": "Password Settings",
"minPasswordLength": "Minimum Password Length",
- "minPasswordLengthHelp": "Minimum number of characters for gallery passwords",
"passwordComplexity": "Password Complexity",
"passwordComplexityHelp": "Security level required for gallery passwords",
"complexitySimple": "Simple (6+ chars, any text)",
@@ -800,7 +749,6 @@
"complexityVeryStrong": "Very Strong (12+ chars, all character types)",
"sessionAuth": "Session & Authentication",
"sessionTimeout": "Session Timeout (minutes)",
- "sessionTimeoutHelp": "Admin session timeout in minutes",
"maxLoginAttempts": "Max Login Attempts",
"maxLoginAttemptsHelp": "Maximum failed login attempts per IP before lockout",
"attemptWindowMinutes": "Attempt Window (minutes)",
@@ -811,11 +759,8 @@
"recaptchaSettings": "reCAPTCHA Settings",
"enableRecaptcha": "Enable reCAPTCHA for login forms",
"siteKey": "Site Key",
- "siteKeyHelp": "Your reCAPTCHA v2 site key (public)",
"secretKey": "Secret Key",
- "secretKeyHelp": "Your reCAPTCHA v2 secret key (keep private)",
"recaptchaHelp": "Get your reCAPTCHA keys from",
- "saveSettings": "Save Security Settings",
"saveSecuritySettings": "Save Security Settings"
},
"categories": {
@@ -857,8 +802,6 @@
"missingDimensions": "Missing Dimensions",
"repairButton": "Repair Dimensions",
"repairing": "Repairing...",
- "alreadyRunning": "Repair is already running",
- "started": "Started repairing {{count}} photos",
"noneToRepair": "All photos already have dimensions",
"resultSuccess": "Last repair: {{success}} updated, {{failed}} failed",
"description": "Backfill missing width/height for photos uploaded before dimension tracking was added. Required for Masonry and Mosaic layouts."
@@ -876,11 +819,12 @@
"sendTest": "Send Test Email",
"saved": "Settings saved",
"saveError": "Failed to save settings",
- "emailSent": "Notification email sent to {{count}} recipients",
"emailFailed": "Failed to send notification",
"checkSuccess": "Notification sent for new version",
"checkNoAction": "No notification needed: {{reason}}",
- "checkError": "Failed to check for updates"
+ "checkError": "Failed to check for updates",
+ "emailSent_one": "Notification email sent to {{count}} recipients",
+ "emailSent_other": "Notification email sent to {{count}} recipients"
},
"events": {
"title": "Event Creation",
@@ -902,7 +846,13 @@
"expirationWarning": "Galleries without expiration will remain active until manually archived",
"saveSettings": "Save Event Settings",
"noteTitle": "Note",
- "noteText": "These settings only affect new event creation. Existing events are not affected. Default behavior requires all fields."
+ "noteText": "These settings only affect new event creation. Existing events are not affected. Default behavior requires all fields.",
+ "defaultRequirePassword": "Require password by default",
+ "defaultRequirePasswordHelp": "Pre-check \"Require password\" when creating new events. Disable for quicker creation of public galleries.",
+ "showGalleryFilterBar": "Show filter bar in galleries",
+ "showGalleryFilterBarHelp": "Display the search-by-filename and sort controls above grid-layout galleries. Disable for a cleaner layout.",
+ "enablePhoneField": "Enable phone number field",
+ "enablePhoneFieldHelp": "Adds an optional phone number input to the event form. Useful for downstream automations like WhatsApp delivery via n8n. Always optional even when enabled."
},
"imageSecurity": {
"title": "Image Protection",
@@ -975,11 +925,6 @@
"format": "Format",
"fit": "Fit Mode",
"fitHelp": "How images are resized to fit the thumbnail dimensions. \"Cover\" crops to fill, \"Contain\" fits within bounds.",
- "fit_cover": "Cover (crop to fill)",
- "fit_contain": "Contain (fit within)",
- "fit_fill": "Fill (stretch)",
- "fit_inside": "Inside (shrink to fit)",
- "fit_outside": "Outside (expand to cover)",
"regenerateTitle": "Regenerate Thumbnails",
"regenerateHelp": "After changing thumbnail settings, regenerate all existing thumbnails to apply the new configuration. This runs in the background and may take a while for large galleries.",
"regenerateButton": "Regenerate All Thumbnails",
@@ -1042,11 +987,57 @@
"deviceTypes": "Device types from user agents",
"privacy": "Privacy",
"privacyText": "IP addresses are hashed for privacy. No personal data is stored. Analytics data is retained for 90 days."
- }
+ },
+ "groups": {
+ "general": "General",
+ "display": "Display",
+ "privacySecurity": "Privacy & Security",
+ "integrations": "Integrations",
+ "system": "System"
+ },
+ "apiTokens": {
+ "title": "API Tokens",
+ "createError": "Failed to create token",
+ "revoked": "Token revoked",
+ "subtitle": "Long-lived bearer tokens for the public /api/v1 surface — n8n integrations, custom apps, scripts. Tokens act as the admin user that minted them, intersected with the chosen scopes.",
+ "copyNow": "Copy this token now — it will not be shown again.",
+ "copied": "Copied",
+ "copyFailed": "Copy failed",
+ "name": "Name",
+ "namePlaceholder": "e.g. n8n production",
+ "scopes": "Scopes",
+ "generate": "Generate Token",
+ "scopeHint": "admin > write > read. A read-only token cannot mutate, even if its owner is super_admin.",
+ "existing": "Existing tokens",
+ "lastUsed": "Last used",
+ "created": "Created",
+ "status": "Status",
+ "statusRevoked": "Revoked",
+ "statusExpired": "Expired",
+ "statusActive": "Active",
+ "confirmRevoke": "settings.apiTokens.confirmRevoke",
+ "revoke": "Revoke",
+ "empty": "No tokens yet. Generate one above to get started."
+ },
+ "webhooks": {
+ "title": "Webhooks",
+ "subtitle": "POST event notifications to your URL the moment something happens — gallery published, photo uploaded, event archived, etc. Signed with HMAC-SHA256 in the X-PicPeak-Signature header.",
+ "piiNotice": "event.* payloads include customer contact info (name, email, phone) and the gallery share token if you have stored them. Only point webhooks at receivers you trust — they have everything needed to message the customer or open the gallery.",
+ "copyNow": "Copy this signing secret now — it will not be shown again.",
+ "name": "Name",
+ "url": "Receiver URL",
+ "events": "Subscribe to events",
+ "filter": "Filter (JSON, optional)",
+ "template": "Template (optional)",
+ "create": "Create Webhook",
+ "existing": "Existing webhooks",
+ "empty": "No webhooks yet. Create one above to start receiving event notifications."
+ },
+ "sectionLabel": "Settings section",
+ "navAriaLabel": "Settings navigation"
},
"analytics": {
"title": "Analytics Dashboard",
- "titleSimple": "Analytics",
"subtitle": "Track gallery performance and visitor engagement",
"detailedSubtitle": "Detailed analytics powered by Umami",
"loadingAnalytics": "Loading analytics...",
@@ -1074,13 +1065,10 @@
"totalPhotos": "Total Photos",
"activeEvents": "Active Events",
"notConfigured": "Umami Analytics Not Configured",
- "configureInstructions": "To see real analytics data, configure Umami in your environment variables and admin panel settings.",
- "noData": "No data available",
- "percentChange": "{{percent}}% from last period"
+ "configureInstructions": "To see real analytics data, configure Umami in your environment variables and admin panel settings."
},
"branding": {
"title": "Branding & Themes",
- "titleFull": "Branding & Customization",
"subtitle": "Customize the look and feel of your galleries",
"loadingBranding": "Loading branding settings...",
"themeAndStyle": "Theme & Style",
@@ -1092,18 +1080,14 @@
"supportEmail": "Support Email",
"supportEmailHelp": "Contact email for guest support",
"footerText": "Footer Text",
- "footerTextHelp": "Displayed at the bottom of galleries",
"logo": "Logo",
- "currentLogo": "Current logo",
"uploadLogo": "Upload Logo",
- "removeLogo": "Remove Logo",
"logoHelp": "Recommended size: 200x60px, PNG or JPEG",
"favicon": "Favicon",
"currentFavicon": "Current favicon",
"uploadFavicon": "Upload Favicon",
"removeFavicon": "Remove Favicon",
"faviconHelp": "PNG or ICO format, recommended size: 32x32px",
- "watermark": "Watermark",
"watermarkSettings": "Watermark Settings",
"enableWatermarks": "Enable Watermarks",
"watermarkHelp": "Add your company name as a watermark on downloaded photos",
@@ -1120,11 +1104,7 @@
"watermarkSize": "Watermark Size",
"theme": "Theme",
"galleryTheme": "Gallery Theme",
- "themeCustomization": "Theme Customization",
- "selectPreset": "Select a preset theme",
"colors": "Colors",
- "primaryColor": "Primary Color",
- "secondaryColor": "Secondary Color",
"accentColor": "Accent Color",
"backgroundColor": "Background Color",
"textColor": "Text Color",
@@ -1133,27 +1113,13 @@
"colorModeDark": "Dark",
"colorModeAuto": "Auto",
"colorModeHelp": "Auto follows the visitor's system preference.",
- "customCSS": "Custom CSS",
"preview": "Preview",
- "previewInNewTab": "Preview in New Tab",
- "reset": "Reset",
"saveChanges": "Save Changes",
"applyLivePreview": "Apply changes immediately (Live Preview)",
"eventSpecificThemes": "Event-Specific Themes",
"eventThemesInfo": "You can override these global theme settings for individual events when creating or editing them.",
"themePresets": "Theme Presets",
"galleryLayout": "Gallery Layout",
- "layoutDescriptions": {
- "grid": "Classic grid layout with consistent photo sizes",
- "masonry": "Pinterest-style layout with varied heights",
- "carousel": "Full-screen slideshow with navigation",
- "timeline": "Photos organized by date",
- "hero": "Featured image with grid below",
- "mosaic": "Artistic layout with mixed sizes",
- "justified": "Row-based layout preserving aspect ratios",
- "gallery-premium": "Elegant light theme with hero and masonry (Beta)",
- "gallery-story": "Cinematic dark theme with scene sections (Beta)"
- },
"layoutSettings": "Layout Settings",
"photoSpacing": "Photo Spacing",
"spacing": {
@@ -1210,16 +1176,6 @@
"xl": "XL — Largest photos"
},
"thumbnailScaleHint": "Adjusts column count relative to the base grid columns",
- "showHeroSection": "Show Hero Section",
- "showHeroSectionHint": "Display a featured hero image above the justified gallery",
- "heroHeight": "Hero Section Height",
- "heroHeightOptions": {
- "small": "Small (40-50%)",
- "medium": "Medium (50-70%)",
- "large": "Large (60-80%)"
- },
- "heroOverlayOpacity": "Hero Overlay Opacity",
- "heroOverlayHint": "Darken the hero image to improve text readability",
"typographyAndStyle": "Typography & Style",
"bodyFont": "Body Font",
"headingFont": "Heading Font",
@@ -1265,8 +1221,6 @@
},
"resetToDefault": "Reset to Default",
"applyTheme": "Apply Theme",
- "customTheme": "Custom Theme",
- "customizeTheme": "Customize Theme",
"saveTheme": "Save Theme",
"previewLayout": "Preview Layout",
"livePreview": "Live Preview",
@@ -1284,9 +1238,6 @@
"logoMaxHeight": "Maximum Height (pixels)",
"logoMaxHeightHelp": "Set a custom maximum height for the logo (20-200 pixels)",
"logoPosition": "Logo Position in Header",
- "positionLeft": "Left",
- "positionCenter": "Center",
- "positionRight": "Right",
"logoDisplayMode": "Display Mode",
"logoOnly": "Logo Only",
"textOnly": "Company Name Only",
@@ -1297,29 +1248,8 @@
"showLogoInHeroHelp": "Display the logo in hero sections (for non-grid layouts)",
"headerStyle": "Header Style",
"headerStyleDescription": "Choose how the gallery header appears. The header style is independent of the photo layout.",
- "headerStyleOptions": {
- "hero": "Hero Image",
- "standard": "Standard",
- "banner": "Banner",
- "minimal": "Minimal",
- "none": "No Header"
- },
- "headerStyleDescriptions": {
- "hero": "Full-height image with event info overlay",
- "standard": "Compact inline header with event details",
- "banner": "Standard header plus a colored banner above",
- "minimal": "Compact header with essential info",
- "none": "Hide header completely"
- },
"heroDividerStyle": "Divider Style",
"heroDividerDescription": "Choose how the transition between the hero image and gallery content looks.",
- "dividerOptions": {
- "wave": "Wave",
- "straight": "Straight",
- "angle": "Angle",
- "curve": "Curve",
- "none": "None"
- },
"controlsStyle": "Controls Style",
"controlsStyleDescription": "Choose how gallery filters and controls are displayed.",
"controlsStyleOptions": {
@@ -1333,15 +1263,43 @@
"controlsStyleHeroWarning": "Sidebar is recommended for hero headers to prevent controls appearing above the hero image.",
"betaThumbnailWarningTitle": "Low thumbnail resolution detected",
"betaThumbnailWarningText": "Your thumbnails are currently {{width}}×{{height}}px. Beta themes display photos at larger sizes and require at least {{recommended}}×{{recommended}}px for good quality. Increase the thumbnail dimensions in Settings > Thumbnails and regenerate.",
- "betaThumbnailWarningLink": "Go to Thumbnail Settings"
+ "betaThumbnailWarningLink": "Go to Thumbnail Settings",
+ "logoSize": "Logo Size",
+ "surfaceColor": "Surface",
+ "elevatedColor": "Elevated",
+ "borderColor": "Border",
+ "mutedTextColor": "Muted text",
+ "accentDarkColor": "Accent (filled)",
+ "syncFromBranding": "Sync from Branding",
+ "forceColorMode": "Force color mode",
+ "forceColorModeHelp": "Lock the entire admin and public site to dark or light. The user-facing dark/light toggle is hidden whenever a lock is active. Per-event themes that try to override the colour mode are also forced to follow.",
+ "forceColorModeNone": "No force (user choice)",
+ "forceColorModeDark": "Force dark",
+ "forceColorModeLight": "Force light",
+ "colorGroupSurfaces": "Surfaces",
+ "colorGroupSurfacesHelp": "The neutral layers behind your content. Background sits furthest back; Surface and Elevated stack on top.",
+ "backgroundColorHelp": "The page itself — body background of every gallery, admin page and CMS page.",
+ "surfaceColorHelp": "Cards, sidebar, header bar and navigation. The first layer above Background.",
+ "elevatedColorHelp": "Panels that float above cards: image placeholders, hover/active rows, modal headers, code blocks.",
+ "borderColorHelp": "Dividers, table grid lines, card outlines, input borders.",
+ "colorGroupText": "Text",
+ "colorGroupTextHelp": "Foreground text colours. Primary is for everything readers focus on; Secondary is for supporting copy.",
+ "textColorHelp": "Headlines, body copy, table cells, form input values, navigation labels — the main text colour.",
+ "mutedTextColorHelp": "Captions, helper text under inputs, table column headers, footer links, dates and metadata.",
+ "colorGroupAccent": "Accent",
+ "colorGroupAccentHelp": "Brand colours that highlight interactive elements. Use a strong colour pair — Accent is for outlines/text, Accent Dark is for filled buttons.",
+ "accentColorHelp": "Links, icons, focus rings, hover states on primary buttons, active sidebar item underline. Should read clearly on both Background and Surface.",
+ "accentDarkColorHelp": "Filled CTA buttons, active sidebar item background, badges and tags. Needs enough contrast for white text to be readable on top.",
+ "cssTemplate": "CSS Template",
+ "cssTemplateDescription": "Select a pre-built CSS template to apply application-wide styling to this gallery. Templates can be managed in Settings > CSS Templates.",
+ "noTemplate": "No Template",
+ "noTemplateDescription": "Use only theme settings without a CSS template",
+ "templateSlot": "Slot {{slot}}",
+ "eventCustomCSS": "Event-specific Custom CSS"
},
"admin": {
"title": "Admin Panel",
- "welcome": "Welcome back, {{name}}",
"recentActivity": "Recent Activity",
- "systemStatus": "System Status",
- "totalEvents": "Total Events",
- "activeGalleries": "Active Galleries",
"storageUsed": "Storage Used",
"totalPhotos": "Total Photos",
"storagePercent": "{{percent}}% of limit {{limit}}",
@@ -1351,9 +1309,6 @@
"archivedEvents": "Archived Events",
"systemHealth": "System Health",
"health": {
- "healthy": "Healthy",
- "warning": "Warning",
- "error": "Error",
"checking": "Checking..."
},
"updates": {
@@ -1366,9 +1321,7 @@
"beta": "BETA",
"viewReleaseNotes": "View Release Notes",
"updateAvailableShort": "v{{version}} available",
- "checkForUpdates": "Check for Updates",
"upToDate": "You're up to date",
- "lastChecked": "Last checked: {{time}}",
"updateNow": "Update Now",
"updateDialog": {
"title": "Update PicPeak",
@@ -1382,8 +1335,6 @@
}
},
"notifications": "Notifications",
- "viewAllNotifications": "View all notifications",
- "noNotifications": "No new notifications",
"markAllRead": "Mark all read",
"clearAll": "Clear all",
"close": "Close",
@@ -1393,16 +1344,13 @@
"eventArchived": "Event \"{{eventName}}\" was archived",
"eventUpdated": "Event \"{{eventName}}\" was updated",
"eventDeleted": "Event \"{{eventName}}\" was deleted",
- "photosUploaded": "{{count}} photos uploaded to \"{{eventName}}\"",
"photoDeleted": "Photo deleted from \"{{eventName}}\"",
- "photosBulkDeleted": "{{count}} photos deleted from \"{{eventName}}\"",
"eventExpiring": "Event \"{{eventName}}\" expires in {{days}} days",
"eventExpired": "Event \"{{eventName}}\" has expired",
"passwordChanged": "Password changed by {{actorName}}",
"passwordReset": "Password reset for \"{{eventName}}\"",
"settingsUpdated": "{{type}} settings updated",
"emailTemplateUpdated": "Email template \"{{template}}\" updated",
- "bulkDownload": "{{count}} photos downloaded from \"{{eventName}}\"",
"storageWarning": "Storage usage at {{percentage}}%",
"adminLogout": "Admin {{actorName}} logged out",
"categoryCreated": "Category \"{{name}}\" created for \"{{eventName}}\"",
@@ -1419,29 +1367,22 @@
"archiveDeleted": "Archive deleted for \"{{eventName}}\"",
"archiveRestored": "Archive restored for \"{{eventName}}\"",
"systemActivity": "System activity: {{type}}",
- "adminProfileUpdated": "Admin profile updated by {{actorName}}"
+ "adminProfileUpdated": "Admin profile updated by {{actorName}}",
+ "photosUploaded_one": "{{count}} photo uploaded to \"{{eventName}}\"",
+ "photosUploaded_other": "{{count}} photos uploaded to \"{{eventName}}\"",
+ "photosBulkDeleted_one": "{{count}} photo deleted from \"{{eventName}}\"",
+ "photosBulkDeleted_other": "{{count}} photos deleted from \"{{eventName}}\"",
+ "bulkDownload_one": "{{count}} photo downloaded from \"{{eventName}}\"",
+ "bulkDownload_other": "{{count}} photos downloaded from \"{{eventName}}\""
},
"notificationToasts": {
"markedAllRead": "All notifications marked as read",
- "clearedAll": "Cleared {{count}} notifications",
- "profileUpdated": "Admin profile updated"
+ "clearedAll_one": "Cleared {{count}} notification",
+ "clearedAll_other": "Cleared {{count}} notifications"
},
- "markAsRead": "Mark as read",
- "markAllAsRead": "Mark all as read",
- "notificationSettings": "Notification Settings",
"changePassword": "Change Password",
"darkMode": "Switch to dark mode",
"lightMode": "Switch to light mode",
- "accountSettings": {
- "title": "Admin account",
- "description": "Update the credentials used to sign in to PicPeak.",
- "username": "Username",
- "usernamePlaceholder": "Admin",
- "email": "Email",
- "emailPlaceholder": "admin@example.com",
- "updateButton": "Update profile"
- },
- "profileUpdateError": "Unable to update admin profile. Please try again.",
"loadingDashboard": "Loading dashboard...",
"activeEvents": "Active Events",
"expiringSoon": "Expiring Soon",
@@ -1452,110 +1393,88 @@
"dashboardSubtitle": "Welcome back! Here's what's happening with your galleries.",
"eventsExpiringSoon": "Events Expiring Soon",
"noEventsExpiring": "No events expiring in the next 7 days",
- "daysLeft": "{{count}} day left",
- "daysLeft_plural": "{{count}} days left",
- "viewAllExpiringEvents": "View all {{count}} expiring events",
"noRecentActivity": "No recent activity",
- "viewAllActivity": "View all activity",
- "quickActions": "Quick Actions",
- "viewArchives": "View Archives",
- "analytics": "Analytics",
- "activities": {
- "event_created": "New event created: {{eventName}}",
- "photos_uploaded": "{{count}} photos uploaded to {{eventName}}",
- "event_archived": "Event archived: {{eventName}}",
- "archive_restored": "Archive restored: {{eventName}}",
- "archive_deleted": "Archive deleted: {{eventName}}",
- "archive_downloaded": "Archive downloaded: {{eventName}}",
- "email_config_updated": "Email configuration updated",
- "email_template_updated": "Email template updated: {{template}}",
- "branding_updated": "Branding settings updated",
- "theme_updated": "Theme settings updated",
- "bulk_download": "{{count}} photos downloaded from {{eventName}}",
- "gallery_password_entry": "Password entered for {{eventName}}",
- "expiration_warning_viewed": "Expiration warning viewed for {{eventName}}",
- "feedback_settings_updated": "Feedback settings updated",
- "feedback_moderated": "Feedback moderated",
- "feedback_deleted": "Feedback deleted",
- "photo_like": "Photo liked in {{eventName}}",
- "photo_favorite": "Photo favorited in {{eventName}}",
- "photo_rating": "Photo rated in {{eventName}}",
- "photo_comment": "Photo commented in {{eventName}}",
- "guest_feedback_like": "Guest liked a photo in {{eventName}}",
- "guest_feedback_favorite": "Guest favorited a photo in {{eventName}}",
- "guest_feedback_rating": "Guest rated a photo in {{eventName}}",
- "guest_feedback_comment": "Guest commented on a photo in {{eventName}}",
- "word_filter_added": "Word filter added",
- "external_import_completed": "External media import completed ({{imported}} imported, {{skipped}} skipped)",
- "bulk_archive_completed": "Bulk archive completed",
- "event_activated": "Event activated: {{eventName}}",
- "event_deactivated": "Event deactivated: {{eventName}}",
- "photo_deleted": "Photo deleted from {{eventName}}",
- "photos_bulk_deleted": "{{count}} photos deleted from {{eventName}}",
- "settings_updated": "Settings updated",
- "event_updated": "Event updated: {{eventName}}",
- "event_renamed": "Event renamed: {{eventName}}",
- "event_deleted": "Event deleted: {{eventName}}",
- "password_changed": "Password changed",
- "email_resent": "Creation email resent for: {{eventName}}",
- "category_created": "Category created: {{categoryName}}",
- "category_updated": "Category updated: {{categoryName}}",
- "category_deleted": "Category deleted: {{categoryName}}",
- "general_settings_updated": "General settings updated",
- "favicon_uploaded": "Favicon uploaded",
- "analytics_settings_updated": "Analytics settings updated",
- "cms_page_updated": "CMS page updated: {{page}}",
- "security_settings_updated": "Security settings updated",
- "password_reset": "Password reset for: {{eventName}}",
- "admin_logout": "Admin {{actorName}} logged out",
- "system_activity": "System activity: {{type}}",
- "unknown": "Unknown activity"
- },
- "userManagement": "User Management",
- "inviteUser": "Invite User",
- "pendingInvitations": "Pending Invitations",
- "roles": {
- "super_admin": "Super Admin",
- "admin": "Admin",
- "editor": "Editor",
- "viewer": "Viewer"
- },
- "userStatus": {
- "active": "Active",
- "inactive": "Inactive"
- },
- "inviteForm": {
- "email": "Email Address",
- "role": "Role",
- "send": "Send Invitation"
- },
- "acceptInvite": {
- "title": "Accept Admin Invitation",
- "username": "Choose a Username",
- "password": "Create Password",
- "submit": "Create Account"
- },
"photos": {
"hidden": "Hidden",
"hideSelected": "Hide",
"showSelected": "Show",
"hiddenSuccess": "Photos hidden from guests",
- "visibleSuccess": "Photos now visible to guests"
+ "visibleSuccess": "Photos now visible to guests",
+ "processingStatus": "Processing…",
+ "processingFailed": "Failed",
+ "retryQueued": "Retry queued"
+ },
+ "events": {
+ "tabs": {
+ "guests": "Guests"
+ }
+ },
+ "daysLeft_one": "{{count}} day left",
+ "daysLeft_other": "{{count}} days left",
+ "viewAllExpiringEvents_one": "View all {{count}} expiring events",
+ "viewAllExpiringEvents_other": "View all {{count}} expiring events",
+ "guests": {
+ "loading": "Loading...",
+ "aggregate": {
+ "empty": "No guest picks yet.",
+ "description": "Photos sorted by how many distinct guests liked or favorited them."
+ },
+ "inviteCreated": "Invite created",
+ "inviteCreateError": "Failed to create invite",
+ "inviteRevoked": "Invite revoked",
+ "inviteRevokeError": "Failed to revoke invite",
+ "invitesTitle": "Guest invites",
+ "createInvite": "Create invite",
+ "inviteName": "Guest name",
+ "inviteEmail": "Email (optional)",
+ "generateInvite": "Generate invite link",
+ "existingInvites": "Existing invites",
+ "noInvites": "No invites yet",
+ "copyLink": "Copy link",
+ "revokeInvite": "Revoke",
+ "deletedToast": "Guest removed",
+ "deletedError": "Failed to remove guest",
+ "mergedToast": "Guests merged",
+ "mergedError": "Failed to merge guests",
+ "forgetGuestConfirm": "Remove this guest? Their picks will be anonymized but kept in aggregate totals.",
+ "exportError": "Export failed",
+ "mergeSelectAtLeastTwo": "Select at least 2 guests to merge",
+ "mergeConfirm_one": "Merge {{count}} guests into {{name}}? This cannot be undone.",
+ "mergeConfirm_other": "Merge {{count}} guests into {{name}}? This cannot be undone.",
+ "backToList": "Back to list",
+ "title": "Guests",
+ "mergeSelected_one": "{{count}} selected",
+ "mergeSelected_other": "{{count}} selected",
+ "mergeNow": "Merge selected",
+ "aggregateView": "By popularity",
+ "mergeMode": "Merge",
+ "exportAll": "Export all",
+ "empty": "No guests have registered yet.",
+ "columns": {
+ "name": "Name",
+ "email": "Email",
+ "likes": "Likes",
+ "favorites": "Favorites",
+ "comments": "Comments",
+ "ratings": "Ratings",
+ "lastSeen": "Last seen"
+ },
+ "view": "View details",
+ "export": "Export",
+ "forgetGuest": "Remove guest",
+ "loadingDetail": "Loading selections...",
+ "detail": {
+ "noComments": "No comments",
+ "empty": "No selections in this category"
+ }
}
},
- "permissions": {
- "insufficient": "You don't have permission to perform this action",
- "viewOnly": "View Only"
- },
"acceptInvitation": {
"title": "Accept Invitation",
"subtitle": "Create your admin account",
"validating": "Validating invitation...",
"invalidToken": "Invalid Invitation",
"invalidTokenMessage": "This invitation link is invalid or has expired. Please contact your administrator for a new invitation.",
- "expiredToken": "Invitation Expired",
- "expiredTokenMessage": "This invitation has expired. Please request a new invitation from your administrator.",
- "alreadyUsed": "Invitation Already Used",
"alreadyUsedMessage": "This invitation has already been used to create an account.",
"invitedAs": "You've been invited as",
"expiresAt": "Invitation expires",
@@ -1582,7 +1501,6 @@
"strong": "Strong"
},
"createAccount": "Create Account",
- "creating": "Creating account...",
"success": "Account Created!",
"successMessage": "Your account has been created successfully. You can now log in with your credentials.",
"redirecting": "Redirecting to login in {{seconds}}...",
@@ -1597,23 +1515,14 @@
"usernameTooLong": "Username must be at most 50 characters",
"usernameInvalid": "Username can only contain letters, numbers, underscores, and hyphens",
"passwordRequired": "Password is required",
- "passwordTooShort": "Password must be at least 12 characters",
"passwordsDoNotMatch": "Passwords do not match",
"confirmPasswordRequired": "Please confirm your password",
- "usernameTaken": "This username is already taken",
- "emailTaken": "An account with this email already exists",
"genericError": "Failed to create account. Please try again."
}
},
"errors": {
- "notFound": "Not Found",
"galleryNotFound": "Gallery Not Found",
"galleryNotFoundMessage": "This gallery does not exist or has been removed.",
- "galleryArchived": "Gallery Archived",
- "galleryArchivedMessage": "This gallery has been archived and is no longer accessible. Please contact the event organizer if you need access to these photos.",
- "unauthorized": "Unauthorized",
- "forbidden": "Forbidden",
- "serverError": "Server Error",
"somethingWentWrong": "Something went wrong",
"tryAgainLater": "Please try again later",
"refreshPage": "Refresh Page",
@@ -1623,10 +1532,9 @@
"errorDetails": "Error Details",
"requiredFields": "Please fill in all required fields",
"enterTestEmail": "Please enter a test email address",
- "failedToCreateEvent": "Failed to create event",
"eventCreationFailed": "Failed to create event",
- "networkError": "Network error. Please check your connection and try again.",
- "sessionExpired": "Session expired. Please login again."
+ "noShareLink": "No share link available",
+ "copyFailed": "Failed to copy link"
},
"validation": {
"eventNameRequired": "Event name is required",
@@ -1637,14 +1545,15 @@
"passwordRequired": "Password is required",
"passwordMinLength": "Password must be at least 6 characters",
"passwordsDoNotMatch": "Passwords do not match",
- "passwordSecurityRequirements": "Password does not meet security requirements",
- "expirationRange": "Expiration must be between 1 and 365 days"
+ "expirationRange": "Expiration must be between 1 and 365 days",
+ "required": "This field is required",
+ "expirationRequired": "Expiration date is required.",
+ "eventDateRequired": "validation.eventDateRequired",
+ "passwordTooSimple": "Password cannot be just numbers. Consider using a date format like \"04.07.2025\""
},
"legal": {
"impressum": "Legal Notice",
- "datenschutz": "Privacy Policy",
- "termsOfService": "Terms of Service",
- "cookiePolicy": "Cookie Policy"
+ "datenschutz": "Privacy Policy"
},
"toast": {
"saveSuccess": "Changes saved successfully",
@@ -1653,9 +1562,6 @@
"deleteError": "Failed to delete",
"uploadSuccess": "Upload completed successfully",
"uploadError": "Upload failed",
- "loginSuccess": "Login successful",
- "loginError": "Login failed",
- "passwordChanged": "Password changed successfully",
"linkCopied": "Link copied to clipboard",
"eventCreated": "Event created successfully",
"eventUpdated": "Event updated successfully",
@@ -1663,14 +1569,10 @@
"settingsSaved": "Settings saved successfully",
"themeUpdated": "Theme updated successfully",
"brandingUpdated": "Branding updated successfully",
- "categoryAdded": "Category added successfully",
- "categoryDeleted": "Category deleted successfully",
"categoryUpdated": "Category updated successfully",
"emailConfigSaved": "Email configuration saved successfully",
- "testEmailSent": "Test email sent successfully",
- "pageUpdated": "Page updated successfully",
- "archiveRestored": "Archive restored successfully",
- "archiveDeleted": "Archive deleted permanently"
+ "brandingThemeMissing": "No branding theme has been saved yet.",
+ "brandingPaletteSynced": "Palette synced from Branding."
},
"email": {
"title": "Email Configuration",
@@ -1678,28 +1580,9 @@
"loadingSettings": "Loading email settings...",
"smtpConfiguration": "SMTP Configuration",
"smtpHost": "SMTP Host",
- "smtpHostHelp": "Your email server hostname",
- "smtpPort": "SMTP Port",
- "smtpPortHelp": "Usually 587 for TLS, 465 for SSL, 25 for unencrypted",
- "smtpSecure": "Use SSL/TLS",
- "smtpSecureHelp": "Enable for secure email transmission",
- "smtpUsername": "SMTP Username",
- "smtpUsernameHelp": "Your email account username",
- "smtpPassword": "SMTP Password",
- "smtpPasswordHelp": "Your email account password",
- "fromDetails": "From Details",
"fromEmail": "From Email",
- "fromEmailHelp": "Email address that appears as sender",
"fromName": "From Name",
- "fromNameHelp": "Name that appears as sender",
- "testConfiguration": "Test Configuration",
- "testEmail": "Test Email Address",
- "testEmailHelp": "Send a test email to verify settings",
- "sendTestEmail": "Send Test Email",
- "saveConfiguration": "Save Configuration",
"emailTemplates": "Email Templates",
- "templateVariables": "Available Variables",
- "previewTemplate": "Preview Template",
"smtpSettings": "SMTP Settings",
"testEmailSuccess": "Test email sent successfully",
"saveSmtpSettings": "Save SMTP Settings",
@@ -1717,23 +1600,18 @@
"emailBody": "Email Body",
"preview": "Preview",
"save": "Save",
- "saveChanges": "Save Changes",
"templates": "Templates",
- "variableHelp": "Use these variables in your template. They will be replaced with actual values when emails are sent.",
"port": "Port",
"security": "Security",
"username": "Username",
"password": "Password",
"enterPassword": "Enter password",
- "required": "required",
"ignoreSslErrors": "Ignore SSL/TLS certificate errors",
"ignoreSslWarning": "Warning: Disabling certificate verification makes the connection vulnerable to man-in-the-middle attacks. Only enable this if you trust the SMTP server and understand the security implications.",
"brandingTitle": "Email Branding",
"brandingDescription": "Customize the colors used in email templates. Changes apply to the header bar, buttons, links, and footer background.",
"primaryColor": "Primary Color",
- "primaryColorHint": "Used for header, buttons, and links",
"secondaryColor": "Footer Background",
- "secondaryColorHint": "Used for footer section background",
"saveEmailColors": "Save Email Colors",
"editor": {
"bold": "Bold",
@@ -1759,7 +1637,23 @@
"copiedFromLanguage": "Copied content from {{language}}",
"noTranslation": "No translation yet",
"noTranslationYet": "No translation exists for this language yet. Copy from an existing language to get started:",
- "copyFrom": "Copy from"
+ "copyFrom": "Copy from",
+ "syncedFromBranding": "Email colours synced from Branding. Click Save to apply.",
+ "syncFromBranding": "Sync from Branding",
+ "primaryColorHelp": "Header bar, H2 headings, button background, link colour. Maps to Branding → Accent (filled).",
+ "secondaryColorHelp": "Footer bar background. Maps to Branding → Surface.",
+ "bodyBgColor": "Page background",
+ "bodyBgColorHelp": "The wrapper around the email card — what the recipient sees behind the email itself. Maps to Branding → Background.",
+ "containerBgColor": "Email card",
+ "containerBgColorHelp": "The white card that holds the email content. Maps to Branding → Surface.",
+ "listBgColor": "Info panel",
+ "listBgColorHelp": "Background of the bulleted info panels inside the email body. Maps to Branding → Elevated.",
+ "bodyTextColor": "Body text",
+ "bodyTextColorHelp": "Paragraph and bold text colour. Maps to Branding → Primary text.",
+ "mutedTextColor": "Footer text",
+ "mutedTextColorHelp": "Footer text and copyright line. Maps to Branding → Secondary text.",
+ "buttonTextColor": "Button text",
+ "buttonTextColorHelp": "Text colour on filled buttons. Should contrast cleanly against the Primary colour. No Branding equivalent — usually white."
},
"cms": {
"title": "CMS Pages",
@@ -1773,17 +1667,22 @@
"pageTitle": "Page Title",
"pageContent": "Page Content",
"pageTitlePlaceholder": "Enter page title...",
- "saveChanges": "Save Changes",
"lastUpdated": "Last updated:",
- "impressum": "Legal Notice",
- "datenschutz": "Privacy Policy",
"pageUpdated": "Page updated successfully",
"useExternalUrl": "Use external URL",
"useExternalUrlHelp": "Redirect visitors to an external page instead of showing the internal content. The internal title and content stay saved as a fallback.",
"externalUrl": "External URL",
"externalUrlPlaceholder": "https://example.com/impressum",
"externalUrlInvalid": "Must be a valid https:// URL",
- "externalUrlActive": "External URL is active — internal content is preserved but not shown to visitors."
+ "externalUrlActive": "External URL is active — internal content is preserved but not shown to visitors.",
+ "logoUploaded": "Logo uploaded",
+ "logoCleared": "Logo cleared",
+ "pageLogo": "Page Logo",
+ "pageLogoHelp": "Optional. If set, used in place of the global branding logo on this page.",
+ "noLogo": "no override",
+ "replaceLogo": "Replace Logo",
+ "uploadLogo": "Upload Logo",
+ "clearLogo": "Use site default"
},
"eventTypes": {
"title": "Event Types",
@@ -1834,12 +1733,6 @@
}
},
"backup": {
- "external": {
- "warning": {
- "title": "External media excluded",
- "body": "This installation references photos from /external-media. These originals are excluded from backups. Thumbnails and database are still backed up."
- }
- },
"title": "Backup Management",
"subtitle": "Manage system backups, configure automated backups, and restore from previous backups.",
"tabs": {
@@ -1860,22 +1753,12 @@
"actions": {
"runBackupNow": "Run Backup Now",
"starting": "Starting...",
- "running": "Running...",
"testConnection": "Test Connection",
- "save": "Save Configuration",
"delete": "Delete",
"view": "View Details",
- "download": "Download",
- "refresh": "Refresh"
+ "download": "Download"
},
"dashboard": {
- "backupHealth": "Backup Health",
- "healthStatus": {
- "excellent": "Excellent",
- "good": "Good",
- "warning": "Warning",
- "critical": "Critical"
- },
"health": {
"title": "Backup Health"
},
@@ -1885,9 +1768,7 @@
"upToDate": "Backup is up to date",
"recent": "Backup is recent",
"gettingOld": "Backup is getting old",
- "outdated": "Backup is outdated",
- "failed": "Last backup failed",
- "old": "Backup is getting old"
+ "outdated": "Backup is outdated"
},
"stats": {
"totalBackups": "Total Backups",
@@ -1896,7 +1777,6 @@
"backupStatus": "Backup Status",
"last": "Last",
"files": "files",
- "minutes": "{{count}}m",
"active": "Active",
"inactive": "Inactive",
"noBackupsYet": "No backups yet"
@@ -1914,16 +1794,10 @@
},
"coverage": {
"title": "Backup Coverage",
- "database": "Database",
- "photos": "Photos",
- "archives": "Archives",
- "systemFiles": "System Files",
"included": "Included",
- "excluded": "Excluded",
- "optional": "Optional"
+ "excluded": "Excluded"
},
"storageDestination": "Storage Destination",
- "nextScheduledBackup": "Next Scheduled Backup",
"backupType": "{{type}} backup",
"noDestinationSet": "No destination set"
},
@@ -1950,42 +1824,24 @@
"destinationPathHelp": "Local directory path for storing backups",
"destinationPathPlaceholder": "/path/to/backup/directory",
"rsyncHost": "Remote Host",
- "rsyncHostHelp": "SSH hostname or IP address",
"rsyncHostPlaceholder": "backup.example.com",
"rsyncUser": "SSH User",
- "rsyncUserHelp": "Username for SSH connection",
"rsyncUserPlaceholder": "backup-user",
"rsyncPath": "Remote Path",
- "rsyncPathHelp": "Directory path on remote server",
"rsyncPathPlaceholder": "/home/backup/photo-sharing",
"rsyncSshKey": "SSH Private Key",
"rsyncSshKeyHelp": "SSH private key for authentication (optional)",
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
"s3Endpoint": "S3 Endpoint",
"s3EndpointHelp": "S3 API endpoint (e.g., s3.amazonaws.com)",
- "s3EndpointPlaceholder": "https://s3.amazonaws.com",
"s3Bucket": "Bucket Name",
- "s3BucketHelp": "S3 bucket for storing backups",
- "s3BucketPlaceholder": "my-backup-bucket",
"s3AccessKey": "Access Key ID",
- "s3AccessKeyHelp": "AWS/S3 access key ID",
- "s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXAMPLE",
"s3SecretKey": "Secret Access Key",
- "s3SecretKeyHelp": "AWS/S3 secret access key",
- "s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
- "s3Region": "Region",
- "s3RegionHelp": "S3 region (e.g., us-east-1)",
- "s3RegionPlaceholder": "us-east-1"
+ "s3Region": "Region"
},
"schedule": {
"title": "Backup Schedule",
"scheduleType": "Schedule Type",
- "scheduleOptions": {
- "hourly": "Every hour",
- "daily": "Daily",
- "weekly": "Weekly",
- "custom": "Custom cron expression"
- },
"options": {
"hourly": "Every hour",
"daily": "Daily",
@@ -2007,9 +1863,7 @@
"archives": "Archives",
"archivesHelp": "Archived event ZIP files",
"thumbnails": "Thumbnails",
- "thumbnailsHelp": "Generated thumbnail images (can be recreated)",
- "tempFiles": "Temporary Files",
- "tempFilesHelp": "Temporary upload and processing files"
+ "thumbnailsHelp": "Generated thumbnail images (can be recreated)"
},
"advancedOptions": {
"title": "Advanced Options",
@@ -2018,15 +1872,7 @@
"encryption": "Enable Encryption",
"encryptionHelp": "Encrypt backups for additional security",
"encryptionPassphrase": "Encryption Passphrase",
- "encryptionPassphraseHelp": "Strong passphrase for backup encryption",
- "confirmPassphrase": "Confirm Passphrase",
- "passphrasesDontMatch": "Passphrases don't match"
- },
- "validation": {
- "requiredFields": "Please fill in all required fields",
- "invalidCron": "Invalid cron expression",
- "connectionTestFailed": "Connection test failed",
- "connectionTestSuccess": "Connection test successful!"
+ "encryptionPassphraseHelp": "Strong passphrase for backup encryption"
},
"messages": {
"requiredFields": "Please fill in all required fields",
@@ -2039,23 +1885,6 @@
},
"history": {
"searchPlaceholder": "Search backups...",
- "allStatus": "All Status",
- "status": {
- "completed": "Completed",
- "failed": "Failed",
- "running": "Running",
- "partial": "Partial"
- },
- "deleteConfirm": "Are you sure you want to delete this backup from {{date}}?",
- "noBackups": "No backups found",
- "tableHeaders": {
- "date": "Date",
- "type": "Type",
- "status": "Status",
- "size": "Size",
- "duration": "Duration",
- "actions": "Actions"
- },
"columns": {
"status": "Status",
"dateTime": "Date & Time",
@@ -2073,35 +1902,10 @@
"errorDetails": "Error Details",
"manifest": "Manifest"
},
- "statistics": "Statistics",
- "errors": "Errors",
- "backupDetails": {
- "backupId": "Backup ID",
- "startTime": "Start Time",
- "endTime": "End Time",
- "destination": "Destination",
- "filesProcessed": "Files Processed",
- "totalSize": "Total Size",
- "compressionRatio": "Compression Ratio",
- "errorLog": "Error Log",
- "noErrors": "No errors occurred"
- },
"pagination": {
"showing": "Showing {{from}}-{{to}} of {{total}} backups",
"previous": "Previous",
"next": "Next"
- },
- "filter": {
- "allStatus": "All Status",
- "completed": "Completed",
- "failed": "Failed",
- "running": "Running",
- "partial": "Partial"
- },
- "noBackupsFound": "No backups found",
- "backupsWillAppear": "Backups will appear here once created",
- "messages": {
- "deleteSuccess": "Backup deleted successfully"
}
},
"restore": {
@@ -2214,12 +2018,6 @@
"current": "Current",
"statusDetails": "Status Details",
"restoreLogs": "Restore Logs",
- "steps": {
- "completed": "Completed",
- "running": "Running",
- "failed": "Failed",
- "pending": "Pending"
- },
"success": {
"title": "Restore Completed Successfully",
"message": "Your data has been restored. Please verify everything is working correctly."
@@ -2232,20 +2030,13 @@
"starting": "Starting...",
"validating": "Validating...",
"startNewRestore": "Start New Restore"
- },
- "messages": {
- "restoreStarted": "Restore started successfully"
}
},
"messages": {
"backupStarted": "Backup started successfully",
"backupFailed": "Failed to start backup",
"configUpdated": "Backup configuration updated",
- "configUpdateFailed": "Failed to update configuration",
- "backupDeleted": "Backup deleted successfully",
- "deleteFailed": "Failed to delete backup",
- "testEmailSent": "Test connection successful!",
- "testEmailFailed": "Connection test failed"
+ "configUpdateFailed": "Failed to update configuration"
}
},
"cssTemplates": {
@@ -2272,8 +2063,6 @@
"maintenance": {
"title": "System Maintenance",
"message": "We're currently performing scheduled maintenance to improve our service. We'll be back online shortly.",
- "expectedCompletion": "Expected completion time:",
- "checkBackLater": "Please check back later",
"urgentMatters": "For urgent matters, please contact"
},
"passwordChange": {
@@ -2352,18 +2141,7 @@
"pendingApproval": "Pending approval",
"noComments": "No comments yet. Be the first to comment!",
"rating": "Rating",
- "ratePhoto": "Rate this photo",
- "yourRating": "Your rating",
- "averageRating": "Average rating",
- "totalRatings": "ratings",
"likes": "Likes",
- "favorites": "Favorites",
- "likePhoto": "Like this photo",
- "favoritePhoto": "Add to favorites",
- "photoFeedback": "Photo Feedback",
- "hasFeedback": "Has feedback",
- "hasComments": "Has comments",
- "hasRating": "Has rating",
"settings": {
"title": "Guest Feedback Settings",
"enableFeedback": "Enable feedback",
@@ -2380,25 +2158,103 @@
"identityModeSimple": "Simple feedback",
"identityModeSimpleDesc": "Anonymous, device-based. All visitors on the same device share state.",
"identityModeGuest": "Per-guest selections",
- "identityModeGuestDesc": "Each visitor enters their name. Enables per-guest tracking and admin insights."
- }
+ "identityModeGuestDesc": "Each visitor enters their name. Enables per-guest tracking and admin insights.",
+ "privacyModeration": "Privacy & Moderation",
+ "requireInfo": "Require Name & Email",
+ "requireInfoDesc": "Guests must provide name and email to leave feedback",
+ "moderateComments": "Moderate Comments",
+ "moderateCommentsDesc": "Comments require approval before being visible",
+ "showToGuests": "Show Feedback to Guests",
+ "showToGuestsDesc": "Other guests can see ratings, likes, and approved comments",
+ "enableRateLimiting": "Enable Rate Limiting",
+ "rateLimitingDesc": "Prevent spam by limiting feedback frequency",
+ "timeWindow": "Time Window (minutes)",
+ "maxRequests": "Max Requests"
+ },
+ "settingsUpdated": "Feedback settings updated",
+ "settingsUpdateError": "Failed to update settings",
+ "moderated": "Feedback moderated",
+ "deleted": "Feedback deleted",
+ "exported": "Feedback exported",
+ "exportError": "Failed to export feedback",
+ "title": "Feedback Management",
+ "exportCSV": "Export CSV",
+ "exportJSON": "Export JSON",
+ "tabs": {
+ "settings": "Settings",
+ "feedback": "Feedback",
+ "analytics": "Analytics",
+ "moderation": "Moderation"
+ },
+ "allTypes": "All Types",
+ "types": {
+ "rating": "Ratings",
+ "like": "Likes",
+ "comment": "Comments",
+ "favorite": "Favorites"
+ },
+ "allStatuses": "All Statuses",
+ "status": {
+ "pending": "Pending",
+ "approved": "Approved",
+ "hidden": "Hidden"
+ },
+ "noFeedback": "No feedback found",
+ "approve": "Approve",
+ "hide": "Hide",
+ "unhide": "Unhide",
+ "confirmDelete": "Are you sure you want to delete this feedback?",
+ "avgRating": "Average Rating",
+ "totalRatings_one": "{{count}} ratings",
+ "totalRatings_other": "{{count}} ratings",
+ "totalLikes": "Total Likes",
+ "totalComments": "Total Comments",
+ "pendingModeration_one": "{{count}} pending",
+ "pendingModeration_other": "{{count}} pending",
+ "totalInteractions": "Total Interactions",
+ "topRated": "Top Rated Photos",
+ "recentComments": "Recent Comments",
+ "wordFilters": "Word Filters",
+ "wordFiltersDesc": "Manage blocked words for comment moderation",
+ "manageFilters": "Manage Word Filters",
+ "manage": "Manage Feedback",
+ "ratingSubmitted": "Rating submitted",
+ "ratingError": "Failed to submit rating",
+ "rateStar_one": "Rate {{count}} stars",
+ "rateStar_other": "Rate {{count}} stars",
+ "ratingsCount_one": "{{count}} ratings",
+ "ratingsCount_other": "{{count}} ratings",
+ "likeError": "Failed to update like",
+ "unlike": "Unlike",
+ "like": "Like",
+ "favoriteError": "Failed to update favorite",
+ "unfavorite": "Remove from favorites",
+ "favorite": "Add to favorites",
+ "invalidEmail": "Invalid email address",
+ "identityRequired": "Your Information Required",
+ "identityReason": "Please provide your name and email to submit {{type}}.",
+ "namePlaceholder": "Enter your name",
+ "emailPlaceholder": "Enter your email",
+ "submitFeedback": "Submit Feedback",
+ "moderationSuccess": "feedback.moderationSuccess",
+ "pendingModeration": "Pending Moderation",
+ "pending": "pending",
+ "noPendingComments": "No comments pending moderation",
+ "onPhoto": "On photo",
+ "showAll_one": "Show all {{count}} pending comments",
+ "showAll_other": "Show all {{count}} pending comments",
+ "viewAllFeedback": "View all feedback & settings"
},
"filter": {
"feedbackFilters": "Feedback Filters",
"clear": "Clear",
"rating": "Rating",
- "allPhotos": "All Photos",
- "anyRating": "Any Rating",
- "oneStarPlus": "1+ Stars",
- "twoStarsPlus": "2+ Stars",
- "threeStarsPlus": "3+ Stars",
- "fourStarsPlus": "4+ Stars",
- "fiveStarsOnly": "5 Stars Only",
"hasLikes": "Has likes",
"hasFavorites": "Has favorites",
"hasComments": "Has comments",
"showingPhotos": "Total photos",
- "withRatings": "With ratings"
+ "withRatings": "With ratings",
+ "combineWith": "Combine with"
},
"adminLogin": {
"title": "Admin Login",
@@ -2413,7 +2269,6 @@
"passwordRequired": "Password is required",
"passwordMinLength": "Password must be at least 6 characters",
"rememberMe": "Remember me",
- "forgotPassword": "Forgot password?",
"signIn": "Sign In",
"loginSuccess": "Login successful!",
"networkError": "Network error. Please check your connection and try again.",
@@ -2453,9 +2308,10 @@
"button": "Export",
"success": "Export downloaded successfully",
"error": "Export failed: ",
- "exportSelected": "Export {{count}} selected",
"exportFiltered": "Export filtered photos",
- "hint": "Select photos or apply filters to export"
+ "hint": "Select photos or apply filters to export",
+ "exportSelected_one": "Export {{count}} selected",
+ "exportSelected_other": "Export {{count}} selected"
},
"photoSort": {
"defaultSort": "Default Photo Sort",
@@ -2466,5 +2322,17 @@
"filenameAZ": "Filename (A-Z)",
"filenameZA": "Filename (Z-A)",
"dateTaken": "Date Taken"
+ },
+ "photos": {
+ "moveToCategory_one": "Move {{count}} photos to category",
+ "moveToCategory_other": "Move {{count}} photos to category",
+ "selectCategory": "Select category",
+ "uncategorized": "Uncategorized",
+ "movePhotos": "Move Photos",
+ "selectedCategory": "selected category",
+ "movedToCategory_one": "{{count}} photos moved to {{category}}",
+ "movedToCategory_other": "{{count}} photos moved to {{category}}",
+ "moveToCategoryFailed": "Failed to move photos to category",
+ "moveToCategory": "Move to Category"
}
}
From 86ee6c80aa1f26b2ad47775337ebed301193e662 Mon Sep 17 00:00:00 2001
From: PiR1
Date: Fri, 8 May 2026 17:38:22 +0200
Subject: [PATCH 016/169] feat(localization): add missing translations
---
frontend/src/i18n/locales/de.json | 1009 +++++++++++-------------
frontend/src/i18n/locales/fr.json | 1212 +++++++++++++++--------------
frontend/src/i18n/locales/nl.json | 1017 +++++++++++-------------
frontend/src/i18n/locales/pt.json | 1048 ++++++++++++-------------
frontend/src/i18n/locales/ru.json | 1081 ++++++++++++-------------
5 files changed, 2520 insertions(+), 2847 deletions(-)
diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json
index f45fcbbf..72f67150 100644
--- a/frontend/src/i18n/locales/de.json
+++ b/frontend/src/i18n/locales/de.json
@@ -81,8 +81,6 @@
"delete": "Löschen",
"edit": "Bearbeiten",
"add": "Hinzufügen",
- "search": "Suchen",
- "filter": "Filtern",
"sortBy": "Sortieren nach",
"yes": "Ja",
"no": "Nein",
@@ -91,35 +89,41 @@
"previous": "Zurück",
"close": "Schließen",
"logout": "Abmelden",
- "menu": "Menü",
"change": "Ändern",
"remove": "Entfernen",
"download": "Herunterladen",
"downloadAll": "Alle herunterladen",
- "uploading": "Wird hochgeladen...",
- "uploaded": "Hochgeladen",
"photo": "Foto",
"photos": "Fotos",
"video": "Video",
- "videos": "Videos",
"media": "Medien",
- "restore": "Wiederherstellen",
- "actions": "Aktionen",
- "refresh": "Aktualisieren",
- "preview": "Vorschau",
- "processing": "Wird verarbeitet...",
"upload": "Hochladen",
- "days": "Tage",
"customize": "Anpassen",
"hide": "Ausblenden",
"unknown": "Unbekannt",
"notSet": "Nicht festgelegt",
"of": "von",
- "up": "Nach oben",
- "select": "Auswählen",
"selected": "Ausgewählt",
"chunk": "Teil",
- "optional": "optional"
+ "optional": "optional",
+ "tryAgain": "Erneut versuchen",
+ "active": "Aktiv",
+ "inactive": "Inaktiv",
+ "create": "Erstellen",
+ "unknownDate": "Unbekanntes Datum",
+ "pageOf": "Seite {{current}} von {{total}}",
+ "collapse": "Einklappen",
+ "expand": "Ausklappen",
+ "submitting": "Wird übermittelt...",
+ "copy": "Kopieren",
+ "copied": "Kopiert!",
+ "applying": "Wird angewendet...",
+ "done": "Fertig",
+ "retry": "Wiederholen",
+ "characters": "Zeichen",
+ "saveChanges": "Änderungen speichern",
+ "resetChanges": "Änderungen zurücksetzen",
+ "dismiss": "Schließen"
},
"upload": {
"photoCategory": "Fotokategorie",
@@ -127,48 +131,34 @@
"eventSpecific": "(Veranstaltungsspezifisch)",
"clickToUpload": "Klicken zum Hochladen oder per Drag & Drop",
"fileRequirements": "JPEG, PNG oder WebP (max. 50MB pro Datei, {{limit}} Dateien pro Upload)",
- "fileRequirementsMedia": "JPEG-, PNG- oder WebP-Bilder sowie MP4/MOV/WEBM-Videos (max. 50MB pro Datei, {{limit}} Dateien pro Upload)",
- "unsupportedFiles": "Einige Dateien wurden übersprungen, da das Format nicht unterstützt wird (JPEG/PNG/WebP/MP4/MOV/WEBM verwenden).",
"selectedFiles": "Ausgewählte Dateien",
"uploading": "Wird hochgeladen...",
"transferring": "Übertragung",
"processing": "Fotos werden verarbeitet...",
"processingHint": "Dateien sind hochgeladen. PicPeak erstellt jetzt Thumbnails und liest Metadaten. Sie können diese Seite verlassen — die Verarbeitung läuft im Hintergrund weiter.",
"processingProgress": "{{complete}} von {{total}} fertig",
- "processingFailed": "{{count}} Foto(s) konnten nicht verarbeitet werden",
"retryFailed": "Fehlgeschlagene erneut versuchen",
"uploadComplete": "Upload abgeschlossen!",
- "uploadFailed": "Upload fehlgeschlagen",
"someFilesFailed": "Einige Dateien konnten nicht hochgeladen werden",
"replaceByName": "Vorhandene Fotos mit gleichem Namen ersetzen",
- "replacedFiles": "{{count}} Foto(s) ersetzt",
"uploadPhotos": "Fotos hochladen",
"uploadMedia": "Fotos & Videos hochladen",
- "importExternal": "Aus externem Ordner importieren",
- "externalImportInfo": "Alle Bilder aus dem ausgewählten Ordner werden importiert.",
- "selectExternalFolder": "Externen Ordner unter /external-media auswählen",
- "importFromSelectedFolder": "Ausgewählten Ordner importieren",
"maxFilesReached": "Maximal {{limit}} Dateien erlaubt",
"someFilesSkipped": "Nur {{allowed}} weitere Dateien erlaubt (Limit {{limit}})",
"tooManyFiles": "Maximal {{limit}} Dateien können gleichzeitig hochgeladen werden",
"limitInfo": "{{selected}} von {{limit}} Dateien ausgewählt ({{remaining}} verbleibend)",
"limitReached": "Upload-Limit erreicht ({{limit}} Dateien pro Vorgang)",
- "uploadingChunks": "Lade {{count}} Dateien in {{total}} Teilen hoch...",
- "mediaCategory": "Medienkategorie",
- "uploadAction": "{{count}} Dateien hochladen"
+ "replacedFiles_one": "{{count}} Foto ersetzt",
+ "replacedFiles_other": "{{count}} Fotos ersetzt",
+ "processingFailed_one": "{{count}} Foto konnte nicht verarbeitet werden",
+ "processingFailed_other": "{{count}} Fotos konnten nicht verarbeitet werden",
+ "uploadingChunks_one": "{{count}} Teil wird hochgeladen",
+ "uploadingChunks_other": "{{count}} Teile werden hochgeladen"
},
"navigation": {
"dashboard": "Dashboard",
"events": "Veranstaltungen",
- "archives": "Archive",
- "settings": "Einstellungen",
- "eventTypes": "Veranstaltungsarten",
- "branding": "Branding",
- "analytics": "Analytik",
- "emailSettings": "E-Mail-Einstellungen",
- "backup": "Backup & Wiederherstellung",
- "cmsPages": "CMS-Seiten",
- "users": "Benutzer"
+ "settings": "Einstellungen"
},
"eventTypes": {
"title": "Veranstaltungsarten",
@@ -239,28 +229,16 @@
"actions": {
"runBackupNow": "Backup jetzt starten",
"starting": "Starte...",
- "running": "Läuft...",
"testConnection": "Verbindung testen",
- "save": "Konfiguration speichern",
"delete": "Löschen",
"view": "Details anzeigen",
- "download": "Herunterladen",
- "refresh": "Aktualisieren"
+ "download": "Herunterladen"
},
"dashboard": {
- "backupHealth": "Backup-Status",
- "healthStatus": {
- "excellent": "Ausgezeichnet",
- "good": "Gut",
- "warning": "Warnung",
- "critical": "Kritisch"
- },
"healthMessages": {
"noBackups": "Keine Backups gefunden",
- "failed": "Letztes Backup fehlgeschlagen",
"upToDate": "Backup ist aktuell",
"recent": "Backup ist aktuell",
- "old": "Backup wird alt",
"outdated": "Backup ist veraltet",
"lastBackupFailed": "Letztes Backup fehlgeschlagen",
"gettingOld": "Backup wird alt"
@@ -272,7 +250,6 @@
"backupStatus": "Backup-Status",
"last": "Letztes",
"files": "Dateien",
- "minutes": "{{count}}m",
"active": "Aktiv",
"inactive": "Inaktiv",
"noBackupsYet": "Noch keine Backups"
@@ -285,17 +262,11 @@
"message": "Bitte konfigurieren Sie die Backup-Einstellungen im Konfiguration-Tab, bevor Sie Backups ausführen."
},
"coverage": {
- "database": "Datenbank",
- "photos": "Fotos",
- "archives": "Archive",
- "systemFiles": "Systemdateien",
"included": "Enthalten",
"excluded": "Ausgeschlossen",
- "optional": "Optional",
"title": "Backup-Abdeckung"
},
"storageDestination": "Speicherziel",
- "nextScheduledBackup": "Nächstes geplantes Backup",
"backupType": "{{type}} Backup",
"noDestinationSet": "Kein Ziel festgelegt",
"health": {
@@ -328,42 +299,24 @@
"destinationPathHelp": "Lokaler Verzeichnispfad für Backup-Speicherung",
"destinationPathPlaceholder": "/pfad/zum/backup/verzeichnis",
"rsyncHost": "Remote-Host",
- "rsyncHostHelp": "SSH-Hostname oder IP-Adresse",
"rsyncHostPlaceholder": "backup.beispiel.de",
"rsyncUser": "SSH-Benutzer",
- "rsyncUserHelp": "Benutzername für SSH-Verbindung",
"rsyncUserPlaceholder": "backup-benutzer",
"rsyncPath": "Remote-Pfad",
- "rsyncPathHelp": "Verzeichnispfad auf Remote-Server",
"rsyncPathPlaceholder": "/home/backup/foto-sharing",
"rsyncSshKey": "SSH Private Key",
"rsyncSshKeyHelp": "SSH Private Key für Authentifizierung (optional)",
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
"s3Endpoint": "S3-Endpunkt",
"s3EndpointHelp": "S3 API-Endpunkt (z.B. s3.amazonaws.com)",
- "s3EndpointPlaceholder": "https://s3.amazonaws.com",
"s3Bucket": "Bucket-Name",
- "s3BucketHelp": "S3-Bucket für Backup-Speicherung",
- "s3BucketPlaceholder": "mein-backup-bucket",
"s3AccessKey": "Zugriffsschlüssel-ID",
- "s3AccessKeyHelp": "AWS/S3 Zugriffsschlüssel-ID",
- "s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXAMPLE",
"s3SecretKey": "Geheimer Zugriffsschlüssel",
- "s3SecretKeyHelp": "AWS/S3 geheimer Zugriffsschlüssel",
- "s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
- "s3Region": "Region",
- "s3RegionHelp": "S3-Region (z.B. eu-central-1)",
- "s3RegionPlaceholder": "eu-central-1"
+ "s3Region": "Region"
},
"schedule": {
"title": "Backup-Zeitplan",
"scheduleType": "Zeitplan-Typ",
- "scheduleOptions": {
- "hourly": "Jede Stunde",
- "daily": "Täglich",
- "weekly": "Wöchentlich",
- "custom": "Benutzerdefinierter Cron-Ausdruck"
- },
"options": {
"hourly": "Jede Stunde",
"daily": "Täglich",
@@ -385,9 +338,7 @@
"archives": "Archive",
"archivesHelp": "Archivierte Veranstaltungs-ZIP-Dateien",
"thumbnails": "Miniaturbilder",
- "thumbnailsHelp": "Generierte Miniaturbilder (können neu erstellt werden)",
- "tempFiles": "Temporäre Dateien",
- "tempFilesHelp": "Temporäre Upload- und Verarbeitungsdateien"
+ "thumbnailsHelp": "Generierte Miniaturbilder (können neu erstellt werden)"
},
"advancedOptions": {
"title": "Erweiterte Optionen",
@@ -396,15 +347,7 @@
"encryption": "Verschlüsselung aktivieren",
"encryptionHelp": "Backups für zusätzliche Sicherheit verschlüsseln",
"encryptionPassphrase": "Verschlüsselungs-Passphrase",
- "encryptionPassphraseHelp": "Starke Passphrase für Backup-Verschlüsselung",
- "confirmPassphrase": "Passphrase bestätigen",
- "passphrasesDontMatch": "Passphrasen stimmen nicht überein"
- },
- "validation": {
- "requiredFields": "Bitte füllen Sie alle erforderlichen Felder aus",
- "invalidCron": "Ungültiger Cron-Ausdruck",
- "connectionTestFailed": "Verbindungstest fehlgeschlagen",
- "connectionTestSuccess": "Verbindungstest erfolgreich!"
+ "encryptionPassphraseHelp": "Starke Passphrase für Backup-Verschlüsselung"
},
"messages": {
"requiredFields": "Bitte füllen Sie alle erforderlichen Felder aus",
@@ -418,23 +361,6 @@
},
"history": {
"searchPlaceholder": "Backups suchen...",
- "allStatus": "Alle Status",
- "status": {
- "completed": "Abgeschlossen",
- "failed": "Fehlgeschlagen",
- "running": "Läuft",
- "partial": "Teilweise"
- },
- "deleteConfirm": "Sind Sie sicher, dass Sie dieses Backup vom {{date}} löschen möchten?",
- "noBackups": "Keine Backups gefunden",
- "tableHeaders": {
- "date": "Datum",
- "type": "Typ",
- "status": "Status",
- "size": "Größe",
- "duration": "Dauer",
- "actions": "Aktionen"
- },
"columns": {
"status": "Status",
"dateTime": "Datum & Zeit",
@@ -452,35 +378,10 @@
"errorDetails": "Fehlerdetails",
"manifest": "Manifest"
},
- "statistics": "Statistiken",
- "errors": "Fehler",
- "backupDetails": {
- "backupId": "Backup-ID",
- "startTime": "Startzeit",
- "endTime": "Endzeit",
- "destination": "Ziel",
- "filesProcessed": "Verarbeitete Dateien",
- "totalSize": "Gesamtgröße",
- "compressionRatio": "Komprimierungsverhältnis",
- "errorLog": "Fehlerprotokoll",
- "noErrors": "Keine Fehler aufgetreten"
- },
"pagination": {
"showing": "Zeige {{from}}-{{to}} von {{total}} Backups",
"previous": "Zurück",
"next": "Weiter"
- },
- "filter": {
- "allStatus": "Alle Status",
- "completed": "Abgeschlossen",
- "failed": "Fehlgeschlagen",
- "running": "Läuft",
- "partial": "Teilweise"
- },
- "noBackupsFound": "Keine Backups gefunden",
- "backupsWillAppear": "Backups werden hier angezeigt, sobald sie erstellt wurden",
- "messages": {
- "deleteSuccess": "Backup erfolgreich gelöscht"
}
},
"restore": {
@@ -593,12 +494,6 @@
"current": "Aktuell",
"statusDetails": "Status-Details",
"restoreLogs": "Wiederherstellungsprotokolle",
- "steps": {
- "completed": "Abgeschlossen",
- "running": "Läuft",
- "failed": "Fehlgeschlagen",
- "pending": "Ausstehend"
- },
"success": {
"title": "Wiederherstellung erfolgreich abgeschlossen",
"message": "Ihre Daten wurden wiederhergestellt. Bitte überprüfen Sie, ob alles korrekt funktioniert."
@@ -611,26 +506,13 @@
"starting": "Starte...",
"validating": "Validiere...",
"startNewRestore": "Neue Wiederherstellung starten"
- },
- "messages": {
- "restoreStarted": "Wiederherstellung erfolgreich gestartet"
}
},
"messages": {
"backupStarted": "Backup erfolgreich gestartet",
"backupFailed": "Backup konnte nicht gestartet werden",
"configUpdated": "Backup-Konfiguration aktualisiert",
- "configUpdateFailed": "Konfiguration konnte nicht aktualisiert werden",
- "backupDeleted": "Backup erfolgreich gelöscht",
- "deleteFailed": "Backup konnte nicht gelöscht werden",
- "testEmailSent": "Verbindungstest erfolgreich!",
- "testEmailFailed": "Verbindungstest fehlgeschlagen"
- },
- "external": {
- "warning": {
- "title": "Externe Medien ausgeschlossen",
- "body": "Diese Installation verweist auf Fotos aus /external-media. Diese Originale werden von Backups ausgeschlossen. Thumbnails und Datenbank werden weiterhin gesichert."
- }
+ "configUpdateFailed": "Konfiguration konnte nicht aktualisiert werden"
}
},
"archives": {
@@ -674,27 +556,18 @@
"deleteSuccess": "Archiv dauerhaft gelöscht"
},
"auth": {
- "login": "Anmelden",
"password": "Passwort",
"enterPassword": "Galerie-Passwort eingeben",
"passwordPlaceholder": "Geben Sie das Galerie-Passwort ein",
"invalidPassword": "Ungültiges Passwort",
"wrongPassword": "Falsches Passwort. Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut.",
"tooManyAttempts": "Zu viele fehlgeschlagene Anmeldeversuche. Bitte versuchen Sie es später erneut.",
- "sessionExpired": "Sitzung abgelaufen",
"pleaseEnterPassword": "Bitte geben Sie ein Passwort ein",
"passwordHint": "Das Passwort wurde vom Veranstalter bereitgestellt. Kontaktieren Sie ihn, wenn Sie es nicht haben."
},
"gallery": {
- "title": "Fotogalerie",
- "welcomeMessage": "Willkommensnachricht",
- "expiresOn": "Läuft ab am",
"expires": "Läuft ab",
"expired": "Abgelaufen",
- "daysRemaining": "{{days}} Tage verbleibend",
- "dayRemaining": "1 Tag verbleibend",
- "hoursRemaining": "{{hours}} Stunden verbleibend",
- "expiredMessage": "Diese Galerie ist am {{date}} abgelaufen",
"contactOrganizer": "Bitte kontaktieren Sie den Veranstalter, wenn Sie Zugriff auf diese Fotos benötigen.",
"searchPhotos": "Fotos nach Dateiname suchen...",
"sortByDate": "Nach Datum sortieren",
@@ -707,34 +580,21 @@
"favorited": "Favorisiert",
"rated": "Bewertet",
"commented": "Kommentiert",
- "shareGallery": "Galerie teilen",
"needHelp": "Hilfe benötigt? Kontaktieren Sie uns unter",
"noPhotosFound": "Keine Fotos gefunden",
"failedToLoad": "Fotos konnten nicht geladen werden",
"tryAgain": "Erneut versuchen",
"loading": "Galerie wird geladen...",
"expiredOn": "Diese Galerie ist am {{date}} abgelaufen.",
- "expiresIn": "Galerie läuft in {{count}} Tag ab",
- "expiresIn_plural": "Galerie läuft in {{count}} Tagen ab",
"downloadBefore": "Laden Sie Ihre Fotos herunter, bevor sie nicht mehr verfügbar sind.",
- "publicGalleryTitle": "Diese Galerie ist öffentlich zugänglich",
- "publicGallerySubtitle": "Fotos werden geladen...",
"viewGallery": "Galerie anzeigen",
"downloadAll": "Alle herunterladen",
- "downloading": "Lade {{count}} Foto herunter...",
- "downloading_plural": "Lade {{count}} Fotos herunter...",
- "downloadedPhotos": "{{count}} Foto heruntergeladen!",
- "downloadedPhotos_plural": "{{count}} Fotos heruntergeladen!",
"downloadError": "Einige Fotos konnten nicht heruntergeladen werden",
"selectPhotos": "Fotos auswählen",
"cancelSelection": "Auswahl abbrechen",
- "photosSelected": "{{count}} ausgewählt",
"selectAll": "Alle auswählen",
"deselectAll": "Auswahl aufheben",
- "downloadSelected": "{{count}} ausgewählte herunterladen",
"deleteSelected": "Ausgewählte löschen",
- "photosCount": "{{count}} Foto",
- "photosCount_plural": "{{count}} Fotos",
"searchByFilename": "Nach Dateinamen suchen...",
"uncategorized": "Ohne Kategorie",
"sortAscending": "Aufsteigend sortieren",
@@ -742,8 +602,6 @@
"remaining": "verbleibend",
"selectPhotosHint": "Tipp: Verwenden Sie Strg+Klick (Cmd+Klick auf Mac), um schnell mehrere Fotos auszuwählen",
"filters": "Filter",
- "openFilters": "Filter öffnen",
- "toggleSidebar": "Seitenleiste umschalten",
"toggleMenu": "Menü umschalten",
"allCategories": "Alle Kategorien",
"categories": "Kategorien",
@@ -775,15 +633,56 @@
"postComment": "Kommentar posten",
"anonymous": "Anonym"
},
- "filter": "Filter",
- "favorites": "Favoriten"
+ "favorites": "Favoriten",
+ "expiresIn_one": "",
+ "expiresIn_other": "",
+ "downloading_one": "",
+ "downloading_other": "",
+ "photosSelected_one": "",
+ "photosSelected_other": "",
+ "downloadSelected_one": "",
+ "downloadSelected_other": "",
+ "guestRecovery": {
+ "invalidEmail": "",
+ "codeSent": "",
+ "requestError": "",
+ "invalidCode": "",
+ "verifyError": "",
+ "back": "",
+ "title": "",
+ "emailStepDescription": "",
+ "codeStepDescription": "",
+ "emailLabel": "",
+ "sendCode": "",
+ "codeLabel": "",
+ "verifyCode": ""
+ },
+ "guestPrompt": {
+ "nameRequired": "",
+ "invalidEmail": "",
+ "emailRequired": "",
+ "error": "",
+ "title": "",
+ "description": "",
+ "nameLabel": "",
+ "namePlaceholder": "",
+ "emailLabelRequired": "",
+ "emailLabel": "",
+ "emailPlaceholder": "",
+ "submit": "",
+ "alreadyHere": ""
+ },
+ "footer": {
+ "forgetMeConfirm": "",
+ "forgetMe": ""
+ },
+ "photosCount_one": "",
+ "photosCount_other": "",
+ "poweredBy": ""
},
"categories": {
"title": "Fotokategorien",
- "global": "Globale Kategorien",
- "eventSpecific": "Veranstaltungsspezifische Kategorien",
"eventSpecificCategories": "Veranstaltungsspezifische Kategorien",
- "organizationInfo": "Organisieren Sie Ihre Fotos in Kategorien. Kategorien helfen Gästen, bestimmte Fototypen zu navigieren und zu finden.",
"noEventSpecificCategories": "Keine veranstaltungsspezifischen Kategorien. Globale Kategorien sind standardmäßig verfügbar.",
"globalCategoriesAlwaysAvailable": "Globale Kategorien (immer verfügbar):",
"deleteCategoryTitle": "Kategorie löschen",
@@ -793,10 +692,8 @@
"failedToDeleteCategory": "Fehler beim Löschen der Kategorie",
"addCategory": "Kategorie hinzufügen",
"categoryName": "Kategoriename",
- "noCategory": "Keine Kategorie",
"noCategoriesYet": "Noch keine Kategorien. Erstellen Sie Ihre erste Kategorie, um Fotos zu organisieren.",
"deleteConfirm": "Sind Sie sicher, dass Sie \"{{name}}\" löschen möchten?",
- "cannotDelete": "Kategorie mit Fotos kann nicht gelöscht werden. Bitte weisen Sie die Fotos zuerst neu zu.",
"setCoverPhoto": "Titelbild festlegen",
"removeCoverPhoto": "Titelbild entfernen",
"coverPhotoSet": "Titelbild erfolgreich festgelegt",
@@ -805,16 +702,12 @@
"categoryHeroHint": "Wenn kein Titelbild für eine Kategorie festgelegt ist, wird das Standard-Hero-Foto verwendet."
},
"events": {
- "noStatisticsAvailableYet": "Noch keine Statistiken verfügbar",
"totalPhotos": "Gesamtfotos",
"totalViews": "Gesamtaufrufe",
"totalDownloads": "Gesamte Downloads",
"uniqueVisitors": "Eindeutige Besucher",
- "addPlus": "Hinzufügen+",
"galleryTheme": "Galerie-Design",
- "customizeTheme": "Design anpassen",
"noThemeSet": "Kein Design konfiguriert",
- "customizingTheme": "Galerie-Design anpassen",
"customizingThemeFor": "Design für {{event}} anpassen",
"customCssTemplate": "Benutzerdefinierte CSS-Vorlage",
"customCssTemplateDesc": "Verwenden Sie eine CSS-Vorlage, um die Galerie mit einzigartigen visuellen Effekten zu gestalten.",
@@ -835,7 +728,6 @@
"expirationDate": "Ablaufdatum",
"active": "Aktiv",
"archived": "Archiviert",
- "photoCount": "{{count}} Fotos",
"totalSize": "Gesamtgröße",
"shareLink": "Freigabelink",
"copyLink": "Link kopieren",
@@ -848,10 +740,7 @@
"backToEvents": "Zurück zu Veranstaltungen",
"loadingEventDetails": "Veranstaltungsdetails werden geladen...",
"saveChanges": "Änderungen speichern",
- "eventExpired": "Diese Veranstaltung ist abgelaufen",
"eventExpiresIn": "Diese Veranstaltung läuft in {{days}} Tagen ab",
- "guestsNoAccess": "Gäste können nicht mehr auf die Galerie zugreifen. Erwägen Sie, diese Veranstaltung zu archivieren.",
- "warningEmailsSent": "Warn-E-Mails wurden an den Kunden gesendet.",
"warningEmailsHaveBeenSent": "Warn-E-Mails wurden an den Kunden gesendet.",
"extendSevenDays": "Um 7 Tage verlängern",
"overview": "Übersicht",
@@ -868,7 +757,6 @@
"externalFolderEmpty": "Keine Unterordner",
"clearSelection": "Löschen",
"welcomeMessage": "Willkommensnachricht",
- "noWelcomeMessage": "Keine Willkommensnachricht festgelegt",
"noWelcomeMessageSet": "Keine Willkommensnachricht festgelegt",
"created": "Erstellt",
"expires": "Läuft ab",
@@ -882,21 +770,12 @@
"managePhotos": "Fotos verwalten",
"actions": "Aktionen",
"archivingInfo": "Beim Archivieren wird eine ZIP-Datei aller Fotos erstellt und die Galerie aus dem öffentlichen Zugriff entfernt.",
- "statistics": "Statistiken",
- "views": "Aufrufe",
- "downloads": "Downloads",
- "noStatistics": "Noch keine Statistiken verfügbar",
- "archiveStatus": "Archivstatus",
"archivedOn": "Archiviert am",
"downloadArchive": "Archiv herunterladen",
"loadingPhotos": "Fotos werden geladen...",
"photoCategories": "Fotokategorien",
"organizeCategoriesInfo": "Organisieren Sie Ihre Fotos in Kategorien. Kategorien helfen Gästen, bestimmte Fototypen zu navigieren und zu finden.",
"categoriesTip": "Tipp: Kategorien sind spezifisch für jede Veranstaltung. Sie können auch globale Kategorien in den Einstellungen erstellen.",
- "contactInformation": "Kontaktinformationen",
- "hostEmailHelp": "Der Kunde erhält Benachrichtigungen zur Galerie-Erstellung und zum Ablauf",
- "adminEmailHelp": "Erhält Systembenachrichtigungen und Archivbestätigungen",
- "securityAccess": "Sicherheit & Zugriff",
"galleryPassword": "Galerie-Passwort",
"requirePasswordToggle": "Galerie mit Passwort schützen",
"requirePasswordToggleHelp": "Deaktivieren Sie diese Option, wenn die Galerie ohne Passwort geteilt werden soll. Jeder mit dem Link kann die Fotos ansehen.",
@@ -904,7 +783,6 @@
"passwordHelperText": "Sie können Datumsangaben wie \"04.07.2025\" oder beliebigen Text mit mindestens 6 Zeichen verwenden",
"passwordPlaceholder": "Sicheres Passwort eingeben",
"confirmPassword": "Passwort bestätigen",
- "showPasswords": "Passwörter anzeigen",
"newPasswordLabel": "Neues Galerie-Passwort",
"passwordReset": {
"title": "Galerie-Passwort zurücksetzen",
@@ -929,15 +807,10 @@
"errorMinLength": "Das Passwort muss mindestens 6 Zeichen lang sein",
"errorMismatch": "Passwörter stimmen nicht überein"
},
- "gallerySettings": "Galerie-Einstellungen",
- "colorTheme": "Farbthema",
"galleryExpiration": "Galerie-Ablauf",
- "galleryExpiresIn": "Galerie läuft ab in",
"daysAfterEvent": "Tage nach dem Veranstaltungsdatum",
"expiresOn": "Läuft ab am",
"themeAndStyle": "Design & Stil",
- "galleryWillExpireOn": "Galerie läuft ab am {{date}}",
- "expirationWarning": "Gäste erhalten 7 Tage vor Ablauf eine Warn-E-Mail.",
"noExpiration": "Kein Ablaufdatum",
"noExpirationHelp": "Diese Galerie bleibt aktiv, bis sie manuell archiviert wird.",
"photoCap": "Fotolimit",
@@ -949,11 +822,7 @@
"uploadCategory": "Upload-Kategorie",
"selectCategory": "Wählen Sie eine Kategorie für Benutzer-Uploads",
"uploadCategoryHelp": "Alle von Benutzern hochgeladenen Fotos werden dieser Kategorie hinzugefügt",
- "userUploadWarning": "Benutzer-Uploads werden moderiert und können jederzeit von Administratoren entfernt werden.",
"allowDownloads": "Foto-Downloads erlauben",
- "allowDownloadsHelp": "Gästen erlauben, Fotos aus dieser Galerie herunterzuladen",
- "downloadPermissions": "Download-Berechtigungen",
- "downloadsEnabled": "Downloads aktiviert",
"downloadsDisabled": "Downloads deaktiviert",
"downloadProtection": "Download-Schutz",
"disableRightClick": "Rechtsklick-Menü blockieren",
@@ -1002,45 +871,15 @@
"heroImageAnchorBottom": "Unten",
"heroPreview": "Hero-Vorschau",
"noPhotosAvailable": "Keine Fotos verfügbar",
- "processingRequest": "Ihre Anfrage wird verarbeitet...",
- "eventTypeWedding": "Hochzeit",
- "eventTypeBirthday": "Geburtstag",
- "eventTypeCorporate": "Geschäftlich",
- "eventTypeOther": "Andere",
- "days30": "30 Tage",
- "days60": "60 Tage",
- "days90": "90 Tage",
- "days365": "1 Jahr",
- "createNewEvent": "Neue Veranstaltung erstellen",
- "setupNewGallery": "Richten Sie eine neue Fotogalerie für Ihre Veranstaltung ein",
- "createNewEventSubtitle": "Richten Sie eine neue Fotogalerie für Ihre Veranstaltung ein",
"eventNamePlaceholder": "z.B. Max & Maria's Hochzeit",
- "welcomeMessageOptional": "Willkommensnachricht (Optional)",
"welcomeMessagePlaceholder": "Willkommen zu unserem besonderen Tag! Laden Sie diese Erinnerungen gerne herunter und teilen Sie sie...",
"hostEmailPlaceholder": "kunde@beispiel.de",
"adminEmailPlaceholder": "admin@beispiel.de",
"adminEmailPickFromAdmins": "Aus Admins wählen:",
"adminEmailCustom": "Eigene E-Mail",
- "securityAndAccess": "Sicherheit & Zugriff",
"accessAndSecurity": "Zugriff & Sicherheit",
"enterPassword": "Passwort eingeben",
"confirmPasswordPlaceholder": "Passwort bestätigen",
- "galleryExpiresOn": "Galerie läuft ab am {{date}}",
- "guestsWillReceiveWarning": "Gäste erhalten 7 Tage vor Ablauf eine Warn-E-Mail.",
- "types": {
- "wedding": "Hochzeit",
- "birthday": "Geburtstag",
- "corporate": "Geschäftlich",
- "other": "Andere"
- },
- "themes": {
- "default": "Standard",
- "oceanBlue": "Ozeanblau",
- "royalPurple": "Königliches Lila",
- "roseGold": "Roségold",
- "sunsetAmber": "Sonnenuntergang Bernstein"
- },
- "adminNotificationEmail": "Admin-Benachrichtigungs-E-Mail",
"inactive": "Inaktiv",
"expired": "Abgelaufen",
"draft": "Entwurf",
@@ -1048,51 +887,42 @@
"publishConfirm": "Dadurch wird die Galerie zugänglich und die Benachrichtigungs-E-Mail an den Kunden gesendet. Fortfahren?",
"publishSuccess": "Galerie veröffentlicht und Kunde benachrichtigt!",
"draftBanner": "Diese Galerie befindet sich im Entwurfsmodus. Laden Sie Ihre Fotos hoch und veröffentlichen Sie, wenn Sie bereit sind.",
- "daysLeft": "{{count}} Tag verbleibend",
- "daysLeft_plural": "{{count}} Tage verbleibend",
"subtitle": "Verwalten Sie Ihre Fotogalerien und Veranstaltungen",
- "loadingEvents": "Veranstaltungen werden geladen...",
"failedToLoadEvents": "Veranstaltungen konnten nicht geladen werden",
"tryAgain": "Erneut versuchen",
"eventExpiredMessage": "Diese Veranstaltung ist abgelaufen",
"guestsCannotAccessGallery": "Gäste können nicht mehr auf die Galerie zugreifen. Erwägen Sie, diese Veranstaltung zu archivieren.",
- "bulkArchiveSuccess": "{{count}} Veranstaltungen erfolgreich archiviert",
"bulkArchivePartial": "{{success}} Veranstaltungen archiviert, {{failed}} fehlgeschlagen",
"deleteSelected": "Ausgewählte löschen",
"bulkDelete": {
- "title": "{{count}} Veranstaltungen endgültig löschen?",
"warning": "Die ausgewählten Veranstaltungen, alle ihre Fotos, Archive und Audit-Logs werden endgültig gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",
+ "passwordLabel": "Zur Bestätigung Ihr Passwort erneut eingeben",
+ "passwordPlaceholder": "Ihr Admin-Passwort",
+ "passwordHelp": "Wir benötigen Ihr Passwort als Schutz vor versehentlichen Massenlöschungen.",
+ "incorrectPassword": "Falsches Passwort. Es wurden keine Veranstaltungen gelöscht.",
"confirmLabel": "Geben Sie {{literal}} ein, um zu bestätigen",
"confirmHelp": "Eine getippte Bestätigung verhindert versehentliche Löschungen und ist nicht von Browser-Autofill oder Passkey-Verknüpfungen betroffen.",
"submit": "{{count}} Veranstaltungen löschen",
"processing": "{{count}} Veranstaltungen werden gelöscht. Dies kann einige Minuten dauern — bitte schließen Sie dieses Fenster nicht.",
"successAll": "{{count}} Veranstaltungen endgültig gelöscht",
"successPartial": "{{success}} Veranstaltungen gelöscht, {{failed}} fehlgeschlagen",
- "errorGeneric": "Veranstaltungen konnten nicht gelöscht werden"
+ "errorGeneric": "Veranstaltungen konnten nicht gelöscht werden",
+ "successAll_one": "",
+ "successAll_other": "",
+ "title_one": "",
+ "title_other": "",
+ "processing_one": "",
+ "processing_other": "",
+ "submit_one": "",
+ "submit_other": ""
},
"searchEventsPlaceholder": "Veranstaltungen suchen...",
"all": "Alle",
"expiring": "Läuft ab",
- "activeFilter": "Aktiv",
- "archivedFilter": "Archiviert",
- "sortByName": "Nach Name",
- "sortByDate": "Nach Datum",
- "sortByExpiration": "Nach Ablauf",
"event": "Veranstaltung",
"type": "Typ",
"date": "Datum",
"status": "Status",
- "photosCount": "Fotos",
- "moreActions": "Weitere Aktionen",
- "copyLinkTooltip": "Link kopieren",
- "viewGalleryTooltip": "Galerie anzeigen",
- "uploadPhotosTooltip": "Fotos hochladen",
- "editTooltip": "Bearbeiten",
- "archiveTooltip": "Archivieren",
- "noEvents": "Keine Veranstaltungen gefunden",
- "noEventsDescription": "Erstellen Sie Ihre erste Veranstaltung, um zu beginnen.",
- "eventsSelected": "{{count}} Veranstaltung ausgewählt",
- "eventsSelected_plural": "{{count}} Veranstaltungen ausgewählt",
"publicAccess": "Öffentlicher Zugriff",
"passwordProtected": "Passwortgeschützt",
"newPasswordRequired": "Bitte legen Sie vor dem Aktivieren des Passwortschutzes ein Passwort fest.",
@@ -1101,9 +931,6 @@
"downloadArchiveAction": "Archiv herunterladen",
"deleteEvent": "Veranstaltung löschen",
"deleteEventConfirm": "Sind Sie sicher, dass Sie diese Veranstaltung löschen möchten?",
- "bulkArchive": "Archivieren",
- "confirmBulkArchive": "Sind Sie sicher, dass Sie {{count}} Veranstaltung(en) archivieren möchten?",
- "confirmBulkArchiveDescription": "Diese Aktion kann nicht rückgängig gemacht werden. Archivierte Veranstaltungen sind nicht mehr öffentlich zugänglich.",
"copy": "Kopieren",
"copied": "Kopiert!",
"rename": {
@@ -1113,8 +940,22 @@
"renamingFiles": "Dateien werden umbenannt...",
"complete": "Fertig!",
"failed": "Umbenennung fehlgeschlagen",
- "filesRenamed": "{{count}} Dateien aktualisiert",
- "confirm": "Veranstaltung umbenennen"
+ "confirm": "Veranstaltung umbenennen",
+ "success": "",
+ "filesRenamed_one": "",
+ "filesRenamed_other": "",
+ "newLink": "",
+ "currentName": "",
+ "newName": "",
+ "enterNewName": "",
+ "newUrl": "",
+ "checkingAvailability": "",
+ "resendEmail": "",
+ "emailTo": "",
+ "warningTitle": "",
+ "warning1": "",
+ "warning2": "",
+ "warning3": ""
},
"stats": {
"totalEvents": "Gesamtveranstaltungen",
@@ -1127,14 +968,31 @@
"noEventsFound": "Keine Veranstaltungen gefunden",
"downloadArchiveSoon": "Archiv-Download bald verfügbar",
"welcomeMessageLabel": "Willkommensnachricht",
- "createdOn": "Erstellt",
- "organizingPhotosInfo": "Organisieren Sie Ihre Fotos in Kategorien. Kategorien helfen Gästen, bestimmte Fototypen zu finden.",
"archiveStatusTitle": "Archivstatus",
"downloadingArchive": "{{name}}-Archiv wird heruntergeladen...",
"downloadStarted": "Download gestartet",
"failedToDownloadArchive": "Archiv-Download fehlgeschlagen",
- "statisticsNotAvailable": "Noch keine Statistiken verfügbar",
- "photoFilters": "Fotofilter"
+ "bulkArchiveSuccess_one": "",
+ "bulkArchiveSuccess_other": "",
+ "daysLeft_one": "",
+ "daysLeft_other": "",
+ "eventsSelected_one": "",
+ "eventsSelected_other": "",
+ "paginationLabel": "",
+ "filtered": "",
+ "pageOf": "",
+ "notFound": "",
+ "customerPhone": "",
+ "customerPhonePlaceholder": "",
+ "allowPresignedDownload": "",
+ "neverExpires": "",
+ "rightClickBlocked": "",
+ "devtoolsDetection": "",
+ "watermarked": "",
+ "importExternal": "",
+ "externalImportInfo": "",
+ "selectExternalFolder": "",
+ "importFromSelectedFolder": ""
},
"settings": {
"title": "Systemeinstellungen",
@@ -1146,9 +1004,7 @@
"siteUrl": "Website-URL",
"siteUrlHelp": "Wird für die Generierung von Galerielinks in E-Mails verwendet",
"defaultExpiration": "Standardablauf (Tage)",
- "defaultExpirationHelp": "Wie lange Galerien standardmäßig aktiv bleiben",
"maxFileSize": "Max. Dateigröße (MB)",
- "maxFileSizeHelp": "Maximale Größe pro hochgeladenem Foto",
"maxFilesPerUpload": "Max. Dateien pro Upload",
"maxFilesPerUploadHelp": "Maximale Anzahl an Fotos pro Upload-Vorgang (1-{{max}}).",
"allowedFileTypes": "Erlaubte Dateitypen",
@@ -1160,13 +1016,7 @@
"enableShortGalleryUrlsHelp": "Entfernt den Veranstaltungs-Slug aus neuen Freigabelinks und lässt bestehende Links weiterhin funktionieren.",
"maintenanceMode": "Wartungsmodus aktivieren",
"language": "Sprache",
- "defaultLanguage": "Standardsprache",
"defaultLanguageHelp": "Sprache, die Gästen vor der Anmeldung angezeigt wird",
- "defaultWelcomeMessage": "Standard-Begrüßungsnachricht",
- "welcomeMessage": "Begrüßungsnachricht",
- "welcomeMessagePlaceholder": "Geben Sie eine Standard-Begrüßungsnachricht ein, die in E-Mails zur Galerieerstellung enthalten sein wird",
- "welcomeMessageHelp": "Diese Nachricht wird in allen E-Mails zur Galerieerstellung enthalten sein, sofern sie beim Erstellen einer Veranstaltung nicht überschrieben wird",
- "saveSettings": "Allgemeine Einstellungen speichern",
"saveGeneralSettings": "Allgemeine Einstellungen speichern",
"dateTimeFormat": "Datums- & Zeitformat",
"dateFormat": "Datumsformat",
@@ -1184,7 +1034,6 @@
"accountSaveSuccess": "Kontodaten aktualisiert"
},
"publicSite": {
- "tabLabel": "Öffentliche Seite",
"badge": "Öffentliche Landingpage",
"title": "Öffentliche Landingpage",
"subtitle": "Veröffentlichen Sie eine anpassbare Landingpage für Gäste, die Ihre Domain besuchen.",
@@ -1212,8 +1061,6 @@
"htmlRequired": "Legen Sie HTML-Inhalt fest, bevor die öffentliche Seite aktiviert wird."
},
"storage": {
- "title": "Speicher",
- "overview": "Speicherübersicht",
"totalUsed": "Gesamt verwendet",
"archiveStorage": "Archivspeicher",
"storageLimit": "Speicherlimit",
@@ -1225,7 +1072,6 @@
"diskCapacityReported": "Festplattenkapazität (gemeldet)",
"diskAvailable": "Verfügbar",
"diskAvailableReported": "Verfügbar (gemeldet)",
- "diskFree": "Frei",
"diskFreeReported": "Frei (gemeldet)",
"diskMetricsUnavailable": "Speicherinformationen sind in Docker Desktop oder virtuellen Umgebungen nicht verfügbar.",
"applyRecommended": "Empfehlung nutzen",
@@ -1244,17 +1090,12 @@
"capacityRequiredForAvailable": "Geben Sie zuerst eine Gesamtkapazität an, bevor Sie verfügbaren Speicher setzen.",
"availableExceedsCapacity": "Der verfügbare Speicher darf die Gesamtkapazität nicht überschreiten.",
"storageUsage": "Speichernutzung",
- "storageByEvent": "Speicher nach Veranstaltung",
- "storageManagement": "Speicherverwaltung",
- "storageManagementHelp": "Erwägen Sie, alte Veranstaltungen zu archivieren oder zu löschen, um Speicherplatz freizugeben. Archivierte Veranstaltungen sind komprimiert und benötigen weniger Speicher als aktive Galerien.",
- "noEventsUsingStorage": "Keine Veranstaltungen verwenden Speicher",
"unlimited": "Unbegrenzt"
},
"security": {
"title": "Sicherheit",
"passwordSettings": "Passworteinstellungen",
"minPasswordLength": "Minimale Passwortlänge",
- "minPasswordLengthHelp": "Mindestanzahl von Zeichen für Galerie-Passwörter",
"passwordComplexity": "Passwort-Komplexität",
"passwordComplexityHelp": "Sicherheitsstufe für Galerie-Passwörter",
"complexitySimple": "Einfach (6+ Zeichen, beliebiger Text)",
@@ -1263,7 +1104,6 @@
"complexityVeryStrong": "Sehr stark (12+ Zeichen, alle Zeichentypen)",
"sessionAuth": "Sitzung & Authentifizierung",
"sessionTimeout": "Sitzungs-Timeout (Minuten)",
- "sessionTimeoutHelp": "Admin-Sitzungs-Timeout in Minuten",
"maxLoginAttempts": "Max. Anmeldeversuche",
"maxLoginAttemptsHelp": "Maximale fehlgeschlagene Anmeldeversuche pro IP vor Sperrung",
"attemptWindowMinutes": "Versuchsfenster (Minuten)",
@@ -1274,11 +1114,8 @@
"recaptchaSettings": "reCAPTCHA-Einstellungen",
"enableRecaptcha": "reCAPTCHA für Anmeldeformulare aktivieren",
"siteKey": "Site-Schlüssel",
- "siteKeyHelp": "Ihr reCAPTCHA v2 Site-Schlüssel (öffentlich)",
"secretKey": "Geheimer Schlüssel",
- "secretKeyHelp": "Ihr reCAPTCHA v2 Geheimschlüssel (privat halten)",
"recaptchaHelp": "Holen Sie sich Ihre reCAPTCHA-Schlüssel von",
- "saveSettings": "Sicherheitseinstellungen speichern",
"saveSecuritySettings": "Sicherheitseinstellungen speichern"
},
"events": {
@@ -1301,7 +1138,13 @@
"expirationWarning": "Galerien ohne Ablaufdatum bleiben aktiv, bis sie manuell archiviert werden",
"saveSettings": "Veranstaltungseinstellungen speichern",
"noteTitle": "Hinweis",
- "noteText": "Diese Einstellungen betreffen nur die Erstellung neuer Veranstaltungen. Bestehende Veranstaltungen sind nicht betroffen. Standardmäßig sind alle Felder erforderlich."
+ "noteText": "Diese Einstellungen betreffen nur die Erstellung neuer Veranstaltungen. Bestehende Veranstaltungen sind nicht betroffen. Standardmäßig sind alle Felder erforderlich.",
+ "defaultRequirePassword": "",
+ "defaultRequirePasswordHelp": "",
+ "showGalleryFilterBar": "",
+ "showGalleryFilterBarHelp": "",
+ "enablePhoneField": "",
+ "enablePhoneFieldHelp": ""
},
"imageSecurity": {
"title": "Bildschutz",
@@ -1370,11 +1213,6 @@
"format": "Format",
"fit": "Anpassungsmodus",
"fitHelp": "Wie Bilder an die Vorschaubildgröße angepasst werden. \"Füllen\" beschneidet das Bild, \"Einpassen\" passt es innerhalb der Grenzen an.",
- "fit_cover": "Füllen (zuschneiden)",
- "fit_contain": "Einpassen (innerhalb)",
- "fit_fill": "Strecken",
- "fit_inside": "Innen (verkleinern)",
- "fit_outside": "Außen (vergrößern)",
"regenerateTitle": "Vorschaubilder neu generieren",
"regenerateHelp": "Nach dem Ändern der Einstellungen können Sie alle vorhandenen Vorschaubilder neu generieren. Dies läuft im Hintergrund und kann bei großen Galerien eine Weile dauern.",
"regenerateButton": "Alle Vorschaubilder neu generieren",
@@ -1425,8 +1263,6 @@
"missingDimensions": "Fehlende Abmessungen",
"repairButton": "Abmessungen reparieren",
"repairing": "Repariere...",
- "alreadyRunning": "Reparatur läuft bereits",
- "started": "Reparatur von {{count}} Fotos gestartet",
"noneToRepair": "Alle Fotos haben bereits Abmessungen",
"resultSuccess": "Letzte Reparatur: {{success}} aktualisiert, {{failed}} fehlgeschlagen",
"description": "Fehlende Breite/Höhe für Fotos ergänzen, die vor der Dimensionsverfolgung hochgeladen wurden. Erforderlich für Masonry- und Mosaik-Layouts."
@@ -1444,11 +1280,12 @@
"sendTest": "Test-E-Mail senden",
"saved": "Einstellungen gespeichert",
"saveError": "Fehler beim Speichern der Einstellungen",
- "emailSent": "Benachrichtigungs-E-Mail an {{count}} Empfänger gesendet",
"emailFailed": "Fehler beim Senden der Benachrichtigung",
"checkSuccess": "Benachrichtigung für neue Version gesendet",
"checkNoAction": "Keine Benachrichtigung erforderlich: {{reason}}",
- "checkError": "Fehler beim Prüfen auf Updates"
+ "checkError": "Fehler beim Prüfen auf Updates",
+ "emailSent_one": "",
+ "emailSent_other": ""
},
"moderation": {
"title": "Moderation",
@@ -1505,11 +1342,57 @@
"deviceTypes": "Gerätetypen aus User-Agents",
"privacy": "Datenschutz",
"privacyText": "IP-Adressen werden aus Datenschutzgründen gehasht. Es werden keine persönlichen Daten gespeichert. Analysedaten werden 90 Tage aufbewahrt."
- }
+ },
+ "groups": {
+ "general": "",
+ "display": "",
+ "privacySecurity": "",
+ "integrations": "",
+ "system": ""
+ },
+ "apiTokens": {
+ "title": "",
+ "createError": "",
+ "revoked": "",
+ "subtitle": "",
+ "copyNow": "",
+ "copied": "",
+ "copyFailed": "",
+ "name": "",
+ "namePlaceholder": "",
+ "scopes": "",
+ "generate": "",
+ "scopeHint": "",
+ "existing": "",
+ "lastUsed": "",
+ "created": "",
+ "status": "",
+ "statusRevoked": "",
+ "statusExpired": "",
+ "statusActive": "",
+ "confirmRevoke": "",
+ "revoke": "",
+ "empty": ""
+ },
+ "webhooks": {
+ "title": "",
+ "subtitle": "",
+ "piiNotice": "",
+ "copyNow": "",
+ "name": "",
+ "url": "",
+ "events": "",
+ "filter": "",
+ "template": "",
+ "create": "",
+ "existing": "",
+ "empty": ""
+ },
+ "sectionLabel": "",
+ "navAriaLabel": ""
},
"branding": {
"title": "Branding & Themen",
- "titleFull": "Branding & Anpassung",
"subtitle": "Passen Sie das Aussehen Ihrer Galerien an",
"loadingBranding": "Branding-Einstellungen werden geladen...",
"themeAndStyle": "Theme & Stil",
@@ -1521,18 +1404,14 @@
"supportEmail": "Support-E-Mail",
"supportEmailHelp": "Kontakt-E-Mail für Gäste-Support",
"footerText": "Fußzeilentext",
- "footerTextHelp": "Wird am unteren Rand der Galerien angezeigt",
"logo": "Logo",
- "currentLogo": "Aktuelles Logo",
"uploadLogo": "Logo hochladen",
- "removeLogo": "Logo entfernen",
"logoHelp": "Empfohlene Größe: 200x60px, PNG oder JPEG",
"favicon": "Favicon",
"currentFavicon": "Aktuelles Favicon",
"uploadFavicon": "Favicon hochladen",
"removeFavicon": "Favicon entfernen",
"faviconHelp": "PNG- oder ICO-Format, empfohlene Größe: 32x32px",
- "watermark": "Wasserzeichen",
"watermarkSettings": "Wasserzeichen-Einstellungen",
"enableWatermarks": "Wasserzeichen aktivieren",
"watermarkHelp": "Fügen Sie Ihren Firmennamen als Wasserzeichen auf heruntergeladenen Fotos hinzu",
@@ -1549,11 +1428,7 @@
"watermarkSize": "Wasserzeichen-Größe",
"theme": "Theme",
"galleryTheme": "Galerie-Theme",
- "themeCustomization": "Theme-Anpassung",
- "selectPreset": "Vorgefertigtes Theme auswählen",
"colors": "Farben",
- "primaryColor": "Primärfarbe",
- "secondaryColor": "Sekundärfarbe",
"accentColor": "Akzentfarbe",
"backgroundColor": "Hintergrundfarbe",
"textColor": "Textfarbe",
@@ -1562,27 +1437,13 @@
"colorModeDark": "Dunkel",
"colorModeAuto": "Auto",
"colorModeHelp": "Auto folgt der Systemeinstellung des Besuchers.",
- "customCSS": "Benutzerdefiniertes CSS",
"preview": "Vorschau",
- "previewInNewTab": "Vorschau in neuem Tab",
- "reset": "Zurücksetzen",
"saveChanges": "Änderungen speichern",
"applyLivePreview": "Änderungen sofort anwenden (Live-Vorschau)",
"eventSpecificThemes": "Veranstaltungsspezifische Themen",
"eventThemesInfo": "Sie können diese globalen Theme-Einstellungen für einzelne Veranstaltungen beim Erstellen oder Bearbeiten überschreiben.",
"themePresets": "Theme-Vorlagen",
"galleryLayout": "Galerie-Layout",
- "layoutDescriptions": {
- "grid": "Klassisches Rasterlayout mit einheitlichen Fotogrößen",
- "masonry": "Pinterest-ähnliches Layout mit variablen Höhen",
- "carousel": "Vollbild-Diashow mit Navigation",
- "timeline": "Nach Datum organisierte Fotos",
- "hero": "Hervorgehobenes Bild mit Raster darunter",
- "mosaic": "Künstlerisches Layout mit gemischten Größen",
- "justified": "Zeilenbasiertes Layout mit Seitenverhältnis-Erhaltung",
- "gallery-premium": "Elegantes helles Theme mit Hero und Masonry (Beta)",
- "gallery-story": "Filmisches dunkles Theme mit Szenen-Abschnitten (Beta)"
- },
"layoutSettings": "Layout-Einstellungen",
"photoSpacing": "Foto-Abstand",
"spacing": {
@@ -1639,16 +1500,6 @@
"xl": "XL — Größte Fotos"
},
"thumbnailScaleHint": "Passt die Spaltenanzahl relativ zu den Basis-Rasterspalten an",
- "showHeroSection": "Hero-Bereich anzeigen",
- "showHeroSectionHint": "Zeigt ein hervorgehobenes Titelbild über der Galerie an",
- "heroHeight": "Hero-Bereich Höhe",
- "heroHeightOptions": {
- "small": "Klein (40-50%)",
- "medium": "Mittel (50-70%)",
- "large": "Groß (60-80%)"
- },
- "heroOverlayOpacity": "Hero-Overlay Deckkraft",
- "heroOverlayHint": "Verdunkelt das Titelbild für bessere Lesbarkeit",
"typographyAndStyle": "Typografie & Stil",
"bodyFont": "Fließtext-Schriftart",
"headingFont": "Überschriften-Schriftart",
@@ -1694,8 +1545,6 @@
},
"resetToDefault": "Auf Standard zurücksetzen",
"applyTheme": "Theme anwenden",
- "customTheme": "Benutzerdefiniertes Design",
- "customizeTheme": "Design anpassen",
"saveTheme": "Design speichern",
"previewLayout": "Vorschau-Layout",
"livePreview": "Live-Vorschau",
@@ -1713,9 +1562,6 @@
"logoMaxHeight": "Maximale Höhe (Pixel)",
"logoMaxHeightHelp": "Legen Sie eine benutzerdefinierte maximale Höhe für das Logo fest (20-200 Pixel)",
"logoPosition": "Logo-Position im Header",
- "positionLeft": "Links",
- "positionCenter": "Mitte",
- "positionRight": "Rechts",
"logoDisplayMode": "Anzeigemodus",
"logoOnly": "Nur Logo",
"textOnly": "Nur Firmenname",
@@ -1726,29 +1572,8 @@
"showLogoInHeroHelp": "Logo in Hero-Bereichen anzeigen (für Nicht-Raster-Layouts)",
"headerStyle": "Kopfzeilen-Stil",
"headerStyleDescription": "Wählen Sie, wie die Galerie-Kopfzeile aussieht. Der Kopfzeilen-Stil ist unabhängig vom Foto-Layout.",
- "headerStyleOptions": {
- "hero": "Hero-Bild",
- "standard": "Standard",
- "banner": "Banner",
- "minimal": "Minimal",
- "none": "Keine Kopfzeile"
- },
- "headerStyleDescriptions": {
- "hero": "Bild in voller Höhe mit Event-Info-Overlay",
- "standard": "Kompakte Kopfzeile mit Veranstaltungsdetails",
- "banner": "Standard-Kopfzeile mit farbigem Banner darüber",
- "minimal": "Kompakte Kopfzeile mit wesentlichen Infos",
- "none": "Kopfzeile komplett ausblenden"
- },
"heroDividerStyle": "Trennlinie-Stil",
"heroDividerDescription": "Wählen Sie, wie der Übergang zwischen dem Hero-Bild und dem Galerie-Inhalt aussieht.",
- "dividerOptions": {
- "wave": "Welle",
- "straight": "Gerade",
- "angle": "Winkel",
- "curve": "Kurve",
- "none": "Keine"
- },
"controlsStyle": "Steuerelemente-Stil",
"controlsStyleDescription": "Wählen Sie, wie Galerie-Filter und Steuerelemente angezeigt werden.",
"controlsStyleOptions": {
@@ -1762,15 +1587,43 @@
"controlsStyleHeroWarning": "Für Hero-Kopfzeilen wird die Seitenleiste empfohlen, um zu verhindern, dass Steuerelemente über dem Hero-Bild erscheinen.",
"betaThumbnailWarningTitle": "Niedrige Thumbnail-Auflösung erkannt",
"betaThumbnailWarningText": "Ihre Thumbnails sind derzeit {{width}}×{{height}}px. Beta-Themes zeigen Fotos in größeren Formaten an und benötigen mindestens {{recommended}}×{{recommended}}px für gute Qualität. Erhöhen Sie die Thumbnail-Abmessungen unter Einstellungen > Thumbnails und regenerieren Sie diese.",
- "betaThumbnailWarningLink": "Zu den Thumbnail-Einstellungen"
+ "betaThumbnailWarningLink": "Zu den Thumbnail-Einstellungen",
+ "logoSize": "",
+ "surfaceColor": "",
+ "elevatedColor": "",
+ "borderColor": "",
+ "mutedTextColor": "",
+ "accentDarkColor": "",
+ "syncFromBranding": "",
+ "forceColorMode": "",
+ "forceColorModeHelp": "",
+ "forceColorModeNone": "",
+ "forceColorModeDark": "",
+ "forceColorModeLight": "",
+ "colorGroupSurfaces": "",
+ "colorGroupSurfacesHelp": "",
+ "backgroundColorHelp": "",
+ "surfaceColorHelp": "",
+ "elevatedColorHelp": "",
+ "borderColorHelp": "",
+ "colorGroupText": "",
+ "colorGroupTextHelp": "",
+ "textColorHelp": "",
+ "mutedTextColorHelp": "",
+ "colorGroupAccent": "",
+ "colorGroupAccentHelp": "",
+ "accentColorHelp": "",
+ "accentDarkColorHelp": "",
+ "cssTemplate": "",
+ "cssTemplateDescription": "",
+ "noTemplate": "",
+ "noTemplateDescription": "",
+ "templateSlot": "",
+ "eventCustomCSS": ""
},
"admin": {
"title": "Admin-Panel",
- "welcome": "Willkommen zurück, {{name}}",
"recentActivity": "Letzte Aktivitäten",
- "systemStatus": "Systemstatus",
- "totalEvents": "Gesamte Veranstaltungen",
- "activeGalleries": "Aktive Galerien",
"storageUsed": "Speicher verwendet",
"totalPhotos": "Gesamte Fotos",
"storagePercent": "{{percent}}% des Limits {{limit}}",
@@ -1782,9 +1635,6 @@
"archivedEvents": "Archivierte Veranstaltungen",
"systemHealth": "Systemstatus",
"health": {
- "healthy": "Gesund",
- "warning": "Warnung",
- "error": "Fehler",
"checking": "Prüfe..."
},
"updates": {
@@ -1797,9 +1647,7 @@
"beta": "BETA",
"viewReleaseNotes": "Versionshinweise anzeigen",
"updateAvailableShort": "v{{version}} verfügbar",
- "checkForUpdates": "Nach Updates suchen",
"upToDate": "Alles aktuell",
- "lastChecked": "Zuletzt geprüft: {{time}}",
"updateNow": "Jetzt aktualisieren",
"updateDialog": {
"title": "PicPeak aktualisieren",
@@ -1813,8 +1661,6 @@
}
},
"notifications": "Benachrichtigungen",
- "viewAllNotifications": "Alle Benachrichtigungen anzeigen",
- "noNotifications": "Keine neuen Benachrichtigungen",
"markAllRead": "Alle als gelesen markieren",
"clearAll": "Alle löschen",
"close": "Schließen",
@@ -1824,16 +1670,13 @@
"eventArchived": "Event \"{{eventName}}\" wurde archiviert",
"eventUpdated": "Event \"{{eventName}}\" wurde aktualisiert",
"eventDeleted": "Event \"{{eventName}}\" wurde gelöscht",
- "photosUploaded": "{{count}} Fotos zu \"{{eventName}}\" hochgeladen",
"photoDeleted": "Foto aus \"{{eventName}}\" gelöscht",
- "photosBulkDeleted": "{{count}} Fotos aus \"{{eventName}}\" gelöscht",
"eventExpiring": "Event \"{{eventName}}\" läuft in {{days}} Tagen ab",
"eventExpired": "Event \"{{eventName}}\" ist abgelaufen",
"passwordChanged": "Passwort geändert von {{actorName}}",
"passwordReset": "Passwort zurückgesetzt für \"{{eventName}}\"",
"settingsUpdated": "{{type}}-Einstellungen aktualisiert",
"emailTemplateUpdated": "E-Mail-Vorlage \"{{template}}\" aktualisiert",
- "bulkDownload": "{{count}} Fotos von \"{{eventName}}\" heruntergeladen",
"storageWarning": "Speichernutzung bei {{percentage}}%",
"adminLogout": "Admin {{actorName}} hat sich abgemeldet",
"categoryCreated": "Kategorie \"{{name}}\" für \"{{eventName}}\" erstellt",
@@ -1850,27 +1693,20 @@
"archiveDeleted": "Archiv für \"{{eventName}}\" gelöscht",
"archiveRestored": "Archiv für \"{{eventName}}\" wiederhergestellt",
"systemActivity": "Systemaktivität: {{type}}",
- "adminProfileUpdated": "Admin-Profil aktualisiert von {{actorName}}"
+ "adminProfileUpdated": "Admin-Profil aktualisiert von {{actorName}}",
+ "photosUploaded_one": "",
+ "photosUploaded_other": "",
+ "photosBulkDeleted_one": "",
+ "photosBulkDeleted_other": "",
+ "bulkDownload_one": "",
+ "bulkDownload_other": ""
},
"notificationToasts": {
"markedAllRead": "Alle Benachrichtigungen als gelesen markiert",
- "clearedAll": "{{count}} Benachrichtigungen gelöscht",
- "profileUpdated": "Admin-Profil aktualisiert"
+ "clearedAll_one": "",
+ "clearedAll_other": ""
},
- "markAsRead": "Als gelesen markieren",
- "markAllAsRead": "Alle als gelesen markieren",
- "notificationSettings": "Benachrichtigungseinstellungen",
"changePassword": "Passwort ändern",
- "accountSettings": {
- "title": "Admin-Konto",
- "description": "Aktualisiere die Zugangsdaten für die PicPeak-Administration.",
- "username": "Benutzername",
- "usernamePlaceholder": "Admin",
- "email": "E-Mail",
- "emailPlaceholder": "admin@example.com",
- "updateButton": "Profil aktualisieren"
- },
- "profileUpdateError": "Admin-Profil konnte nicht aktualisiert werden. Bitte versuche es erneut.",
"loadingDashboard": "Dashboard wird geladen...",
"activeEvents": "Aktive Veranstaltungen",
"expiringSoon": "Demnächst ablaufend",
@@ -1881,110 +1717,88 @@
"dashboardSubtitle": "Willkommen zurück! Hier ist, was mit Ihren Galerien passiert.",
"eventsExpiringSoon": "Demnächst ablaufende Veranstaltungen",
"noEventsExpiring": "Keine Veranstaltungen laufen in den nächsten 7 Tagen ab",
- "daysLeft": "{{count}} Tag verbleibend",
- "daysLeft_plural": "{{count}} Tage verbleibend",
- "viewAllExpiringEvents": "Alle {{count}} ablaufenden Veranstaltungen anzeigen",
"noRecentActivity": "Keine aktuellen Aktivitäten",
- "viewAllActivity": "Alle Aktivitäten anzeigen",
- "quickActions": "Schnellaktionen",
- "viewArchives": "Archive anzeigen",
- "analytics": "Analytik",
- "activities": {
- "event_created": "Neue Veranstaltung erstellt: {{eventName}}",
- "photos_uploaded": "{{count}} Fotos hochgeladen zu {{eventName}}",
- "event_archived": "Veranstaltung archiviert: {{eventName}}",
- "archive_restored": "Archiv wiederhergestellt: {{eventName}}",
- "archive_deleted": "Archiv gelöscht: {{eventName}}",
- "archive_downloaded": "Archiv heruntergeladen: {{eventName}}",
- "email_config_updated": "E-Mail-Konfiguration aktualisiert",
- "email_template_updated": "E-Mail-Vorlage aktualisiert: {{template}}",
- "branding_updated": "Branding-Einstellungen aktualisiert",
- "theme_updated": "Theme-Einstellungen aktualisiert",
- "bulk_download": "{{count}} Fotos heruntergeladen von {{eventName}}",
- "gallery_password_entry": "Passwort eingegeben für {{eventName}}",
- "expiration_warning_viewed": "Ablaufwarnung angesehen für {{eventName}}",
- "feedback_settings_updated": "Feedback-Einstellungen aktualisiert",
- "feedback_moderated": "Feedback moderiert",
- "feedback_deleted": "Feedback gelöscht",
- "photo_like": "Foto mit Gefällt mir markiert in {{eventName}}",
- "photo_favorite": "Foto favorisiert in {{eventName}}",
- "photo_rating": "Foto bewertet in {{eventName}}",
- "photo_comment": "Foto kommentiert in {{eventName}}",
- "guest_feedback_like": "Gast hat ein Foto mit Gefällt mir markiert in {{eventName}}",
- "guest_feedback_favorite": "Gast hat ein Foto favorisiert in {{eventName}}",
- "guest_feedback_rating": "Gast hat ein Foto bewertet in {{eventName}}",
- "guest_feedback_comment": "Gast hat ein Foto kommentiert in {{eventName}}",
- "word_filter_added": "Wortfilter hinzugefügt",
- "external_import_completed": "Externer Medienimport abgeschlossen ({{imported}} importiert, {{skipped}} übersprungen)",
- "bulk_archive_completed": "Sammelarchivierung abgeschlossen",
- "event_activated": "Veranstaltung aktiviert: {{eventName}}",
- "event_deactivated": "Veranstaltung deaktiviert: {{eventName}}",
- "photo_deleted": "Foto gelöscht aus {{eventName}}",
- "photos_bulk_deleted": "{{count}} Fotos gelöscht aus {{eventName}}",
- "settings_updated": "Einstellungen aktualisiert",
- "event_updated": "Veranstaltung aktualisiert: {{eventName}}",
- "event_renamed": "Veranstaltung umbenannt: {{eventName}}",
- "event_deleted": "Veranstaltung gelöscht: {{eventName}}",
- "password_changed": "Passwort geändert",
- "email_resent": "Erstellungs-E-Mail erneut gesendet für: {{eventName}}",
- "category_created": "Kategorie erstellt: {{categoryName}}",
- "category_updated": "Kategorie aktualisiert: {{categoryName}}",
- "category_deleted": "Kategorie gelöscht: {{categoryName}}",
- "general_settings_updated": "Allgemeine Einstellungen aktualisiert",
- "favicon_uploaded": "Favicon hochgeladen",
- "analytics_settings_updated": "Analytik-Einstellungen aktualisiert",
- "cms_page_updated": "CMS-Seite aktualisiert: {{page}}",
- "security_settings_updated": "Sicherheitseinstellungen aktualisiert",
- "password_reset": "Passwort zurückgesetzt für: {{eventName}}",
- "admin_logout": "Admin {{actorName}} abgemeldet",
- "system_activity": "Systemaktivität: {{type}}",
- "unknown": "Unbekannte Aktivität"
- },
- "userManagement": "Benutzerverwaltung",
- "inviteUser": "Benutzer einladen",
- "pendingInvitations": "Ausstehende Einladungen",
- "roles": {
- "super_admin": "Super-Admin",
- "admin": "Admin",
- "editor": "Redakteur",
- "viewer": "Betrachter"
- },
- "userStatus": {
- "active": "Aktiv",
- "inactive": "Inaktiv"
- },
- "inviteForm": {
- "email": "E-Mail-Adresse",
- "role": "Rolle",
- "send": "Einladung senden"
- },
- "acceptInvite": {
- "title": "Admin-Einladung annehmen",
- "username": "Benutzernamen wählen",
- "password": "Passwort erstellen",
- "submit": "Konto erstellen"
- },
"photos": {
"hidden": "Versteckt",
"hideSelected": "Ausblenden",
"showSelected": "Einblenden",
"hiddenSuccess": "Fotos für Gäste ausgeblendet",
- "visibleSuccess": "Fotos jetzt für Gäste sichtbar"
+ "visibleSuccess": "Fotos jetzt für Gäste sichtbar",
+ "processingStatus": "",
+ "processingFailed": "",
+ "retryQueued": ""
+ },
+ "events": {
+ "tabs": {
+ "guests": ""
+ }
+ },
+ "daysLeft_one": "",
+ "daysLeft_other": "",
+ "viewAllExpiringEvents_one": "",
+ "viewAllExpiringEvents_other": "",
+ "guests": {
+ "loading": "",
+ "aggregate": {
+ "empty": "",
+ "description": ""
+ },
+ "inviteCreated": "",
+ "inviteCreateError": "",
+ "inviteRevoked": "",
+ "inviteRevokeError": "",
+ "invitesTitle": "",
+ "createInvite": "",
+ "inviteName": "",
+ "inviteEmail": "",
+ "generateInvite": "",
+ "existingInvites": "",
+ "noInvites": "",
+ "copyLink": "",
+ "revokeInvite": "",
+ "deletedToast": "",
+ "deletedError": "",
+ "mergedToast": "",
+ "mergedError": "",
+ "forgetGuestConfirm": "",
+ "exportError": "",
+ "mergeSelectAtLeastTwo": "",
+ "mergeConfirm_one": "",
+ "mergeConfirm_other": "",
+ "backToList": "",
+ "title": "",
+ "mergeSelected_one": "",
+ "mergeSelected_other": "",
+ "mergeNow": "",
+ "aggregateView": "",
+ "mergeMode": "",
+ "exportAll": "",
+ "empty": "",
+ "columns": {
+ "name": "",
+ "email": "",
+ "likes": "",
+ "favorites": "",
+ "comments": "",
+ "ratings": "",
+ "lastSeen": ""
+ },
+ "view": "",
+ "export": "",
+ "forgetGuest": "",
+ "loadingDetail": "",
+ "detail": {
+ "noComments": "",
+ "empty": ""
+ }
}
},
- "permissions": {
- "insufficient": "Sie haben keine Berechtigung, diese Aktion auszuführen",
- "viewOnly": "Nur Ansicht"
- },
"acceptInvitation": {
"title": "Einladung annehmen",
"subtitle": "Erstellen Sie Ihr Administratorkonto",
"validating": "Einladung wird überprüft...",
"invalidToken": "Ungültige Einladung",
"invalidTokenMessage": "Dieser Einladungslink ist ungültig oder abgelaufen. Bitte kontaktieren Sie Ihren Administrator für eine neue Einladung.",
- "expiredToken": "Einladung abgelaufen",
- "expiredTokenMessage": "Diese Einladung ist abgelaufen. Bitte fordern Sie eine neue Einladung von Ihrem Administrator an.",
- "alreadyUsed": "Einladung bereits verwendet",
"alreadyUsedMessage": "Diese Einladung wurde bereits verwendet, um ein Konto zu erstellen.",
"invitedAs": "Sie wurden eingeladen als",
"expiresAt": "Einladung läuft ab",
@@ -2011,7 +1825,6 @@
"strong": "Stark"
},
"createAccount": "Konto erstellen",
- "creating": "Konto wird erstellt...",
"success": "Konto erstellt!",
"successMessage": "Ihr Konto wurde erfolgreich erstellt. Sie können sich jetzt mit Ihren Zugangsdaten anmelden.",
"redirecting": "Weiterleitung zur Anmeldung in {{seconds}}...",
@@ -2026,23 +1839,14 @@
"usernameTooLong": "Benutzername darf maximal 50 Zeichen lang sein",
"usernameInvalid": "Benutzername darf nur Buchstaben, Zahlen, Unterstriche und Bindestriche enthalten",
"passwordRequired": "Passwort ist erforderlich",
- "passwordTooShort": "Passwort muss mindestens 12 Zeichen lang sein",
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
"confirmPasswordRequired": "Bitte bestätigen Sie Ihr Passwort",
- "usernameTaken": "Dieser Benutzername ist bereits vergeben",
- "emailTaken": "Ein Konto mit dieser E-Mail-Adresse existiert bereits",
"genericError": "Konto konnte nicht erstellt werden. Bitte versuchen Sie es erneut."
}
},
"errors": {
- "notFound": "Nicht gefunden",
"galleryNotFound": "Galerie nicht gefunden",
"galleryNotFoundMessage": "Diese Galerie existiert nicht oder wurde entfernt.",
- "galleryArchived": "Galerie archiviert",
- "galleryArchivedMessage": "Diese Galerie wurde archiviert und ist nicht mehr zugänglich. Bitte kontaktieren Sie den Veranstalter, wenn Sie Zugriff auf diese Fotos benötigen.",
- "unauthorized": "Nicht autorisiert",
- "forbidden": "Verboten",
- "serverError": "Serverfehler",
"somethingWentWrong": "Etwas ist schiefgelaufen",
"tryAgainLater": "Bitte versuchen Sie es später erneut",
"refreshPage": "Seite aktualisieren",
@@ -2052,16 +1856,13 @@
"errorDetails": "Fehlerdetails",
"requiredFields": "Bitte füllen Sie alle Pflichtfelder aus",
"enterTestEmail": "Bitte geben Sie eine Test-E-Mail-Adresse ein",
- "failedToCreateEvent": "Veranstaltung konnte nicht erstellt werden",
- "networkError": "Netzwerkfehler. Bitte überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
- "sessionExpired": "Sitzung abgelaufen. Bitte melden Sie sich erneut an.",
- "eventCreationFailed": "Veranstaltung konnte nicht erstellt werden"
+ "eventCreationFailed": "Veranstaltung konnte nicht erstellt werden",
+ "noShareLink": "",
+ "copyFailed": ""
},
"legal": {
"impressum": "Impressum",
- "datenschutz": "Datenschutzerklärung",
- "termsOfService": "Nutzungsbedingungen",
- "cookiePolicy": "Cookie-Richtlinie"
+ "datenschutz": "Datenschutzerklärung"
},
"toast": {
"saveSuccess": "Änderungen erfolgreich gespeichert",
@@ -2070,9 +1871,6 @@
"deleteError": "Fehler beim Löschen",
"uploadSuccess": "Upload erfolgreich abgeschlossen",
"uploadError": "Upload fehlgeschlagen",
- "loginSuccess": "Anmeldung erfolgreich",
- "loginError": "Anmeldung fehlgeschlagen",
- "passwordChanged": "Passwort erfolgreich geändert",
"linkCopied": "Link in Zwischenablage kopiert",
"eventCreated": "Veranstaltung erfolgreich erstellt",
"eventUpdated": "Veranstaltung erfolgreich aktualisiert",
@@ -2080,18 +1878,13 @@
"settingsSaved": "Einstellungen erfolgreich gespeichert",
"themeUpdated": "Theme erfolgreich aktualisiert",
"brandingUpdated": "Branding erfolgreich aktualisiert",
- "categoryAdded": "Kategorie erfolgreich hinzugefügt",
- "categoryDeleted": "Kategorie erfolgreich gelöscht",
"categoryUpdated": "Kategorie erfolgreich aktualisiert",
"emailConfigSaved": "E-Mail-Konfiguration erfolgreich gespeichert",
- "testEmailSent": "Test-E-Mail erfolgreich gesendet",
- "pageUpdated": "Seite erfolgreich aktualisiert",
- "archiveRestored": "Archiv erfolgreich wiederhergestellt",
- "archiveDeleted": "Archiv dauerhaft gelöscht"
+ "brandingThemeMissing": "",
+ "brandingPaletteSynced": ""
},
"analytics": {
"title": "Analytics Dashboard",
- "titleSimple": "Analytik",
"subtitle": "Galerie-Performance und Besucherengagement verfolgen",
"detailedSubtitle": "Detaillierte Analysen mit Umami",
"loadingAnalytics": "Analytik wird geladen...",
@@ -2119,9 +1912,7 @@
"totalPhotos": "Gesamte Fotos",
"activeEvents": "Aktive Veranstaltungen",
"notConfigured": "Umami Analytics nicht konfiguriert",
- "configureInstructions": "Um echte Analysedaten zu sehen, konfigurieren Sie Umami in Ihren Umgebungsvariablen und Admin-Panel-Einstellungen.",
- "noData": "Keine Daten verfügbar",
- "percentChange": "{{percent}}% gegenüber letztem Zeitraum"
+ "configureInstructions": "Um echte Analysedaten zu sehen, konfigurieren Sie Umami in Ihren Umgebungsvariablen und Admin-Panel-Einstellungen."
},
"email": {
"title": "E-Mail-Konfiguration",
@@ -2129,28 +1920,9 @@
"loadingSettings": "E-Mail-Einstellungen werden geladen...",
"smtpConfiguration": "SMTP-Konfiguration",
"smtpHost": "SMTP-Host",
- "smtpHostHelp": "Ihr E-Mail-Server-Hostname",
- "smtpPort": "SMTP-Port",
- "smtpPortHelp": "Normalerweise 587 für TLS, 465 für SSL, 25 für unverschlüsselt",
- "smtpSecure": "SSL/TLS verwenden",
- "smtpSecureHelp": "Für sichere E-Mail-Übertragung aktivieren",
- "smtpUsername": "SMTP-Benutzername",
- "smtpUsernameHelp": "Ihr E-Mail-Konto-Benutzername",
- "smtpPassword": "SMTP-Passwort",
- "smtpPasswordHelp": "Ihr E-Mail-Konto-Passwort",
- "fromDetails": "Absenderdetails",
"fromEmail": "Absender-E-Mail",
- "fromEmailHelp": "E-Mail-Adresse, die als Absender erscheint",
"fromName": "Absendername",
- "fromNameHelp": "Name, der als Absender erscheint",
- "testConfiguration": "Konfiguration testen",
- "testEmail": "Test-E-Mail-Adresse",
- "testEmailHelp": "Senden Sie eine Test-E-Mail zur Überprüfung der Einstellungen",
- "sendTestEmail": "Test-E-Mail senden",
- "saveConfiguration": "Konfiguration speichern",
"emailTemplates": "E-Mail-Vorlagen",
- "templateVariables": "Verfügbare Variablen",
- "previewTemplate": "Vorlage anzeigen",
"smtpSettings": "SMTP-Einstellungen",
"testEmailSuccess": "Test-E-Mail erfolgreich gesendet",
"saveSmtpSettings": "SMTP-Einstellungen speichern",
@@ -2168,23 +1940,18 @@
"emailBody": "E-Mail-Text",
"preview": "Vorschau",
"save": "Speichern",
- "saveChanges": "Änderungen speichern",
"templates": "Vorlagen",
- "variableHelp": "Verwenden Sie diese Variablen in Ihrer Vorlage. Sie werden beim Senden durch tatsächliche Werte ersetzt.",
"port": "Port",
"security": "Sicherheit",
"username": "Benutzername",
"password": "Passwort",
"enterPassword": "Passwort eingeben",
- "required": "erforderlich",
"ignoreSslErrors": "SSL/TLS-Zertifikatfehler ignorieren",
"ignoreSslWarning": "Warnung: Das Deaktivieren der Zertifikatüberprüfung macht die Verbindung anfällig für Man-in-the-Middle-Angriffe. Aktivieren Sie dies nur, wenn Sie dem SMTP-Server vertrauen und die Sicherheitsrisiken verstehen.",
"brandingTitle": "E-Mail-Branding",
"brandingDescription": "Passen Sie die Farben in E-Mail-Vorlagen an. Änderungen gelten für Kopfzeile, Schaltflächen, Links und Fußzeilen-Hintergrund.",
"primaryColor": "Primärfarbe",
- "primaryColorHint": "Wird für Kopfzeile, Schaltflächen und Links verwendet",
"secondaryColor": "Fußzeilen-Hintergrund",
- "secondaryColorHint": "Wird für den Hintergrund der Fußzeile verwendet",
"saveEmailColors": "E-Mail-Farben speichern",
"editor": {
"bold": "Fett",
@@ -2210,7 +1977,23 @@
"copiedFromLanguage": "Inhalt von {{language}} kopiert",
"noTranslation": "Noch keine Übersetzung",
"noTranslationYet": "Für diese Sprache existiert noch keine Übersetzung. Kopieren Sie von einer vorhandenen Sprache:",
- "copyFrom": "Kopieren von"
+ "copyFrom": "Kopieren von",
+ "syncedFromBranding": "",
+ "syncFromBranding": "",
+ "primaryColorHelp": "",
+ "secondaryColorHelp": "",
+ "bodyBgColor": "",
+ "bodyBgColorHelp": "",
+ "containerBgColor": "",
+ "containerBgColorHelp": "",
+ "listBgColor": "",
+ "listBgColorHelp": "",
+ "bodyTextColor": "",
+ "bodyTextColorHelp": "",
+ "mutedTextColor": "",
+ "mutedTextColorHelp": "",
+ "buttonTextColor": "",
+ "buttonTextColorHelp": ""
},
"cms": {
"title": "CMS-Seiten",
@@ -2224,17 +2007,22 @@
"pageTitle": "Seitentitel",
"pageContent": "Seiteninhalt",
"pageTitlePlaceholder": "Seitentitel eingeben...",
- "saveChanges": "Änderungen speichern",
"lastUpdated": "Zuletzt aktualisiert:",
- "impressum": "Impressum",
- "datenschutz": "Datenschutzerklärung",
"pageUpdated": "Seite erfolgreich aktualisiert",
"useExternalUrl": "Externe URL verwenden",
"useExternalUrlHelp": "Besucher werden auf eine externe Seite weitergeleitet, anstatt die internen Inhalte anzuzeigen. Titel und Inhalt bleiben als Fallback gespeichert.",
"externalUrl": "Externe URL",
"externalUrlPlaceholder": "https://example.com/impressum",
"externalUrlInvalid": "Muss eine gültige https://-URL sein",
- "externalUrlActive": "Externe URL ist aktiv — interne Inhalte bleiben gespeichert, werden Besuchern aber nicht angezeigt."
+ "externalUrlActive": "Externe URL ist aktiv — interne Inhalte bleiben gespeichert, werden Besuchern aber nicht angezeigt.",
+ "logoUploaded": "",
+ "logoCleared": "",
+ "pageLogo": "",
+ "pageLogoHelp": "",
+ "noLogo": "",
+ "replaceLogo": "",
+ "uploadLogo": "",
+ "clearLogo": ""
},
"validation": {
"eventNameRequired": "Veranstaltungsname ist erforderlich",
@@ -2245,14 +2033,15 @@
"passwordRequired": "Passwort ist erforderlich",
"passwordMinLength": "Passwort muss mindestens 6 Zeichen lang sein",
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
- "passwordSecurityRequirements": "Passwort erfüllt nicht die Sicherheitsanforderungen",
- "expirationRange": "Ablauf muss zwischen 1 und 365 Tagen liegen"
+ "expirationRange": "Ablauf muss zwischen 1 und 365 Tagen liegen",
+ "required": "",
+ "expirationRequired": "",
+ "eventDateRequired": "",
+ "passwordTooSimple": ""
},
"maintenance": {
"title": "Systemwartung",
"message": "Wir führen derzeit geplante Wartungsarbeiten durch, um unseren Service zu verbessern. Wir sind in Kürze wieder online.",
- "expectedCompletion": "Voraussichtliche Fertigstellung:",
- "checkBackLater": "Bitte schauen Sie später wieder vorbei",
"urgentMatters": "Bei dringenden Anliegen kontaktieren Sie bitte"
},
"passwordChange": {
@@ -2331,18 +2120,7 @@
"pendingApproval": "Genehmigung ausstehend",
"noComments": "Noch keine Kommentare. Seien Sie der Erste!",
"rating": "Bewertung",
- "ratePhoto": "Dieses Foto bewerten",
- "yourRating": "Ihre Bewertung",
- "averageRating": "Durchschnittliche Bewertung",
- "totalRatings": "Bewertungen",
"likes": "Gefällt mir",
- "favorites": "Favoriten",
- "likePhoto": "Foto gefällt mir",
- "favoritePhoto": "Zu Favoriten hinzufügen",
- "photoFeedback": "Foto-Feedback",
- "hasFeedback": "Hat Feedback",
- "hasComments": "Hat Kommentare",
- "hasRating": "Hat Bewertung",
"settings": {
"title": "Gast-Feedback-Einstellungen",
"enableFeedback": "Feedback aktivieren",
@@ -2354,33 +2132,117 @@
"comments": "Kommentare",
"commentsDesc": "Textkommentare auf Fotos",
"favorites": "Favoriten",
- "favoritesDesc": "Fotos als Favoriten markieren"
- }
+ "favoritesDesc": "Fotos als Favoriten markieren",
+ "identityMode": "",
+ "identityModeSimple": "",
+ "identityModeSimpleDesc": "",
+ "identityModeGuest": "",
+ "identityModeGuestDesc": "",
+ "privacyModeration": "",
+ "requireInfo": "",
+ "requireInfoDesc": "",
+ "moderateComments": "",
+ "moderateCommentsDesc": "",
+ "showToGuests": "",
+ "showToGuestsDesc": "",
+ "enableRateLimiting": "",
+ "rateLimitingDesc": "",
+ "timeWindow": "",
+ "maxRequests": ""
+ },
+ "settingsUpdated": "",
+ "settingsUpdateError": "",
+ "moderated": "",
+ "deleted": "",
+ "exported": "",
+ "exportError": "",
+ "title": "",
+ "exportCSV": "",
+ "exportJSON": "",
+ "tabs": {
+ "settings": "",
+ "feedback": "",
+ "analytics": "",
+ "moderation": ""
+ },
+ "allTypes": "",
+ "types": {
+ "rating": "",
+ "like": "",
+ "comment": "",
+ "favorite": ""
+ },
+ "allStatuses": "",
+ "status": {
+ "pending": "",
+ "approved": "",
+ "hidden": ""
+ },
+ "noFeedback": "",
+ "approve": "",
+ "hide": "",
+ "unhide": "",
+ "confirmDelete": "",
+ "avgRating": "",
+ "totalRatings_one": "",
+ "totalRatings_other": "",
+ "totalLikes": "",
+ "totalComments": "",
+ "pendingModeration_one": "",
+ "pendingModeration_other": "",
+ "totalInteractions": "",
+ "topRated": "",
+ "recentComments": "",
+ "wordFilters": "",
+ "wordFiltersDesc": "",
+ "manageFilters": "",
+ "manage": "",
+ "ratingSubmitted": "",
+ "ratingError": "",
+ "rateStar_one": "",
+ "rateStar_other": "",
+ "ratingsCount_one": "",
+ "ratingsCount_other": "",
+ "likeError": "",
+ "unlike": "",
+ "like": "",
+ "favoriteError": "",
+ "unfavorite": "",
+ "favorite": "",
+ "invalidEmail": "",
+ "identityRequired": "",
+ "identityReason": "",
+ "namePlaceholder": "",
+ "emailPlaceholder": "",
+ "submitFeedback": "",
+ "moderationSuccess": "",
+ "pendingModeration": "",
+ "pending": "",
+ "noPendingComments": "",
+ "onPhoto": "",
+ "showAll_one": "",
+ "showAll_other": "",
+ "viewAllFeedback": ""
},
"filter": {
"feedbackFilters": "Feedback-Filter",
"clear": "Löschen",
"rating": "Bewertung",
- "allPhotos": "Alle Fotos",
- "anyRating": "Jede Bewertung",
- "oneStarPlus": "1+ Sterne",
- "twoStarsPlus": "2+ Sterne",
- "threeStarsPlus": "3+ Sterne",
- "fourStarsPlus": "4+ Sterne",
- "fiveStarsOnly": "Nur 5 Sterne",
"hasLikes": "Hat Gefällt mir",
"hasFavorites": "Hat Favoriten",
"hasComments": "Hat Kommentare",
"showingPhotos": "Fotos gesamt",
- "withRatings": "Mit Bewertungen"
+ "withRatings": "Mit Bewertungen",
+ "combineWith": ""
},
"export": {
"button": "Exportieren",
"success": "Export erfolgreich heruntergeladen",
"error": "Export fehlgeschlagen: ",
- "exportSelected": "{{count}} ausgewählte exportieren",
"exportFiltered": "Gefilterte Fotos exportieren",
- "hint": "Fotos auswählen oder Filter anwenden zum Exportieren"
+ "hint": "Fotos auswählen oder Filter anwenden zum Exportieren",
+ "exportSelected_one": "",
+ "exportSelected_other": ""
},
"clientAccess": {
"title": "Kundenzugang",
@@ -2420,7 +2282,6 @@
"passwordRequired": "Passwort ist erforderlich",
"passwordMinLength": "Passwort muss mindestens 6 Zeichen lang sein",
"rememberMe": "Angemeldet bleiben",
- "forgotPassword": "Passwort vergessen?",
"signIn": "Anmelden",
"loginSuccess": "Anmeldung erfolgreich!",
"networkError": "Netzwerkfehler. Bitte überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
@@ -2461,5 +2322,17 @@
"filenameAZ": "Dateiname (A-Z)",
"filenameZA": "Dateiname (Z-A)",
"dateTaken": "Aufnahmedatum"
+ },
+ "photos": {
+ "moveToCategory_one": "",
+ "moveToCategory_other": "",
+ "selectCategory": "",
+ "uncategorized": "",
+ "movePhotos": "",
+ "selectedCategory": "",
+ "movedToCategory_one": "",
+ "movedToCategory_other": "",
+ "moveToCategoryFailed": "",
+ "moveToCategory": ""
}
}
diff --git a/frontend/src/i18n/locales/fr.json b/frontend/src/i18n/locales/fr.json
index c57e9751..b530c0cc 100644
--- a/frontend/src/i18n/locales/fr.json
+++ b/frontend/src/i18n/locales/fr.json
@@ -81,8 +81,6 @@
"delete": "Supprimer",
"edit": "Modifier",
"add": "Ajouter",
- "search": "Rechercher",
- "filter": "Filtrer",
"sortBy": "Trier par",
"yes": "Oui",
"no": "Non",
@@ -91,35 +89,41 @@
"previous": "Précédent",
"close": "Fermer",
"logout": "Déconnexion",
- "menu": "Menu",
"change": "Modifier",
"remove": "Retirer",
"download": "Télécharger",
"downloadAll": "Tout télécharger",
- "uploading": "Téléversement...",
- "uploaded": "Téléversé",
"photo": "photo",
"photos": "photos",
"video": "vidéo",
- "videos": "vidéos",
"media": "média",
- "restore": "Restaurer",
- "actions": "Actions",
- "refresh": "Actualiser",
- "preview": "Aperçu",
- "processing": "Traitement...",
"upload": "Téléverser",
- "days": "jours",
"customize": "Personnaliser",
"hide": "Masquer",
"unknown": "Inconnu",
"notSet": "Non défini",
"of": "sur",
- "up": "Haut",
- "select": "Sélectionner",
"selected": "Sélectionné",
"chunk": "Segment",
- "optional": "optionnel"
+ "optional": "optionnel",
+ "tryAgain": "Réessayer",
+ "active": "Actif",
+ "inactive": "Inactif",
+ "create": "Créer",
+ "unknownDate": "Date inconnue",
+ "pageOf": "Page {{current}} sur {{total}}",
+ "collapse": "Réduire",
+ "expand": "Développer",
+ "submitting": "Envoi en cours…",
+ "copy": "Copier",
+ "copied": "Copié !",
+ "applying": "Application en cours…",
+ "done": "Terminé",
+ "retry": "Réessayer",
+ "characters": "caractères",
+ "saveChanges": "Enregistrer les modifications",
+ "resetChanges": "Réinitialiser les modifications",
+ "dismiss": "Ignorer"
},
"upload": {
"photoCategory": "Catégorie de photo",
@@ -127,40 +131,37 @@
"eventSpecific": "(Spécifique à l'événement)",
"clickToUpload": "Cliquez pour téléverser ou glissez-déposez",
"fileRequirements": "JPEG, PNG ou WebP (max 50 Mo par fichier, {{limit}} fichiers par envoi)",
- "fileRequirementsMedia": "Images JPEG, PNG ou WebP, plus vidéos MP4/MOV/WEBM (max 50 Mo par fichier, {{limit}} fichiers par envoi)",
- "unsupportedFiles": "Certains fichiers ont été ignorés car le format n'est pas supporté (utilisez JPEG/PNG/WebP/MP4/MOV/WEBM).",
"selectedFiles": "Fichiers sélectionnés",
"uploading": "Téléversement...",
"uploadComplete": "Téléversement terminé !",
- "uploadFailed": "Échec du téléversement",
"someFilesFailed": "Certains fichiers n'ont pas pu être téléversés",
"uploadPhotos": "Téléverser des photos",
"uploadMedia": "Téléverser photos et vidéos",
- "importExternal": "Importer depuis un dossier externe",
- "externalImportInfo": "Toutes les images du dossier sélectionné seront importées.",
- "selectExternalFolder": "Sélectionnez le dossier externe sous /external-media",
- "importFromSelectedFolder": "Importer depuis le dossier sélectionné",
"maxFilesReached": "Maximum de {{limit}} fichiers autorisés",
"someFilesSkipped": "Seuls {{allowed}} fichiers supplémentaires peuvent être ajoutés (limite de {{limit}})",
"tooManyFiles": "Un maximum de {{limit}} fichiers peuvent être téléversés à la fois",
"limitInfo": "{{selected}} sur {{limit}} fichiers sélectionnés ({{remaining}} restants)",
"limitReached": "Limite de téléversement atteinte ({{limit}} fichiers par lot)",
- "uploadingChunks": "Téléversement de {{count}} fichiers en {{total}} lots...",
- "mediaCategory": "Catégorie de média",
- "uploadAction": "Téléverser {{count}} fichiers"
+ "replacedFiles_many": "{{count}} photos remplacées",
+ "replacedFiles_one": "{{count}} photo remplacée",
+ "replacedFiles_other": "{{count}} photos remplacées",
+ "processingFailed_many": "{{count}} photos n'ont pas pu être traitées",
+ "processingFailed_one": "{{count}} photo n'a pas pu être traitée",
+ "processingFailed_other": "{{count}} photos n'ont pas pu être traitées",
+ "replaceByName": "Remplacer les photos existantes avec le même nom",
+ "processing": "Traitement des photos…",
+ "processingProgress": "{{complete}} sur {{total}} terminés",
+ "processingHint": "Les fichiers sont téléversés. PicPeak génère maintenant les miniatures et lit les métadonnées. Vous pouvez quitter cette page — le travail continue en arrière-plan.",
+ "transferring": "Transfert en cours",
+ "uploadingChunks_many": "{{count}} segments en cours de téléversement",
+ "uploadingChunks_one": "{{count}} segment en cours de téléversement",
+ "uploadingChunks_other": "{{count}} segments en cours de téléversement",
+ "retryFailed": "Réessayer les échoués"
},
"navigation": {
"dashboard": "Tableau de bord",
"events": "Événements",
- "archives": "Archives",
- "settings": "Paramètres",
- "eventTypes": "Types d'événements",
- "branding": "Identité visuelle",
- "analytics": "Analytique",
- "emailSettings": "Paramètres e-mail",
- "backup": "Sauvegarde et Restauration",
- "cmsPages": "Pages CMS",
- "users": "Utilisateurs"
+ "settings": "Paramètres"
},
"archives": {
"title": "Archives",
@@ -203,68 +204,44 @@
"deleteSuccess": "Archive supprimée définitivement"
},
"auth": {
- "login": "Connexion",
"password": "Mot de passe",
"enterPassword": "Entrer le mot de passe de la galerie",
"passwordPlaceholder": "Saisissez le mot de passe de la galerie",
"invalidPassword": "Mot de passe invalide",
"wrongPassword": "Mot de passe incorrect. Veuillez vérifier et réessayer.",
"tooManyAttempts": "Trop de tentatives de connexion échouées. Veuillez réessayer plus tard.",
- "sessionExpired": "Session expirée",
"pleaseEnterPassword": "Veuillez entrer un mot de passe",
"passwordHint": "Le mot de passe a été fourni par l'organisateur de l'événement. Contactez-le si vous ne l'avez pas."
},
"gallery": {
- "title": "Galerie Photo",
- "welcomeMessage": "Message de bienvenue",
- "expiresOn": "Expire le",
"expires": "Expire",
"expired": "Expirée",
- "daysRemaining": "{{days}} jours restants",
- "dayRemaining": "1 jour restant",
- "hoursRemaining": "{{hours}} heures restantes",
- "expiredMessage": "Cette galerie a expiré le {{date}}",
"contactOrganizer": "Veuillez contacter l'organisateur si vous avez besoin d'accéder à ces photos",
"searchPhotos": "Rechercher par nom de fichier...",
"sortByDate": "Trier par date",
- "sortByName": "Trier par nom",
+ "sortByName": "Trier par nom",
"sortBySize": "Trier par taille",
"allPhotos": "Toutes les photos",
- "filter": "Filtrer",
"feedbackFilter": "Filtre d'avis",
"all": "Tout",
"liked": "Aimé",
"favorited": "Favori",
"favorites": "Favoris",
- "downloadSelected": "Télécharger la sélection",
- "shareGallery": "Partager la galerie",
"needHelp": "Besoin d'aide ? Contactez-nous à",
"noPhotosFound": "Aucune photo trouvée",
"failedToLoad": "Échec du chargement des photos",
"tryAgain": "Réessayer",
"loading": "Chargement de la galerie...",
"expiredOn": "Cette galerie a expiré le {{date}}.",
- "expiresIn": "La galerie expire dans {{count}} jour",
- "expiresIn_plural": "La galerie expire dans {{count}} jours",
"downloadBefore": "Téléchargez vos photos avant qu'elles ne soient plus disponibles.",
- "publicGalleryTitle": "Cette galerie est accessible publiquement",
- "publicGallerySubtitle": "Chargement des photos...",
"viewGallery": "Voir la galerie",
"downloadAll": "Tout télécharger",
- "downloading": "Téléchargement de {{count}} photo...",
- "downloading_plural": "Téléchargement de {{count}} photos...",
- "downloadedPhotos": "{{count}} photo téléchargée !",
- "downloadedPhotos_plural": "{{count}} photos téléchargées !",
"downloadError": "Échec du téléchargement de certaines photos",
"selectPhotos": "Sélectionner des photos",
"cancelSelection": "Annuler la sélection",
- "photosSelected": "{{count}} sélectionnée(s)",
"selectAll": "Tout sélectionner",
"deselectAll": "Tout désélectionner",
- "downloadSelected": "Télécharger les {{count}} sélectionnés",
"deleteSelected": "Supprimer la sélection",
- "photosCount": "{{count}} photo",
- "photosCount_plural": "{{count}} photos",
"searchByFilename": "Rechercher par nom de fichier...",
"uncategorized": "Non catégorisé",
"sortAscending": "Tri croissant",
@@ -272,8 +249,6 @@
"remaining": "restant",
"selectPhotosHint": "Astuce : Utilisez Ctrl+Clic (Cmd+Clic sur Mac) pour sélectionner rapidement plusieurs photos",
"filters": "Filtres",
- "openFilters": "Ouvrir les filtres",
- "toggleSidebar": "Basculer la barre latérale",
"toggleMenu": "Basculer le menu",
"allCategories": "Toutes les catégories",
"categories": "Catégories",
@@ -285,10 +260,7 @@
"noMedia": "Aucun média téléversé pour le moment",
"searchPlaceholder": "Rechercher des photos...",
"sortBy": "Trier par",
- "sortByDate": "Trier par date",
"sortByCaptureDate": "Trier par date de capture",
- "sortByName": "Trier par nom",
- "sortBySize": "Trier par taille",
"sortByRating": "Trier par note",
"photoGallery": "Galerie Photo",
"photos": "Photos",
@@ -307,14 +279,63 @@
"writeLovelyNote": "Écrivez un petit mot...",
"postComment": "Publier le commentaire",
"anonymous": "Anonyme"
- }
+ },
+ "expiresIn_many": "La galerie expire dans {{count}} jours",
+ "expiresIn_one": "La galerie expire dans {{count}} jour",
+ "expiresIn_other": "La galerie expire dans {{count}} jours",
+ "downloading_many": "Téléchargement de {{count}} photos…",
+ "downloading_one": "Téléchargement d'1 photo…",
+ "downloading_other": "Téléchargement de {{count}} photos…",
+ "photosSelected_many": "{{count}} photos sélectionnées",
+ "photosSelected_one": "{{count}} photo sélectionnée",
+ "photosSelected_other": "{{count}} photos sélectionnées",
+ "downloadSelected_many": "Télécharger {{count}} photos",
+ "downloadSelected_one": "Télécharger {{count}} photo",
+ "downloadSelected_other": "Télécharger {{count}} photos",
+ "rated": "Noté",
+ "commented": "Commenté",
+ "guestRecovery": {
+ "invalidEmail": "Saisissez une adresse e-mail valide",
+ "codeSent": "Vérifiez votre boîte de réception pour un code de vérification.",
+ "requestError": "Impossible d'envoyer le code. Réessayez.",
+ "invalidCode": "Saisissez le code à 6 chiffres",
+ "verifyError": "Code invalide ou expiré.",
+ "back": "Retour",
+ "title": "Retrouvez vos sélections",
+ "emailStepDescription": "Saisissez l'adresse e-mail que vous avez utilisée. Nous vous enverrons un code de vérification à 6 chiffres.",
+ "codeStepDescription": "Saisissez le code à 6 chiffres que nous avons envoyé à votre adresse e-mail.",
+ "emailLabel": "E-mail",
+ "sendCode": "Envoyer le code",
+ "codeLabel": "Code de vérification",
+ "verifyCode": "Vérifier et continuer"
+ },
+ "guestPrompt": {
+ "nameRequired": "Le nom est obligatoire",
+ "invalidEmail": "Adresse e-mail invalide",
+ "emailRequired": "L'e-mail est obligatoire",
+ "error": "Échec de l'inscription",
+ "title": "Bienvenue — quel est votre prénom ?",
+ "description": "Vos sélections seront enregistrées sous ce nom afin que le photographe sache quelles photos vous aimez.",
+ "nameLabel": "Votre nom",
+ "namePlaceholder": "Entrez votre nom",
+ "emailLabelRequired": "E-mail",
+ "emailLabel": "E-mail (facultatif)",
+ "emailPlaceholder": "vous@exemple.com",
+ "submit": "Continuer",
+ "alreadyHere": "J'ai déjà été ici"
+ },
+ "footer": {
+ "forgetMeConfirm": "Votre nom et vos sélections seront supprimés de cette galerie.",
+ "forgetMe": "M'oublier ({{name}})"
+ },
+ "photosCount_many": "{{count}} photos",
+ "photosCount_one": "{{count}} photo",
+ "photosCount_other": "{{count}} photos",
+ "poweredBy": "Propulsé par PicPeak"
},
"categories": {
"title": "Catégories de photos",
- "global": "Catégories globales",
- "eventSpecific": "Catégories spécifiques à l'événement",
"addCategory": "Ajouter une catégorie",
- "organizationInfo": "Organisez vos photos en catégories. Les catégories aident les invités à naviguer et à trouver des types de photos spécifiques.",
"eventSpecificCategories": "Catégories spécifiques à l'événement",
"noEventSpecificCategories": "Aucune catégorie spécifique. Les catégories globales sont disponibles par défaut.",
"globalCategoriesAlwaysAvailable": "Catégories globales (toujours disponibles) :",
@@ -324,10 +345,8 @@
"failedToCreateCategory": "Échec de la création de la catégorie",
"failedToDeleteCategory": "Échec de la suppression de la catégorie",
"categoryName": "Nom de la catégorie",
- "noCategory": "Aucune catégorie",
"noCategoriesYet": "Pas encore de catégories. Créez votre première catégorie pour organiser les photos.",
"deleteConfirm": "Êtes-vous sûr de vouloir supprimer \"{{name}}\" ?",
- "cannotDelete": "Impossible de supprimer une catégorie contenant des photos. Veuillez réassigner les photos d'abord.",
"setCoverPhoto": "Définir comme photo de couverture",
"removeCoverPhoto": "Retirer la photo de couverture",
"coverPhotoSet": "Photo de couverture définie avec succès",
@@ -342,34 +361,14 @@
"totalViews": "Total des vues",
"totalDownloads": "Total des téléchargements",
"uniqueVisitors": "Visiteurs uniques",
- "createNewEvent": "Créer un nouvel événement",
- "setupNewGallery": "Configurez une nouvelle galerie photo pour votre événement",
- "createNewEventSubtitle": "Configurez une nouvelle galerie photo pour votre événement",
"eventNamePlaceholder": "ex: Mariage de Julie & Thomas",
- "welcomeMessageOptional": "Message de bienvenue (Optionnel)",
"welcomeMessagePlaceholder": "Bienvenue à notre journée spéciale ! N'hésitez pas à télécharger et partager ces souvenirs...",
"hostEmailPlaceholder": "client@exemple.com",
"adminEmailPlaceholder": "admin@exemple.com",
- "securityAndAccess": "Sécurité et Accès",
"accessAndSecurity": "Accès et Sécurité",
"enterPassword": "Entrer le mot de passe",
"passwordPlaceholder": "Entrer un mot de passe sécurisé",
"confirmPasswordPlaceholder": "Confirmer le mot de passe",
- "galleryExpiresOn": "La galerie expirera le {{date}}",
- "guestsWillReceiveWarning": "Les invités recevront un e-mail d'avertissement 7 jours avant l'expiration.",
- "types": {
- "wedding": "Mariage",
- "birthday": "Anniversaire",
- "corporate": "Entreprise",
- "other": "Autre"
- },
- "themes": {
- "default": "Par défaut",
- "oceanBlue": "Bleu Océan",
- "royalPurple": "Violet Royal",
- "roseGold": "Or Rose",
- "sunsetAmber": "Ambre Coucher de Soleil"
- },
"eventDetails": "Détails de l'événement",
"eventName": "Nom de l'événement",
"eventType": "Type d'événement",
@@ -378,11 +377,9 @@
"hostName": "Nom du client",
"hostNamePlaceholder": "Jean Dupont",
"adminEmail": "E-mail de l'admin",
- "adminNotificationEmail": "E-mail de notification admin",
"expirationDate": "Date d'expiration",
"active": "Actif",
"archived": "Archivé",
- "photoCount": "{{count}} photos",
"totalSize": "Taille totale",
"shareLink": "Lien de partage",
"copyLink": "Copier le lien",
@@ -395,10 +392,7 @@
"backToEvents": "Retour aux événements",
"loadingEventDetails": "Chargement des détails...",
"saveChanges": "Enregistrer les modifications",
- "eventExpired": "Cet événement a expiré",
"eventExpiresIn": "Cet événement expire dans {{days}} jours",
- "guestsNoAccess": "Les invités ne peuvent plus accéder à la galerie. Envisagez d'archiver cet événement.",
- "warningEmailsSent": "Des e-mails d'avertissement ont été envoyés au client.",
"overview": "Aperçu",
"photos": "Photos",
"categories": "Catégories",
@@ -411,7 +405,6 @@
"externalFolderHint": "Ces dossiers sont lus depuis le montage /external-media dans votre conteneur ou hôte.",
"externalFolderRequired": "Veuillez sélectionner un dossier externe avant d'enregistrer.",
"welcomeMessage": "Message de bienvenue",
- "noWelcomeMessage": "Aucun message de bienvenue défini",
"created": "Créé",
"expires": "Expire le",
"shareWithGuests": "Partagez ce lien avec vos invités. Ils auront besoin du mot de passe pour accéder à la galerie.",
@@ -425,37 +418,22 @@
"managePhotos": "Gérer les photos",
"actions": "Actions",
"archivingInfo": "L'archivage créera un fichier ZIP de toutes les photos et supprimera l'accès public à la galerie.",
- "statistics": "Statistiques",
- "views": "Vues",
- "downloads": "Téléchargements",
- "noStatistics": "Aucune statistique disponible pour le moment",
- "archiveStatus": "Statut de l'archive",
"archivedOn": "Archivé le",
"downloadArchive": "Télécharger l'archive",
"loadingPhotos": "Chargement des photos...",
"photoCategories": "Catégories de photos",
"organizeCategoriesInfo": "Organisez vos photos en catégories. Les catégories aident les invités à naviguer.",
- "categoriesTip": "Astuce : Les catégories sont spécifiques à chaque événement. Vous pouvez aussi créer des catégories globales dans les Paramètres.",
- "contactInformation": "Informations de contact",
- "hostEmailHelp": "Le client recevra les notifications de création et d'expiration de la galerie",
- "adminEmailHelp": "Recevra les notifications système et les confirmations d'archivage",
- "securityAccess": "Sécurité et Accès",
+ "categoriesTip": "Astuce : Créez des catégories comme \"Cérémonie\", \"Réception\", \"Portraits\", etc.",
"galleryPassword": "Mot de passe de la galerie",
"requirePasswordToggle": "Exiger un mot de passe pour cette galerie",
"requirePasswordToggleHelp": "Désactivez cette option pour partager la galerie sans mot de passe. Toute personne disposant du lien pourra voir les photos.",
"publicGalleryWarning": "Les galeries publiques sont accessibles à tous ceux qui ont le lien. Envisagez d'activer les filigranes et de surveiller l'activité.",
"passwordHelperText": "Vous pouvez utiliser des dates comme \"04.07.2025\" ou n'importe quel texte de plus de 6 caractères",
"confirmPassword": "Confirmer le mot de passe",
- "showPasswords": "Afficher les mots de passe",
"newPasswordLabel": "Nouveau mot de passe de la galerie",
- "gallerySettings": "Paramètres de la galerie",
"themeAndStyle": "Thème et Style",
- "colorTheme": "Thème de couleur",
"galleryExpiration": "Expiration de la galerie",
- "galleryExpiresIn": "La galerie expire dans",
"daysAfterEvent": "jours après la date de l'événement",
- "galleryWillExpireOn": "La galerie expirera le {{date}}",
- "expirationWarning": "Les invités recevront un e-mail d'avertissement 7 jours avant l'expiration.",
"noExpiration": "Pas d'expiration",
"noExpirationHelp": "Cette galerie restera active jusqu'à son archivage manuel.",
"userUploads": "Paramètres de téléversement invité",
@@ -465,11 +443,7 @@
"uploadCategory": "Catégorie de téléversement",
"selectCategory": "Sélectionner une catégorie pour les envois invités",
"uploadCategoryHelp": "Toutes les photos envoyées par les invités seront ajoutées à cette catégorie",
- "userUploadWarning": "Les envois invités seront modérés et peuvent être supprimés par les admins à tout moment.",
"allowDownloads": "Autoriser le téléchargement des photos",
- "allowDownloadsHelp": "Autorise les invités à télécharger les photos de cette galerie",
- "downloadPermissions": "Permissions de téléchargement",
- "downloadsEnabled": "Téléchargements activés",
"downloadsDisabled": "Téléchargements désactivés",
"downloadProtection": "Protection contre le téléchargement",
"disableRightClick": "Bloquer le clic droit",
@@ -518,28 +492,13 @@
"heroImageAnchorBottom": "Bas",
"heroPreview": "Aperçu Hero",
"noPhotosAvailable": "Aucune photo disponible",
- "processingRequest": "Traitement de votre demande...",
- "eventTypeWedding": "Mariage",
- "eventTypeBirthday": "Anniversaire",
- "eventTypeCorporate": "Entreprise",
- "eventTypeOther": "Autre",
- "days30": "30 jours",
- "days60": "60 jours",
- "days90": "90 jours",
- "days365": "1 an",
"inactive": "Inactif",
- "daysLeft": "{{count}}j restant",
- "daysLeft_plural": "{{count}}j restants",
"subtitle": "Gérez vos galeries photo et vos événements",
- "loadingEvents": "Chargement des événements...",
"failedToLoadEvents": "Échec du chargement des événements",
- "bulkArchiveSuccess": "Archivage réussi de {{count}} événements",
"bulkArchivePartial": "{{success}} événements archivés, {{failed}} échecs",
"searchEventsPlaceholder": "Rechercher des événements...",
"all": "Tout",
"expiring": "Expire bientôt",
- "eventsSelected": "{{count}} événement sélectionné",
- "eventsSelected_plural": "{{count}} événements sélectionnés",
"clear": "Effacer",
"archiveSelected": "Archiver la sélection",
"publicAccess": "Accès public",
@@ -568,25 +527,14 @@
"extendSevenDays": "Prolonger de 7 jours",
"welcomeMessageLabel": "Message de bienvenue",
"noWelcomeMessageSet": "Aucun message de bienvenue défini",
- "createdOn": "Créé le",
- "daysLeft": "({{count}} jour restant)",
- "daysLeft_plural": "({{count}} jours restants)",
"copy": "Copier",
"copied": "Copié !",
- "organizingPhotosInfo": "Organisez vos photos en catégories pour aider vos invités.",
- "categoriesTip": "Astuce : Créez des catégories comme \"Cérémonie\", \"Réception\", \"Portraits\", etc.",
"archiveStatusTitle": "Statut de l'archive",
"downloadingArchive": "Téléchargement de l'archive {{name}}...",
"downloadStarted": "Téléchargement démarré",
"failedToDownloadArchive": "Échec du téléchargement de l'archive",
- "statisticsNotAvailable": "Statistiques non disponibles pour le moment",
- "photoFilters": "Filtres photo",
- "noStatisticsAvailableYet": "Pas encore de statistiques disponibles",
- "addPlus": "Ajouter+",
"galleryTheme": "Thème de la galerie",
- "customizeTheme": "Personnaliser le thème",
"noThemeSet": "Aucun thème configuré",
- "customizingTheme": "Personnalisation du thème de la galerie",
"customizingThemeFor": "Personnalisation du thème pour {{event}}",
"customCssTemplate": "Modèle CSS personnalisé",
"customCssTemplateDesc": "Appliquez un modèle CSS personnalisé pour un style unique.",
@@ -602,8 +550,104 @@
"renamingFiles": "Renommage des fichiers...",
"complete": "Terminé !",
"failed": "Échec du renommage",
- "filesRenamed": "{{count}} fichiers mis à jour",
- "confirm": "Renommer l'événement"
+ "confirm": "Renommer l'événement",
+ "success": "Événement renommé avec succès !",
+ "filesRenamed_many": "{{count}} fichiers mis à jour",
+ "filesRenamed_one": "{{count}} fichier mis à jour",
+ "filesRenamed_other": "{{count}} fichiers mis à jour",
+ "newLink": "Nouveau lien de galerie",
+ "currentName": "Nom actuel :",
+ "newName": "Nouveau nom de l'événement",
+ "enterNewName": "Saisissez le nouveau nom de l'événement",
+ "newUrl": "Nouvelle URL :",
+ "checkingAvailability": "Vérification de la disponibilité…",
+ "resendEmail": "Renvoyer l'e-mail d'invitation avec le nouveau lien",
+ "emailTo": "Envoyer l'e-mail d'accès à la galerie mis à jour à",
+ "warningTitle": "Veuillez noter :",
+ "warning1": "L'URL de la galerie va changer",
+ "warning2": "Les anciennes URLs redirigeront automatiquement vers la nouvelle",
+ "warning3": "Les fichiers photos pourraient être renommés"
+ },
+ "bulkArchiveSuccess_many": "{{count}} événements archivés avec succès",
+ "bulkArchiveSuccess_one": "{{count}} événement archivé avec succès",
+ "bulkArchiveSuccess_other": "{{count}} événements archivés avec succès",
+ "bulkDelete": {
+ "successAll_many": "{{count}} événements supprimés définitivement",
+ "successAll_one": "{{count}} événement supprimé définitivement",
+ "successAll_other": "{{count}} événements supprimés définitivement",
+ "successPartial": "{{success}} événements supprimés, {{failed}} échoués",
+ "incorrectPassword": "Mot de passe incorrect. Aucun événement supprimé.",
+ "errorGeneric": "Échec de la suppression des événements",
+ "title_many": "Supprimer définitivement {{count}} événements ?",
+ "title_one": "Supprimer définitivement {{count}} événement ?",
+ "title_other": "Supprimer définitivement {{count}} événements ?",
+ "processing_many": "Suppression de {{count}} événements. Cela peut prendre quelques minutes — ne fermez pas cette fenêtre.",
+ "processing_one": "Suppression de {{count}} événement. Cela peut prendre quelques minutes — ne fermez pas cette fenêtre.",
+ "processing_other": "Suppression de {{count}} événements. Cela peut prendre quelques minutes — ne fermez pas cette fenêtre.",
+ "warning": "Cette action supprimera définitivement les événements sélectionnés, toutes leurs photos, archives et journaux d'audit. Cette action est irréversible.",
+ "passwordLabel": "Ressaisissez votre mot de passe pour confirmer",
+ "passwordPlaceholder": "Votre mot de passe administrateur",
+ "passwordHelp": "Votre mot de passe est requis pour éviter les suppressions accidentelles en masse.",
+ "submit_many": "Supprimer {{count}} événements",
+ "submit_one": "Supprimer {{count}} événement",
+ "submit_other": "Supprimer {{count}} événements"
+ },
+ "draft": "Brouillon",
+ "expired": "Expiré",
+ "daysLeft_many": "({{count}} jours restants)",
+ "daysLeft_one": "({{count}} jour restant)",
+ "daysLeft_other": "({{count}} jours restants)",
+ "tryAgain": "Réessayer",
+ "eventsSelected_many": "{{count}} événements sélectionnés",
+ "eventsSelected_one": "{{count}} événement sélectionné",
+ "eventsSelected_other": "{{count}} événements sélectionnés",
+ "deleteSelected": "Supprimer la sélection",
+ "paginationLabel": "{{from}}–{{to}} sur {{total}}",
+ "filtered": "filtré",
+ "pageOf": "Page {{page}} sur {{totalPages}}",
+ "notFound": "Événement introuvable",
+ "externalFolderEmpty": "Aucun sous-dossier",
+ "clearSelection": "Effacer",
+ "publishSuccess": "Galerie publiée et client notifié !",
+ "draftBanner": "Cette galerie est en mode brouillon. Téléversez vos photos, puis publiez quand vous êtes prêt.",
+ "publishConfirm": "Cela rendra la galerie accessible et enverra l'e-mail de notification au client. Continuer ?",
+ "publishAndNotify": "Publier et notifier le client",
+ "customerPhone": "Téléphone du client",
+ "customerPhonePlaceholder": "+33 6 12 34 56 78",
+ "allowPresignedDownload": "Autoriser le téléchargement direct S3 (sans filigrane, mode S3 uniquement)",
+ "neverExpires": "Jamais",
+ "rightClickBlocked": "Clic droit bloqué",
+ "devtoolsDetection": "Détection des outils développeur",
+ "watermarked": "Avec filigrane",
+ "importExternal": "Importer depuis un dossier externe",
+ "externalImportInfo": "Toutes les images du dossier sélectionné seront importées.",
+ "selectExternalFolder": "Sélectionner un dossier externe sous /external-media",
+ "importFromSelectedFolder": "Importer depuis le dossier sélectionné",
+ "adminEmailPickFromAdmins": "Choisir parmi les administrateurs :",
+ "adminEmailCustom": "E-mail personnalisé",
+ "expiresOn": "Expire le",
+ "passwordReset": {
+ "errorMinLength": "Le mot de passe doit contenir au moins 6 caractères",
+ "errorMismatch": "Les mots de passe ne correspondent pas",
+ "toastSuccess": "Mot de passe réinitialisé avec succès",
+ "toastError": "Échec de la réinitialisation du mot de passe",
+ "toastCopied": "Mot de passe copié dans le presse-papiers",
+ "newTitle": "Nouveau mot de passe",
+ "title": "Réinitialiser le mot de passe de la galerie",
+ "description": "Définissez un nouveau mot de passe pour {{eventName}}, ou laissez les deux champs vides pour en générer un automatiquement.",
+ "newPasswordLabel": "Nouveau mot de passe",
+ "placeholder": "Laisser vide pour générer automatiquement",
+ "helperText": "Utilisez 6+ caractères, ou laissez vide pour générer automatiquement",
+ "confirmLabel": "Confirmer le mot de passe",
+ "sendEmail": "Envoyer une notification par e-mail",
+ "sendEmailHelp": "Informer l'hôte du changement de mot de passe",
+ "warning": "Note : L'ancien mot de passe ne fonctionnera plus. Assurez-vous de partager le nouveau mot de passe avec l'hôte.",
+ "submit": "Réinitialiser le mot de passe",
+ "successHeading": "Mot de passe réinitialisé avec succès !",
+ "emailSentNote": "Une notification par e-mail a été envoyée à l'hôte.",
+ "generatedLabel": "Mot de passe de galerie généré automatiquement",
+ "saveSecurelyNote": "Important : Sauvegardez ce mot de passe en lieu sûr. Il ne pourra pas être récupéré une fois cette fenêtre fermée.",
+ "done": "Terminé"
}
},
"settings": {
@@ -616,9 +660,7 @@
"siteUrl": "URL du site",
"siteUrlHelp": "Utilisé pour générer les liens des galeries dans les e-mails",
"defaultExpiration": "Expiration par défaut (jours)",
- "defaultExpirationHelp": "Durée d'activation par défaut des galeries",
"maxFileSize": "Taille max de fichier (Mo)",
- "maxFileSizeHelp": "Taille maximale par photo téléversée",
"maxFilesPerUpload": "Fichiers max par envoi",
"maxFilesPerUploadHelp": "Nombre maximum de photos autorisées par lot (1-{{max}}).",
"allowedFileTypes": "Types de fichiers autorisés",
@@ -630,13 +672,7 @@
"enableShortGalleryUrlsHelp": "Supprime le slug de l'événement des nouveaux liens tout en gardant les anciens fonctionnels.",
"maintenanceMode": "Activer le mode maintenance",
"language": "Langue",
- "defaultLanguage": "Langue par défaut",
"defaultLanguageHelp": "Langue affichée aux invités avant connexion",
- "defaultWelcomeMessage": "Message de bienvenue par défaut",
- "welcomeMessage": "Message de bienvenue",
- "welcomeMessagePlaceholder": "Entrez un message de bienvenue par défaut pour les e-mails de création",
- "welcomeMessageHelp": "Ce message sera inclus dans tous les e-mails de création, sauf s'il est modifié lors de la création d'un événement",
- "saveSettings": "Enregistrer les paramètres généraux",
"saveGeneralSettings": "Enregistrer les paramètres généraux",
"dateTimeFormat": "Format de date et d'heure",
"dateFormat": "Format de date",
@@ -654,7 +690,6 @@
"accountSaveSuccess": "Détails du compte mis à jour"
},
"publicSite": {
- "tabLabel": "Site Public",
"badge": "Page d'accueil",
"title": "Page d'accueil publique",
"subtitle": "Publiez une page d'accueil personnalisée pour les invités visitant votre domaine.",
@@ -682,8 +717,6 @@
"htmlRequired": "Fournissez un contenu HTML avant d'activer le site."
},
"storage": {
- "title": "Stockage",
- "overview": "Aperçu du stockage",
"totalUsed": "Total utilisé",
"archiveStorage": "Stockage des archives",
"storageLimit": "Limite de stockage",
@@ -695,7 +728,6 @@
"diskCapacityReported": "Capacité disque (déclarée)",
"diskAvailable": "Disponible",
"diskAvailableReported": "Disponible (déclarée)",
- "diskFree": "Libre",
"diskFreeReported": "Libre (déclarée)",
"diskMetricsUnavailable": "Les mesures disque ne sont pas disponibles dans Docker Desktop ou les environnements virtualisés.",
"applyRecommended": "Utiliser la recommandation",
@@ -714,17 +746,12 @@
"capacityRequiredForAvailable": "Entrez une capacité totale avant l'espace disponible.",
"availableExceedsCapacity": "L'espace disponible ne peut excéder la capacité totale.",
"storageUsage": "Usage du stockage",
- "storageByEvent": "Stockage par événement",
- "storageManagement": "Gestion du stockage",
- "storageManagementHelp": "Envisagez d'archiver ou supprimer d'anciens événements pour libérer de l'espace.",
- "noEventsUsingStorage": "Aucun événement n'utilise de stockage",
"unlimited": "Illimité"
},
"security": {
"title": "Sécurité",
"passwordSettings": "Paramètres de mot de passe",
"minPasswordLength": "Longueur minimale du mot de passe",
- "minPasswordLengthHelp": "Nombre minimum de caractères pour les galeries",
"passwordComplexity": "Complexité du mot de passe",
"passwordComplexityHelp": "Niveau de sécurité requis",
"complexitySimple": "Simple (6+ car., n'importe quel texte)",
@@ -733,7 +760,6 @@
"complexityVeryStrong": "Très Fort (12+ car., tous types de caractères)",
"sessionAuth": "Session et Authentification",
"sessionTimeout": "Expiration de session (minutes)",
- "sessionTimeoutHelp": "Expiration de la session admin",
"maxLoginAttempts": "Tentatives de connexion max",
"maxLoginAttemptsHelp": "Échecs autorisés par IP avant blocage",
"attemptWindowMinutes": "Fenêtre de tentative (minutes)",
@@ -744,11 +770,8 @@
"recaptchaSettings": "Paramètres reCAPTCHA",
"enableRecaptcha": "Activer reCAPTCHA sur les formulaires",
"siteKey": "Clé du site",
- "siteKeyHelp": "Votre clé publique reCAPTCHA v2",
"secretKey": "Clé secrète",
- "secretKeyHelp": "Votre clé secrète reCAPTCHA v2 (garder privé)",
"recaptchaHelp": "Obtenez vos clés reCAPTCHA sur",
- "saveSettings": "Enregistrer les paramètres de sécurité",
"saveSecuritySettings": "Enregistrer les paramètres de sécurité"
},
"categories": {
@@ -790,8 +813,6 @@
"missingDimensions": "Dimensions manquantes",
"repairButton": "Réparer les dimensions",
"repairing": "Réparation...",
- "alreadyRunning": "La réparation est déjà en cours",
- "started": "Réparation lancée pour {{count}} photos",
"noneToRepair": "Toutes les photos ont déjà leurs dimensions",
"resultSuccess": "Dernière réparation : {{success}} mis à jour, {{failed}} échecs",
"description": "Complète les dimensions manquantes (largeur/hauteur) pour les photos anciennes. Requis pour les mises en page Masonry et Mosaic."
@@ -809,11 +830,13 @@
"sendTest": "Envoyer un e-mail test",
"saved": "Paramètres enregistrés",
"saveError": "Échec de l'enregistrement",
- "emailSent": "E-mail de notification envoyé à {{count}} destinataires",
"emailFailed": "Échec de l'envoi",
"checkSuccess": "Notification envoyée pour la nouvelle version",
"checkNoAction": "Aucune notification nécessaire : {{reason}}",
- "checkError": "Échec de la vérification"
+ "checkError": "Échec de la vérification",
+ "emailSent_many": "Notification envoyée à {{count}} destinataires",
+ "emailSent_one": "Notification envoyée à {{count}} destinataire",
+ "emailSent_other": "Notification envoyée à {{count}} destinataires"
},
"events": {
"title": "Création d'événement",
@@ -835,7 +858,13 @@
"expirationWarning": "Sans expiration, les galeries restent actives jusqu'à archivage manuel",
"saveSettings": "Enregistrer les paramètres d'événement",
"noteTitle": "Note",
- "noteText": "Ces paramètres n'affectent que les nouveaux événements. Par défaut, tous les champs sont requis."
+ "noteText": "Ces paramètres n'affectent que les nouveaux événements. Par défaut, tous les champs sont requis.",
+ "defaultRequirePassword": "Exiger un mot de passe par défaut",
+ "defaultRequirePasswordHelp": "Pré-cocher « Exiger un mot de passe » lors de la création d'événements. Désactivez pour créer plus rapidement des galeries publiques.",
+ "showGalleryFilterBar": "Afficher la barre de filtres dans les galeries",
+ "showGalleryFilterBarHelp": "Affiche la recherche par nom de fichier et les contrôles de tri au-dessus des galeries en grille. Désactivez pour un affichage plus épuré.",
+ "enablePhoneField": "Activer le champ numéro de téléphone",
+ "enablePhoneFieldHelp": "Ajoute un champ numéro de téléphone optionnel au formulaire d'événement. Utile pour les automatisations comme la livraison WhatsApp via n8n. Toujours facultatif même quand activé."
},
"imageSecurity": {
"title": "Protection de l'image",
@@ -908,11 +937,6 @@
"format": "Format",
"fit": "Mode d'ajustement",
"fitHelp": "Comment l'image est redimensionnée. 'Cover' remplit, 'Contain' ajuste dans le cadre.",
- "fit_cover": "Cover (remplir et couper)",
- "fit_contain": "Contain (ajuster à l'intérieur)",
- "fit_fill": "Fill (étirer)",
- "fit_inside": "Inside (réduire pour ajuster)",
- "fit_outside": "Outside (étendre pour couvrir)",
"regenerateTitle": "Régénérer les vignettes",
"regenerateHelp": "Lancez ceci après avoir changé les réglages. S'exécute en arrière-plan.",
"regenerateButton": "Régénérer toutes les vignettes",
@@ -975,11 +999,57 @@
"deviceTypes": "Types d'appareils",
"privacy": "Vie privée",
"privacyText": "Les adresses IP sont hachées. Rétention : 90 jours."
- }
+ },
+ "groups": {
+ "general": "Général",
+ "display": "Affichage",
+ "privacySecurity": "Confidentialité & Sécurité",
+ "integrations": "Intégrations",
+ "system": "Système"
+ },
+ "apiTokens": {
+ "title": "Jetons API",
+ "createError": "Échec de la création du jeton",
+ "revoked": "Jeton révoqué",
+ "subtitle": "Jetons porteur longue durée pour la surface publique /api/v1 — intégrations n8n, apps personnalisées, scripts. Les jetons agissent en tant qu'administrateur qui les a créés, limités aux portées choisies.",
+ "copyNow": "Copiez ce jeton maintenant — il ne sera plus affiché.",
+ "copied": "Copié",
+ "copyFailed": "Échec de la copie",
+ "name": "Nom",
+ "namePlaceholder": "ex. : n8n production",
+ "scopes": "Portées",
+ "generate": "Générer un jeton",
+ "scopeHint": "admin > écriture > lecture. Un jeton lecture seule ne peut pas modifier, même si son propriétaire est super_admin.",
+ "existing": "Jetons existants",
+ "lastUsed": "Dernière utilisation",
+ "created": "Créé",
+ "status": "Statut",
+ "statusRevoked": "Révoqué",
+ "statusExpired": "Expiré",
+ "statusActive": "Actif",
+ "confirmRevoke": "Révoquer ce jeton ? Cette action est irréversible.",
+ "revoke": "Révoquer",
+ "empty": "Aucun jeton pour l'instant. Générez-en un ci-dessus pour commencer."
+ },
+ "webhooks": {
+ "title": "Webhooks",
+ "subtitle": "Envoyez des notifications POST à votre URL dès qu'un événement se produit — galerie publiée, photo téléversée, événement archivé, etc. Signé avec HMAC-SHA256 dans l'en-tête X-PicPeak-Signature.",
+ "piiNotice": "Les données event.* incluent les coordonnées du client (nom, e-mail, téléphone) et le jeton de partage de la galerie si vous les avez enregistrés. Ne pointez les webhooks que vers des récepteurs de confiance.",
+ "copyNow": "Copiez ce secret de signature maintenant — il ne sera plus affiché.",
+ "name": "Nom",
+ "url": "URL du récepteur",
+ "events": "S'abonner aux événements",
+ "filter": "Filtre (JSON, facultatif)",
+ "template": "Modèle (facultatif)",
+ "create": "Créer un webhook",
+ "existing": "Webhooks existants",
+ "empty": "Aucun webhook pour l'instant. Créez-en un ci-dessus pour recevoir des notifications."
+ },
+ "sectionLabel": "Section des paramètres",
+ "navAriaLabel": "Navigation des paramètres"
},
"analytics": {
"title": "Tableau de bord analytique",
- "titleSimple": "Analytique",
"subtitle": "Suivi des performances et de l'engagement",
"detailedSubtitle": "Analyses détaillées via Umami",
"loadingAnalytics": "Chargement...",
@@ -987,7 +1057,7 @@
"fullDashboard": "Tableau de bord complet",
"refresh": "Actualiser",
"last7Days": "7 derniers jours",
- "last30Days": "30 derniers jours",
+ "last30Days": "30 derniers jours",
"last90Days": "90 derniers jours",
"pageViews": "Vues de pages",
"uniqueVisitors": "Visiteurs uniques",
@@ -1007,13 +1077,10 @@
"totalPhotos": "Total photos",
"activeEvents": "Événements actifs",
"notConfigured": "Umami non configuré",
- "configureInstructions": "Configurez Umami dans vos variables d'environnement.",
- "noData": "Aucune donnée disponible",
- "percentChange": "{{percent}}% par rapport à la période précédente"
+ "configureInstructions": "Configurez Umami dans vos variables d'environnement."
},
"branding": {
"title": "Identité et Thèmes",
- "titleFull": "Personnalisation de marque",
"subtitle": "Personnalisez l'apparence de vos galeries",
"loadingBranding": "Chargement...",
"themeAndStyle": "Thème et Style",
@@ -1025,18 +1092,14 @@
"supportEmail": "E-mail de support",
"supportEmailHelp": "Contact pour l'aide aux invités",
"footerText": "Texte de pied de page",
- "footerTextHelp": "Affiché en bas des galeries",
"logo": "Logo",
- "currentLogo": "Logo actuel",
"uploadLogo": "Téléverser logo",
- "removeLogo": "Retirer logo",
"logoHelp": "Taille recommandée : 200x60px, PNG ou JPEG",
- "favicon": "Favicon",
+ "favicon": "Favicon",
"currentFavicon": "Favicon actuel",
"uploadFavicon": "Téléverser favicon",
"removeFavicon": "Retirer favicon",
"faviconHelp": "Format PNG ou ICO, 32x32px recommandé",
- "watermark": "Filigrane",
"watermarkSettings": "Paramètres filigrane",
"enableWatermarks": "Activer les filigranes",
"watermarkHelp": "Ajoute le nom de votre entreprise sur les photos téléchargées",
@@ -1053,11 +1116,7 @@
"watermarkSize": "Taille filigrane",
"theme": "Thème",
"galleryTheme": "Thème galerie",
- "themeCustomization": "Personnalisation thème",
- "selectPreset": "Sélectionner un préréglage",
"colors": "Couleurs",
- "primaryColor": "Couleur primaire",
- "secondaryColor": "Couleur secondaire",
"accentColor": "Couleur d'accentuation",
"backgroundColor": "Couleur de fond",
"textColor": "Couleur de texte",
@@ -1066,27 +1125,13 @@
"colorModeDark": "Sombre",
"colorModeAuto": "Auto",
"colorModeHelp": "Auto suit les préférences système de l'invité.",
- "customCSS": "CSS personnalisé",
"preview": "Aperçu",
- "previewInNewTab": "Aperçu (nouvel onglet)",
- "reset": "Réinitialiser",
"saveChanges": "Enregistrer",
"applyLivePreview": "Appliquer immédiatement (Aperçu direct)",
"eventSpecificThemes": "Thèmes spécifiques par événement",
"eventThemesInfo": "Vous pouvez surcharger ces paramètres globaux pour chaque événement.",
"themePresets": "Préréglages de thème",
"galleryLayout": "Mise en page",
- "layoutDescriptions": {
- "grid": "Grille classique, tailles uniformes",
- "masonry": "Style Pinterest, hauteurs variables",
- "carousel": "Diaporama plein écran",
- "timeline": "Photos triées par date",
- "hero": "Image mise en avant avec grille en dessous",
- "mosaic": "Mosaïque artistique, tailles mixtes",
- "justified": "Lignes justifiées préservant les ratios",
- "gallery-premium": "Thème clair élégant avec hero et masonry (Beta)",
- "gallery-story": "Thème sombre cinématique avec sections (Beta)"
- },
"layoutSettings": "Paramètres de mise en page",
"photoSpacing": "Espacement des photos",
"spacing": {
@@ -1134,16 +1179,6 @@
"center": "Centré",
"justify": "Justifié (étiré)"
},
- "showHeroSection": "Afficher la section Hero",
- "showHeroSectionHint": "Affiche une image principale au-dessus de la galerie",
- "heroHeight": "Hauteur section Hero",
- "heroHeightOptions": {
- "small": "Petit (40-50%)",
- "medium": "Moyen (50-70%)",
- "large": "Grand (60-80%)"
- },
- "heroOverlayOpacity": "Opacité superposition Hero",
- "heroOverlayHint": "Assombrit l'image pour la lisibilité du texte",
"typographyAndStyle": "Typographie et Style",
"bodyFont": "Police de corps",
"headingFont": "Police de titre",
@@ -1189,8 +1224,6 @@
},
"resetToDefault": "Réinitialiser",
"applyTheme": "Appliquer le thème",
- "customTheme": "Thème personnalisé",
- "customizeTheme": "Personnaliser le thème",
"saveTheme": "Enregistrer le thème",
"previewLayout": "Aperçu mise en page",
"livePreview": "Aperçu direct",
@@ -1208,9 +1241,6 @@
"logoMaxHeight": "Hauteur maximale (pixels)",
"logoMaxHeightHelp": "Hauteur personnalisée (20-200 pixels)",
"logoPosition": "Position du logo dans l'en-tête",
- "positionLeft": "Gauche",
- "positionCenter": "Centre",
- "positionRight": "Droite",
"logoDisplayMode": "Mode d'affichage",
"logoOnly": "Logo uniquement",
"textOnly": "Nom d'entreprise uniquement",
@@ -1221,27 +1251,8 @@
"showLogoInHeroHelp": "Afficher le logo dans la section principale",
"headerStyle": "Style d'en-tête",
"headerStyleDescription": "Choisissez l'apparence de l'en-tête.",
- "headerStyleOptions": {
- "hero": "Image Hero",
- "standard": "Bannière standard",
- "minimal": "Minimaliste",
- "none": "Aucun en-tête"
- },
- "headerStyleDescriptions": {
- "hero": "Image pleine hauteur avec infos superposées",
- "standard": "Bannière classique avec détails",
- "minimal": "En-tête compact avec infos essentielles",
- "none": "Masquer complètement l'en-tête"
- },
"heroDividerStyle": "Style de séparateur",
"heroDividerDescription": "Forme de la transition sous l'image Hero.",
- "dividerOptions": {
- "wave": "Vague",
- "straight": "Droit",
- "angle": "Angle",
- "curve": "Courbe",
- "none": "Aucun"
- },
"controlsStyle": "Style des contrôles",
"controlsStyleDescription": "Affichage des filtres et contrôles.",
"controlsStyleOptions": {
@@ -1252,15 +1263,55 @@
"classic": "Barre de filtres sous l'en-tête",
"sidebar": "Bouton menu ouvrant un volet latéral"
},
- "controlsStyleHeroWarning": "La barre latérale est recommandée pour les en-têtes Hero."
+ "controlsStyleHeroWarning": "La barre latérale est recommandée pour les en-têtes Hero.",
+ "logoSize": "Taille du logo",
+ "surfaceColor": "Surface",
+ "elevatedColor": "Élevé",
+ "borderColor": "Bordure",
+ "mutedTextColor": "Texte atténué",
+ "accentDarkColor": "Accent (rempli)",
+ "betaThumbnailWarningTitle": "Résolution de miniature faible détectée",
+ "betaThumbnailWarningText": "Vos miniatures font actuellement {{width}}×{{height}}px. Les thèmes bêta affichent les photos en plus grande taille et nécessitent au moins {{recommended}}×{{recommended}}px pour une bonne qualité. Augmentez les dimensions dans Paramètres > Miniatures et régénérez.",
+ "betaThumbnailWarningLink": "Aller aux paramètres de miniatures",
+ "thumbnailScale": "Échelle des miniatures",
+ "thumbnailScaleOptions": {
+ "xs": "XS — Plus de photos",
+ "sm": "SM — Beaucoup de photos",
+ "md": "MD — Par défaut",
+ "lg": "LG — Photos plus grandes",
+ "xl": "XL — Photos les plus grandes"
+ },
+ "thumbnailScaleHint": "Ajuste le nombre de colonnes par rapport à la grille de base",
+ "syncFromBranding": "Synchroniser depuis la charte graphique",
+ "forceColorMode": "Forcer le mode couleur",
+ "forceColorModeHelp": "Verrouille l'ensemble du site admin et public en mode sombre ou clair. Le bouton de basculement sombre/clair est masqué dès qu'un verrouillage est actif.",
+ "forceColorModeNone": "Pas de forçage (choix de l'utilisateur)",
+ "forceColorModeDark": "Forcer le mode sombre",
+ "forceColorModeLight": "Forcer le mode clair",
+ "colorGroupSurfaces": "Surfaces",
+ "colorGroupSurfacesHelp": "Les couches neutres derrière votre contenu. L'arrière-plan est le plus en retrait ; Surface et Élevé s'empilent au-dessus.",
+ "backgroundColorHelp": "La page elle-même — arrière-plan de chaque galerie, page admin et page CMS.",
+ "surfaceColorHelp": "Cartes, barre latérale, en-tête et navigation. La première couche au-dessus de l'arrière-plan.",
+ "elevatedColorHelp": "Panneaux flottant au-dessus des cartes : espaces réservés aux images, lignes au survol, en-têtes modaux, blocs de code.",
+ "borderColorHelp": "Séparateurs, lignes de grille, contours de cartes, bordures d'inputs.",
+ "colorGroupText": "Texte",
+ "colorGroupTextHelp": "Couleurs de texte en avant-plan. Primaire pour tout ce sur quoi les lecteurs se concentrent ; Secondaire pour le texte d'accompagnement.",
+ "textColorHelp": "Titres, corps de texte, cellules de tableau, valeurs d'inputs, étiquettes de navigation — la couleur principale du texte.",
+ "mutedTextColorHelp": "Légendes, texte d'aide sous les inputs, en-têtes de colonnes, liens de pied de page, dates et métadonnées.",
+ "colorGroupAccent": "Accent",
+ "colorGroupAccentHelp": "Couleurs de marque qui mettent en valeur les éléments interactifs. Utilisez une paire de couleurs fortes — Accent pour les contours/texte, Accent (rempli) pour les boutons remplis.",
+ "accentColorHelp": "Liens, icônes, anneaux de focus, états de survol sur les boutons principaux. Doit être lisible sur l'arrière-plan et la surface.",
+ "accentDarkColorHelp": "Boutons d'appel à l'action remplis, arrière-plan de l'élément actif de la barre latérale, badges et étiquettes. Doit offrir assez de contraste pour un texte blanc lisible.",
+ "cssTemplate": "Modèle CSS",
+ "cssTemplateDescription": "Sélectionnez un modèle CSS prédéfini pour appliquer un style global à cette galerie. Les modèles peuvent être gérés dans Paramètres > Modèles CSS.",
+ "noTemplate": "Aucun modèle",
+ "noTemplateDescription": "Utiliser uniquement les paramètres de thème sans modèle CSS",
+ "templateSlot": "Emplacement {{slot}}",
+ "eventCustomCSS": "CSS personnalisé par événement"
},
"admin": {
"title": "Panneau d'administration",
- "welcome": "Bon retour, {{name}}",
"recentActivity": "Activité récente",
- "systemStatus": "Statut système",
- "totalEvents": "Total événements",
- "activeGalleries": "Galeries actives",
"storageUsed": "Stockage utilisé",
"totalPhotos": "Total photos",
"storagePercent": "{{percent}}% de la limite {{limit}}",
@@ -1270,9 +1321,6 @@
"archivedEvents": "Événements archivés",
"systemHealth": "Santé système",
"health": {
- "healthy": "Sain",
- "warning": "Attention",
- "error": "Erreur",
"checking": "Vérification..."
},
"updates": {
@@ -1285,9 +1333,7 @@
"beta": "BETA",
"viewReleaseNotes": "Notes de version",
"updateAvailableShort": "v{{version}} disponible",
- "checkForUpdates": "Vérifier les mises à jour",
"upToDate": "À jour",
- "lastChecked": "Vérifié à : {{time}}",
"updateNow": "Mettre à jour",
"updateDialog": {
"title": "Mettre à jour PicPeak",
@@ -1301,8 +1347,6 @@
}
},
"notifications": "Notifications",
- "viewAllNotifications": "Toutes les notifications",
- "noNotifications": "Aucune nouvelle notification",
"markAllRead": "Tout marquer comme lu",
"clearAll": "Tout effacer",
"close": "Fermer",
@@ -1312,16 +1356,13 @@
"eventArchived": "Événement \"{{eventName}}\" archivé",
"eventUpdated": "Événement \"{{eventName}}\" mis à jour",
"eventDeleted": "Événement \"{{eventName}}\" supprimé",
- "photosUploaded": "{{count}} photos téléversées dans \"{{eventName}}\"",
"photoDeleted": "Photo supprimée de \"{{eventName}}\"",
- "photosBulkDeleted": "{{count}} photos supprimées de \"{{eventName}}\"",
"eventExpiring": "L'événement \"{{eventName}}\" expire dans {{days}} jours",
"eventExpired": "L'événement \"{{eventName}}\" a expiré",
"passwordChanged": "Mot de passe changé par {{actorName}}",
"passwordReset": "Réinitialisation du mot de passe pour \"{{eventName}}\"",
"settingsUpdated": "Paramètres {{type}} mis à jour",
"emailTemplateUpdated": "Modèle d'e-mail \"{{template}}\" mis à jour",
- "bulkDownload": "{{count}} photos téléchargées depuis \"{{eventName}}\"",
"storageWarning": "Usage stockage à {{percentage}}%",
"adminLogout": "Déconnexion admin {{actorName}}",
"categoryCreated": "Catégorie \"{{name}}\" créée pour \"{{eventName}}\"",
@@ -1338,29 +1379,26 @@
"archiveDeleted": "Archive supprimée pour \"{{eventName}}\"",
"archiveRestored": "Archive restaurée pour \"{{eventName}}\"",
"systemActivity": "Activité système : {{type}}",
- "adminProfileUpdated": "Profil admin mis à jour par {{actorName}}"
+ "adminProfileUpdated": "Profil admin mis à jour par {{actorName}}",
+ "photosUploaded_many": "{{count}} photos téléversées dans « {{eventName}} »",
+ "photosUploaded_one": "{{count}} photo téléversée dans « {{eventName}} »",
+ "photosUploaded_other": "{{count}} photos téléversées dans « {{eventName}} »",
+ "photosBulkDeleted_many": "{{count}} photos supprimées de « {{eventName}} »",
+ "photosBulkDeleted_one": "{{count}} photo supprimée de « {{eventName}} »",
+ "photosBulkDeleted_other": "{{count}} photos supprimées de « {{eventName}} »",
+ "bulkDownload_many": "{{count}} photos téléchargées depuis « {{eventName}} »",
+ "bulkDownload_one": "{{count}} photo téléchargée depuis « {{eventName}} »",
+ "bulkDownload_other": "{{count}} photos téléchargées depuis « {{eventName}} »"
},
"notificationToasts": {
"markedAllRead": "Toutes les notifications sont lues",
- "clearedAll": "{{count}} notifications effacées",
- "profileUpdated": "Profil admin mis à jour"
+ "clearedAll_many": "{{count}} notifications effacées",
+ "clearedAll_one": "{{count}} notification effacée",
+ "clearedAll_other": "{{count}} notifications effacées"
},
- "markAsRead": "Marquer comme lu",
- "markAllAsRead": "Tout marquer comme lu",
- "notificationSettings": "Paramètres de notification",
"changePassword": "Changer le mot de passe",
"darkMode": "Passer au mode sombre",
"lightMode": "Passer au mode clair",
- "accountSettings": {
- "title": "Compte admin",
- "description": "Modifier les accès de connexion à PicPeak.",
- "username": "Nom d'utilisateur",
- "usernamePlaceholder": "Admin",
- "email": "E-mail",
- "emailPlaceholder": "admin@exemple.com",
- "updateButton": "Mettre à jour le profil"
- },
- "profileUpdateError": "Impossible de mettre à jour le profil. Réessayez.",
"loadingDashboard": "Chargement du tableau de bord...",
"activeEvents": "Événements actifs",
"expiringSoon": "Expire bientôt",
@@ -1371,103 +1409,92 @@
"dashboardSubtitle": "Bon retour ! Voici l'état de vos galeries.",
"eventsExpiringSoon": "Événements expirant bientôt",
"noEventsExpiring": "Aucun événement n'expire dans les 7 prochains jours",
- "daysLeft": "{{count}} jour restant",
- "daysLeft_plural": "{{count}} jours restants",
- "viewAllExpiringEvents": "Voir les {{count}} événements expirants",
"noRecentActivity": "Aucune activité récente",
- "viewAllActivity": "Toute l'activité",
- "quickActions": "Actions rapides",
- "viewArchives": "Voir les archives",
- "analytics": "Analytique",
- "activities": {
- "event_created": "Nouvel événement : {{eventName}}",
- "photos_uploaded": "{{count}} photos téléversées : {{eventName}}",
- "event_archived": "Événement archivé : {{eventName}}",
- "archive_restored": "Archive restaurée : {{eventName}}",
- "archive_deleted": "Archive supprimée : {{eventName}}",
- "archive_downloaded": "Archive téléchargée : {{eventName}}",
- "email_config_updated": "Configuration e-mail mise à jour",
- "email_template_updated": "Modèle d'e-mail mis à jour : {{template}}",
- "branding_updated": "Identité visuelle mise à jour",
- "theme_updated": "Thème mis à jour",
- "bulk_download": "{{count}} photos téléchargées : {{eventName}}",
- "gallery_password_entry": "Mot de passe saisi pour {{eventName}}",
- "expiration_warning_viewed": "Avertissement d'expiration vu pour {{eventName}}",
- "feedback_settings_updated": "Paramètres d'avis mis à jour",
- "feedback_moderated": "Avis modéré",
- "feedback_deleted": "Avis supprimé",
- "photo_like": "Photo aimée dans {{eventName}}",
- "photo_favorite": "Photo mise en favoris dans {{eventName}}",
- "photo_rating": "Photo notée dans {{eventName}}",
- "photo_comment": "Commentaire sur photo dans {{eventName}}",
- "guest_feedback_like": "Un invité a aimé une photo dans {{eventName}}",
- "guest_feedback_favorite": "Un invité a mis une photo en favoris dans {{eventName}}",
- "guest_feedback_rating": "Un invité a noté une photo dans {{eventName}}",
- "guest_feedback_comment": "Un invité a commenté une photo dans {{eventName}}",
- "word_filter_added": "Filtre de mot ajouté",
- "external_import_completed": "Import externe terminé ({{imported}} importés, {{skipped}} ignorés)",
- "bulk_archive_completed": "Archivage groupé terminé",
- "event_activated": "Événement activé : {{eventName}}",
- "event_deactivated": "Événement désactivé : {{eventName}}",
- "photo_deleted": "Photo supprimée de {{eventName}}",
- "photos_bulk_deleted": "{{count}} photos supprimées de {{eventName}}",
- "settings_updated": "Paramètres mis à jour",
- "event_updated": "Événement mis à jour : {{eventName}}",
- "event_renamed": "Événement renommé : {{eventName}}",
- "event_deleted": "Événement supprimé : {{eventName}}",
- "password_changed": "Mot de passe changé",
- "email_resent": "E-mail de création renvoyé pour : {{eventName}}",
- "category_created": "Catégorie créée : {{categoryName}}",
- "category_updated": "Catégorie mise à jour : {{categoryName}}",
- "category_deleted": "Catégorie supprimée : {{categoryName}}",
- "general_settings_updated": "Paramètres généraux mis à jour",
- "favicon_uploaded": "Favicon téléversé",
- "analytics_settings_updated": "Paramètres analytiques mis à jour",
- "cms_page_updated": "Page CMS mise à jour : {{page}}",
- "security_settings_updated": "Paramètres de sécurité mis à jour",
- "password_reset": "Mot de passe réinitialisé pour : {{eventName}}",
- "admin_logout": "Déconnexion admin {{actorName}}",
- "system_activity": "Activité système : {{type}}",
- "unknown": "Activité inconnue"
+ "events": {
+ "tabs": {
+ "guests": "Invités"
+ }
},
- "userManagement": "Gestion utilisateurs",
- "inviteUser": "Inviter",
- "pendingInvitations": "Invitations en attente",
- "roles": {
- "super_admin": "Super Admin",
- "admin": "Admin",
- "editor": "Éditeur",
- "viewer": "Spectateur"
+ "daysLeft_many": "{{count}} jours restants",
+ "daysLeft_one": "{{count}} jour restant",
+ "daysLeft_other": "{{count}} jours restants",
+ "viewAllExpiringEvents_many": "Voir tous les {{count}} événements expirant",
+ "viewAllExpiringEvents_one": "Voir le {{count}} événement expirant",
+ "viewAllExpiringEvents_other": "Voir tous les {{count}} événements expirant",
+ "guests": {
+ "loading": "Chargement…",
+ "aggregate": {
+ "empty": "Aucune sélection d'invité pour l'instant.",
+ "description": "Photos triées par le nombre d'invités distincts qui les ont aimées ou marquées en favori."
+ },
+ "inviteCreated": "Invitation créée",
+ "inviteCreateError": "Échec de la création de l'invitation",
+ "inviteRevoked": "Invitation révoquée",
+ "inviteRevokeError": "Échec de la révocation de l'invitation",
+ "invitesTitle": "Invitations des invités",
+ "createInvite": "Créer une invitation",
+ "inviteName": "Nom de l'invité",
+ "inviteEmail": "E-mail (facultatif)",
+ "generateInvite": "Générer un lien d'invitation",
+ "existingInvites": "Invitations existantes",
+ "noInvites": "Aucune invitation pour l'instant",
+ "copyLink": "Copier le lien",
+ "revokeInvite": "Révoquer",
+ "deletedToast": "Invité supprimé",
+ "deletedError": "Échec de la suppression de l'invité",
+ "mergedToast": "Invités fusionnés",
+ "mergedError": "Échec de la fusion des invités",
+ "forgetGuestConfirm": "Supprimer cet invité ? Ses sélections seront anonymisées mais conservées dans les totaux agrégés.",
+ "exportError": "Échec de l'export",
+ "mergeSelectAtLeastTwo": "Sélectionnez au moins 2 invités à fusionner",
+ "mergeConfirm_many": "Fusionner {{count}} invités avec {{name}} ? Cette action est irréversible.",
+ "mergeConfirm_one": "Fusionner {{count}} invité avec {{name}} ? Cette action est irréversible.",
+ "mergeConfirm_other": "Fusionner {{count}} invités avec {{name}} ? Cette action est irréversible.",
+ "backToList": "Retour à la liste",
+ "title": "Invités",
+ "mergeSelected_many": "{{count}} sélectionnés",
+ "mergeSelected_one": "{{count}} sélectionné",
+ "mergeSelected_other": "{{count}} sélectionnés",
+ "mergeNow": "Fusionner la sélection",
+ "aggregateView": "Par popularité",
+ "mergeMode": "Fusionner",
+ "exportAll": "Tout exporter",
+ "empty": "Aucun invité inscrit pour l'instant.",
+ "columns": {
+ "name": "Nom",
+ "email": "E-mail",
+ "likes": "J'aime",
+ "favorites": "Favoris",
+ "comments": "Commentaires",
+ "ratings": "Notes",
+ "lastSeen": "Dernière visite"
+ },
+ "view": "Voir les détails",
+ "export": "Exporter",
+ "forgetGuest": "Supprimer l'invité",
+ "loadingDetail": "Chargement des sélections…",
+ "detail": {
+ "noComments": "Aucun commentaire",
+ "empty": "Aucune sélection dans cette catégorie"
+ }
},
- "userStatus": {
- "active": "Actif",
- "inactive": "Inactif"
- },
- "inviteForm": {
- "email": "Adresse e-mail",
- "role": "Rôle",
- "send": "Envoyer l'invitation"
- },
- "acceptInvite": {
- "title": "Accepter l'invitation admin",
- "username": "Nom d'utilisateur",
- "password": "Mot de passe",
- "submit": "Créer le compte"
+ "photos": {
+ "hiddenSuccess": "Photos masquées aux invités",
+ "hideSelected": "Masquer",
+ "visibleSuccess": "Photos visibles aux invités",
+ "showSelected": "Afficher",
+ "hidden": "Masqué",
+ "processingStatus": "En cours…",
+ "processingFailed": "Échoué",
+ "retryQueued": "Nouvelle tentative en file d'attente"
}
},
- "permissions": {
- "insufficient": "Permissions insuffisantes pour cette action",
- "viewOnly": "Lecture seule"
- },
"acceptInvitation": {
"title": "Accepter l'invitation",
"subtitle": "Créez votre compte administrateur",
"validating": "Validation de l'invitation...",
"invalidToken": "Invitation invalide",
"invalidTokenMessage": "Ce lien est invalide ou a expiré. Contactez l'administrateur.",
- "expiredToken": "Invitation expirée",
- "expiredTokenMessage": "Cette invitation a expiré.",
- "alreadyUsed": "Invitation déjà utilisée",
"alreadyUsedMessage": "Cette invitation a déjà servi à créer un compte.",
"invitedAs": "Vous avez été invité en tant que",
"expiresAt": "L'invitation expire",
@@ -1494,7 +1521,6 @@
"strong": "Robuste"
},
"createAccount": "Créer le compte",
- "creating": "Création du compte...",
"success": "Compte créé !",
"successMessage": "Compte créé avec succès. Vous pouvez maintenant vous connecter.",
"redirecting": "Redirection vers la connexion dans {{seconds}}...",
@@ -1509,23 +1535,14 @@
"usernameTooLong": "Maximum 50 caractères",
"usernameInvalid": "Caractères invalides",
"passwordRequired": "Mot de passe requis",
- "passwordTooShort": "Minimum 12 caractères",
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
"confirmPasswordRequired": "Veuillez confirmer le mot de passe",
- "usernameTaken": "Ce nom d'utilisateur est déjà pris",
- "emailTaken": "Un compte existe déjà avec cet e-mail",
"genericError": "Échec de la création. Réessayez."
}
},
"errors": {
- "notFound": "Non trouvé",
"galleryNotFound": "Galerie non trouvée",
"galleryNotFoundMessage": "Cette galerie n'existe pas ou a été supprimée.",
- "galleryArchived": "Galerie archivée",
- "galleryArchivedMessage": "Cette galerie a été archivée et n'est plus accessible.",
- "unauthorized": "Non autorisé",
- "forbidden": "Interdit",
- "serverError": "Erreur serveur",
"somethingWentWrong": "Un problème est survenu",
"tryAgainLater": "Veuillez réessayer plus tard",
"refreshPage": "Actualiser la page",
@@ -1535,10 +1552,9 @@
"errorDetails": "Détails de l'erreur",
"requiredFields": "Veuillez remplir tous les champs requis",
"enterTestEmail": "Veuillez entrer une adresse e-mail de test",
- "failedToCreateEvent": "Échec de la création de l'événement",
"eventCreationFailed": "Échec de la création de l'événement",
- "networkError": "Erreur réseau. Vérifiez votre connexion.",
- "sessionExpired": "Session expirée. Veuillez vous reconnecter."
+ "noShareLink": "Aucun lien de partage disponible",
+ "copyFailed": "Échec de la copie du lien"
},
"validation": {
"eventNameRequired": "Nom de l'événement requis",
@@ -1549,14 +1565,15 @@
"passwordRequired": "Mot de passe requis",
"passwordMinLength": "Le mot de passe doit faire au moins 6 caractères",
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
- "passwordSecurityRequirements": "Le mot de passe ne respecte pas les critères de sécurité",
- "expirationRange": "L'expiration doit être entre 1 et 365 jours"
+ "expirationRange": "L'expiration doit être entre 1 et 365 jours",
+ "required": "Ce champ est obligatoire",
+ "expirationRequired": "La date d'expiration est obligatoire.",
+ "eventDateRequired": "La date de l'événement est obligatoire",
+ "passwordTooSimple": "Le mot de passe ne peut pas être composé uniquement de chiffres. Pensez à un format comme « 04.07.2025 »"
},
"legal": {
"impressum": "Mentions Légales",
- "datenschutz": "Politique de Confidentialité",
- "termsOfService": "Conditions Générales d'Utilisation",
- "cookiePolicy": "Politique de Cookies"
+ "datenschutz": "Politique de Confidentialité"
},
"toast": {
"saveSuccess": "Modifications enregistrées",
@@ -1565,9 +1582,6 @@
"deleteError": "Échec de la suppression",
"uploadSuccess": "Téléversement réussi",
"uploadError": "Échec du téléversement",
- "loginSuccess": "Connexion réussie",
- "loginError": "Échec de la connexion",
- "passwordChanged": "Mot de passe modifié",
"linkCopied": "Lien copié dans le presse-papier",
"eventCreated": "Événement créé",
"eventUpdated": "Événement mis à jour",
@@ -1575,14 +1589,10 @@
"settingsSaved": "Paramètres enregistrés",
"themeUpdated": "Thème mis à jour",
"brandingUpdated": "Identité visuelle mise à jour",
- "categoryAdded": "Catégorie ajoutée",
- "categoryDeleted": "Catégorie supprimée",
"categoryUpdated": "Catégorie mise à jour",
"emailConfigSaved": "Configuration e-mail enregistrée",
- "testEmailSent": "E-mail de test envoyé",
- "pageUpdated": "Page mise à jour",
- "archiveRestored": "Archive restaurée",
- "archiveDeleted": "Archive supprimée définitivement"
+ "brandingThemeMissing": "Aucun thème de charte graphique n'a encore été enregistré.",
+ "brandingPaletteSynced": "Palette synchronisée depuis la charte graphique."
},
"email": {
"title": "Configuration E-mail",
@@ -1590,28 +1600,9 @@
"loadingSettings": "Chargement...",
"smtpConfiguration": "Configuration SMTP",
"smtpHost": "Hôte SMTP",
- "smtpHostHelp": "Nom d'hôte du serveur e-mail",
- "smtpPort": "Port SMTP",
- "smtpPortHelp": "Généralement 587 (TLS), 465 (SSL) ou 25",
- "smtpSecure": "Utiliser SSL/TLS",
- "smtpSecureHelp": "Activer pour une transmission sécurisée",
- "smtpUsername": "Nom d'utilisateur SMTP",
- "smtpUsernameHelp": "Compte utilisé pour l'envoi",
- "smtpPassword": "Mot de passe SMTP",
- "smtpPasswordHelp": "Mot de passe du compte e-mail",
- "fromDetails": "Expéditeur",
"fromEmail": "E-mail expéditeur",
- "fromEmailHelp": "Adresse apparaissant comme expéditeur",
"fromName": "Nom expéditeur",
- "fromNameHelp": "Nom apparaissant comme expéditeur",
- "testConfiguration": "Tester la configuration",
- "testEmail": "E-mail de test",
- "testEmailHelp": "Envoyer un e-mail pour vérifier les paramètres",
- "sendTestEmail": "Envoyer l'e-mail test",
- "saveConfiguration": "Enregistrer la configuration",
"emailTemplates": "Modèles d'e-mails",
- "templateVariables": "Variables disponibles",
- "previewTemplate": "Aperçu du modèle",
"smtpSettings": "Paramètres SMTP",
"testEmailSuccess": "E-mail test envoyé",
"saveSmtpSettings": "Enregistrer SMTP",
@@ -1628,17 +1619,61 @@
"subjectLine": "Objet de l'e-mail",
"emailBody": "Corps de l'e-mail",
"preview": "Aperçu",
- "saveChanges": "Enregistrer",
"templates": "Modèles",
- "variableHelp": "Utilisez ces variables. Elles seront remplacées lors de l'envoi.",
"port": "Port",
"security": "Sécurité",
"username": "Utilisateur",
"password": "Mot de passe",
"enterPassword": "Saisir le mot de passe",
- "required": "requis",
"ignoreSslErrors": "Ignorer les erreurs de certificat SSL/TLS",
- "ignoreSslWarning": "Attention : Désactiver la vérification rend la connexion vulnérable aux attaques man-in-the-middle. N'activez ceci que si vous avez confiance en votre serveur SMTP."
+ "ignoreSslWarning": "Attention : Désactiver la vérification rend la connexion vulnérable aux attaques man-in-the-middle. N'activez ceci que si vous avez confiance en votre serveur SMTP.",
+ "syncedFromBranding": "Couleurs d'e-mail synchronisées depuis la charte graphique. Cliquez sur Enregistrer pour appliquer.",
+ "copiedFromLanguage": "Contenu copié depuis {{language}}",
+ "brandingTitle": "Charte graphique des e-mails",
+ "syncFromBranding": "Synchroniser depuis la charte graphique",
+ "brandingDescription": "Personnalisez les couleurs utilisées dans les modèles d'e-mails. Les modifications s'appliquent à la barre d'en-tête, aux boutons, aux liens et à l'arrière-plan du pied de page.",
+ "primaryColor": "Couleur principale",
+ "primaryColorHelp": "Barre d'en-tête, titres H2, fond des boutons, couleur des liens. Correspond à Charte graphique → Accent (rempli).",
+ "secondaryColor": "Arrière-plan du pied de page",
+ "secondaryColorHelp": "Arrière-plan de la barre de pied de page. Correspond à Charte graphique → Surface.",
+ "bodyBgColor": "Arrière-plan de la page",
+ "bodyBgColorHelp": "L'enveloppe autour de la carte e-mail — ce que le destinataire voit derrière l'e-mail. Correspond à Charte graphique → Arrière-plan.",
+ "containerBgColor": "Carte e-mail",
+ "containerBgColorHelp": "La carte blanche qui contient le contenu de l'e-mail. Correspond à Charte graphique → Surface.",
+ "listBgColor": "Panneau d'information",
+ "listBgColorHelp": "Arrière-plan des panneaux d'information à puces dans le corps de l'e-mail. Correspond à Charte graphique → Élevé.",
+ "bodyTextColor": "Texte du corps",
+ "bodyTextColorHelp": "Couleur des paragraphes et du texte en gras. Correspond à Charte graphique → Texte principal.",
+ "mutedTextColor": "Texte du pied de page",
+ "mutedTextColorHelp": "Texte du pied de page et ligne de copyright. Correspond à Charte graphique → Texte secondaire.",
+ "buttonTextColor": "Texte des boutons",
+ "buttonTextColorHelp": "Couleur du texte sur les boutons remplis. Doit bien contraster avec la couleur principale. Généralement blanc.",
+ "saveEmailColors": "Enregistrer les couleurs",
+ "save": "Enregistrer",
+ "noTranslation": "Pas encore de traduction",
+ "noTranslationYet": "Aucune traduction n'existe encore pour cette langue. Copiez depuis une langue existante pour commencer :",
+ "copyFrom": "Copier depuis",
+ "editor": {
+ "bold": "Gras",
+ "italic": "Italique",
+ "bulletList": "Liste à puces",
+ "numberedList": "Liste numérotée",
+ "blockquote": "Citation",
+ "link": "Ajouter un lien",
+ "horizontalRule": "Ligne horizontale",
+ "alignLeft": "Aligner à gauche",
+ "alignCenter": "Centrer",
+ "alignRight": "Aligner à droite",
+ "clearFormatting": "Effacer la mise en forme",
+ "undo": "Annuler",
+ "redo": "Rétablir",
+ "insertVariable": "Insérer une variable",
+ "visualMode": "Mode visuel",
+ "sourceMode": "Mode source",
+ "enterUrl": "Saisir une URL…",
+ "addLink": "Ajouter",
+ "cancel": "Annuler"
+ }
},
"cms": {
"title": "Pages CMS",
@@ -1652,11 +1687,22 @@
"pageTitle": "Titre de la page",
"pageContent": "Contenu de la page",
"pageTitlePlaceholder": "Titre...",
- "saveChanges": "Enregistrer",
"lastUpdated": "Dernière mise à jour :",
- "impressum": "Mentions Légales",
- "datenschutz": "Politique de Confidentialité",
- "pageUpdated": "Page mise à jour"
+ "pageUpdated": "Page mise à jour",
+ "externalUrlInvalid": "Doit être une URL https:// valide",
+ "logoUploaded": "Logo téléversé",
+ "logoCleared": "Logo supprimé",
+ "useExternalUrl": "Utiliser une URL externe",
+ "useExternalUrlHelp": "Redirige les visiteurs vers une page externe au lieu d'afficher le contenu interne. Le titre et le contenu internes sont conservés en secours.",
+ "externalUrl": "URL externe",
+ "externalUrlPlaceholder": "https://example.com/mentions-legales",
+ "externalUrlActive": "L'URL externe est active — le contenu interne est préservé mais non affiché aux visiteurs.",
+ "pageLogo": "Logo de la page",
+ "pageLogoHelp": "Facultatif. Si défini, remplace le logo de la charte graphique globale sur cette page.",
+ "noLogo": "pas de remplacement",
+ "replaceLogo": "Remplacer le logo",
+ "uploadLogo": "Téléverser un logo",
+ "clearLogo": "Utiliser le logo du site"
},
"eventTypes": {
"title": "Types d'événements",
@@ -1707,12 +1753,6 @@
}
},
"backup": {
- "external": {
- "warning": {
- "title": "Média externes exclus",
- "body": "Cette installation utilise des photos de /external-media. Ces originaux sont exclus des sauvegardes. La base de données et les vignettes sont sauvegardées."
- }
- },
"title": "Gestion des sauvegardes",
"subtitle": "Gérer les sauvegardes système et configurer les restaurations.",
"tabs": {
@@ -1733,22 +1773,12 @@
"actions": {
"runBackupNow": "Lancer maintenant",
"starting": "Démarrage...",
- "running": "Exécution...",
"testConnection": "Tester la connexion",
- "save": "Enregistrer",
"delete": "Supprimer",
"view": "Détails",
- "download": "Télécharger",
- "refresh": "Actualiser"
+ "download": "Télécharger"
},
"dashboard": {
- "backupHealth": "Santé des sauvegardes",
- "healthStatus": {
- "excellent": "Excellente",
- "good": "Bonne",
- "warning": "Attention",
- "critical": "Critique"
- },
"health": {
"title": "Santé Sauvegarde"
},
@@ -1767,7 +1797,6 @@
"backupStatus": "Statut",
"last": "Dernier",
"files": "fichiers",
- "minutes": "{{count}}m",
"active": "Actif",
"inactive": "Inactif",
"noBackupsYet": "Pas encore de sauvegardes"
@@ -1785,16 +1814,10 @@
},
"coverage": {
"title": "Contenu sauvegardé",
- "database": "Base de données",
- "photos": "Photos",
- "archives": "Archives",
- "systemFiles": "Fichiers système",
"included": "Inclus",
- "excluded": "Exclu",
- "optional": "Optionnel"
+ "excluded": "Exclu"
},
"storageDestination": "Destination",
- "nextScheduledBackup": "Prochaine planification",
"backupType": "Sauvegarde {{type}}",
"noDestinationSet": "Pas de destination"
},
@@ -1821,42 +1844,24 @@
"destinationPathHelp": "Répertoire local",
"destinationPathPlaceholder": "/chemin/vers/sauvegarde",
"rsyncHost": "Hôte distant",
- "rsyncHostHelp": "IP ou nom d'hôte SSH",
"rsyncHostPlaceholder": "sauvegarde.exemple.com",
"rsyncUser": "Utilisateur SSH",
- "rsyncUserHelp": "Pour la connexion SSH",
"rsyncUserPlaceholder": "backup-user",
"rsyncPath": "Chemin distant",
- "rsyncPathHelp": "Répertoire sur le serveur distant",
"rsyncPathPlaceholder": "/home/backup/photos",
"rsyncSshKey": "Clé privée SSH",
"rsyncSshKeyHelp": "Optionnel",
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
"s3Endpoint": "Point de terminaison S3",
"s3EndpointHelp": "URL API S3",
- "s3EndpointPlaceholder": "https://s3.amazonaws.com",
"s3Bucket": "Nom du Bucket",
- "s3BucketHelp": "Bucket de stockage",
- "s3BucketPlaceholder": "mon-bucket-backup",
"s3AccessKey": "ID Clé d'accès",
- "s3AccessKeyHelp": "Identifiant S3",
- "s3AccessKeyPlaceholder": "AKIA...",
"s3SecretKey": "Clé secrète S3",
- "s3SecretKeyHelp": "Secret S3",
- "s3SecretKeyPlaceholder": "wJal...",
- "s3Region": "Région",
- "s3RegionHelp": "Ex: us-east-1",
- "s3RegionPlaceholder": "us-east-1"
+ "s3Region": "Région"
},
"schedule": {
"title": "Calendrier",
"scheduleType": "Type de calendrier",
- "scheduleOptions": {
- "hourly": "Toutes les heures",
- "daily": "Quotidien",
- "weekly": "Hebdomadaire",
- "custom": "Expression Cron personnalisée"
- },
"options": {
"hourly": "Heure",
"daily": "Jour",
@@ -1878,9 +1883,7 @@
"archives": "Archives",
"archivesHelp": "Fichiers ZIP archivés",
"thumbnails": "Vignettes",
- "thumbnailsHelp": "Aperçus (peuvent être régénérés)",
- "tempFiles": "Fichiers temporaires",
- "tempFilesHelp": "En cours de traitement"
+ "thumbnailsHelp": "Aperçus (peuvent être régénérés)"
},
"advancedOptions": {
"title": "Options avancées",
@@ -1889,15 +1892,7 @@
"encryption": "Activer le chiffrement",
"encryptionHelp": "Sécurité supplémentaire",
"encryptionPassphrase": "Phrase secrète de chiffrement",
- "encryptionPassphraseHelp": "Nécessaire pour restaurer",
- "confirmPassphrase": "Confirmer la phrase secrète",
- "passphrasesDontMatch": "Les phrases ne correspondent pas"
- },
- "validation": {
- "requiredFields": "Remplissez les champs requis",
- "invalidCron": "Expression Cron invalide",
- "connectionTestFailed": "Échec du test de connexion",
- "connectionTestSuccess": "Connexion réussie !"
+ "encryptionPassphraseHelp": "Nécessaire pour restaurer"
},
"messages": {
"requiredFields": "Champs requis manquants",
@@ -1910,23 +1905,6 @@
},
"history": {
"searchPlaceholder": "Rechercher...",
- "allStatus": "Tous les statuts",
- "status": {
- "completed": "Terminé",
- "failed": "Échoué",
- "running": "En cours",
- "partial": "Partiel"
- },
- "deleteConfirm": "Supprimer la sauvegarde du {{date}} ?",
- "noBackups": "Aucune sauvegarde",
- "tableHeaders": {
- "date": "Date",
- "type": "Type",
- "status": "Statut",
- "size": "Taille",
- "duration": "Durée",
- "actions": "Actions"
- },
"columns": {
"status": "Statut",
"dateTime": "Date et Heure",
@@ -1935,37 +1913,6 @@
"duration": "Durée",
"actions": "Actions"
},
- "details": "Détails",
- "statistics": "Statistiques",
- "errors": "Erreurs",
- "backupDetails": {
- "backupId": "ID Sauvegarde",
- "startTime": "Heure de début",
- "endTime": "Heure de fin",
- "destination": "Destination",
- "filesProcessed": "Fichiers traités",
- "totalSize": "Taille totale",
- "compressionRatio": "Taux de compression",
- "errorLog": "Journal d'erreurs",
- "noErrors": "Aucune erreur détectée"
- },
- "pagination": {
- "showing": "Affichage {{from}}-{{to}} sur {{total}}",
- "previous": "Précédent",
- "next": "Suivant"
- },
- "filter": {
- "allStatus": "Tous",
- "completed": "Réussis",
- "failed": "Échoués",
- "running": "En cours",
- "partial": "Partiels"
- },
- "noBackupsFound": "Aucune sauvegarde trouvée",
- "backupsWillAppear": "Les sauvegardes apparaîtront ici",
- "messages": {
- "deleteSuccess": "Sauvegarde supprimée"
- },
"details": {
"backupDetails": "Détails de la sauvegarde",
"destination": "Destination",
@@ -1974,6 +1921,11 @@
"contentBackedUp": "Contenu sauvegardé",
"errorDetails": "Détails d'erreur",
"manifest": "Manifeste"
+ },
+ "pagination": {
+ "showing": "Affichage {{from}}-{{to}} sur {{total}}",
+ "previous": "Précédent",
+ "next": "Suivant"
}
},
"restore": {
@@ -2018,26 +1970,26 @@
"at": "à"
},
"restoreTypes": {
- "full": {
- "name": "Complète",
- "description": "Base, photos et archives",
- "warning": "Remplace toutes les données actuelles"
- },
- "database": {
- "name": "Base de données",
- "description": "Paramètres, événements, comptes",
- "warning": "La base actuelle sera remplacée"
- },
- "files": {
- "name": "Fichiers",
- "description": "Photos et archives uniquement",
- "warning": "Les fichiers existants peuvent être écrasés"
- },
- "selective": {
- "name": "Sélective",
- "description": "Éléments au choix",
- "warning": "Seuls les éléments choisis seront restaurés"
- }
+ "full": {
+ "name": "Complète",
+ "description": "Base, photos et archives",
+ "warning": "Remplace toutes les données actuelles"
+ },
+ "database": {
+ "name": "Base de données",
+ "description": "Paramètres, événements, comptes",
+ "warning": "La base actuelle sera remplacée"
+ },
+ "files": {
+ "name": "Fichiers",
+ "description": "Photos et archives uniquement",
+ "warning": "Les fichiers existants peuvent être écrasés"
+ },
+ "selective": {
+ "name": "Sélective",
+ "description": "Éléments au choix",
+ "warning": "Seuls les éléments choisis seront restaurés"
+ }
},
"options": {
"title": "Options de restauration",
@@ -2086,12 +2038,6 @@
"current": "Actuel",
"statusDetails": "Détails du statut",
"restoreLogs": "Journaux",
- "steps": {
- "completed": "Terminé",
- "running": "En cours",
- "failed": "Échoué",
- "pending": "En attente"
- },
"success": {
"title": "Restauration réussie",
"message": "Vos données ont été restaurées."
@@ -2104,20 +2050,13 @@
"starting": "Démarrage...",
"validating": "Validation...",
"startNewRestore": "Nouvelle restauration"
- },
- "messages": {
- "restoreStarted": "Restauration lancée"
}
},
"messages": {
"backupStarted": "Sauvegarde lancée",
"backupFailed": "Échec du lancement",
"configUpdated": "Configuration mise à jour",
- "configUpdateFailed": "Échec de mise à jour",
- "backupDeleted": "Sauvegarde supprimée",
- "deleteFailed": "Échec de suppression",
- "testEmailSent": "Connexion réussie !",
- "testEmailFailed": "La connexion a échoué"
+ "configUpdateFailed": "Échec de mise à jour"
}
},
"cssTemplates": {
@@ -2144,8 +2083,6 @@
"maintenance": {
"title": "Maintenance système",
"message": "Maintenance en cours. Nous revenons bientôt.",
- "expectedCompletion": "Heure de fin prévue :",
- "checkBackLater": "Réessayez plus tard",
"urgentMatters": "Pour une urgence, contactez"
},
"passwordChange": {
@@ -2224,18 +2161,7 @@
"pendingApproval": "En attente d'approbation",
"noComments": "Soyez le premier à commenter !",
"rating": "Note",
- "ratePhoto": "Noter cette photo",
- "yourRating": "Votre note",
- "averageRating": "Note moyenne",
- "totalRatings": "notes",
"likes": "J'aime",
- "favorites": "Favoris",
- "likePhoto": "Aimer cette photo",
- "favoritePhoto": "Ajouter aux favoris",
- "photoFeedback": "Avis sur la photo",
- "hasFeedback": "Contient des avis",
- "hasComments": "Contient des commentaires",
- "hasRating": "Contient des notes",
"settings": {
"title": "Paramètres des avis",
"enableFeedback": "Activer les avis",
@@ -2247,23 +2173,113 @@
"comments": "Commentaires",
"commentsDesc": "Commentaires textuels",
"favorites": "Favoris",
- "favoritesDesc": "Mise en favoris"
- }
+ "favoritesDesc": "Mise en favoris",
+ "identityMode": "Mode d'identité",
+ "identityModeSimple": "Avis simple",
+ "identityModeSimpleDesc": "Anonyme, basé sur l'appareil. Tous les visiteurs sur le même appareil partagent l'état.",
+ "identityModeGuest": "Sélections par invité",
+ "identityModeGuestDesc": "Chaque visiteur saisit son nom. Active le suivi par invité et les statistiques admin.",
+ "privacyModeration": "Confidentialité & Modération",
+ "requireInfo": "Exiger nom et e-mail",
+ "requireInfoDesc": "Les invités doivent fournir leur nom et e-mail pour laisser un avis",
+ "moderateComments": "Modérer les commentaires",
+ "moderateCommentsDesc": "Les commentaires nécessitent une approbation avant d'être visibles",
+ "showToGuests": "Afficher les avis aux invités",
+ "showToGuestsDesc": "Les autres invités peuvent voir les notes, les j'aime et les commentaires approuvés",
+ "enableRateLimiting": "Activer la limitation de débit",
+ "rateLimitingDesc": "Empêche le spam en limitant la fréquence des avis",
+ "timeWindow": "Fenêtre temporelle (minutes)",
+ "maxRequests": "Requêtes max"
+ },
+ "settingsUpdated": "Paramètres d'avis mis à jour",
+ "settingsUpdateError": "Échec de la mise à jour des paramètres",
+ "moderated": "Avis modéré",
+ "deleted": "Avis supprimé",
+ "exported": "Avis exporté",
+ "exportError": "Échec de l'export des avis",
+ "title": "Gestion des avis",
+ "exportCSV": "Exporter CSV",
+ "exportJSON": "Exporter JSON",
+ "tabs": {
+ "settings": "Paramètres",
+ "feedback": "Avis",
+ "analytics": "Analytique",
+ "moderation": "Modération"
+ },
+ "allTypes": "Tous les types",
+ "types": {
+ "rating": "Notes",
+ "like": "J'aime",
+ "comment": "Commentaires",
+ "favorite": "Favoris"
+ },
+ "allStatuses": "Tous les statuts",
+ "status": {
+ "pending": "En attente",
+ "approved": "Approuvé",
+ "hidden": "Masqué"
+ },
+ "noFeedback": "Aucun avis trouvé",
+ "approve": "Approuver",
+ "hide": "Masquer",
+ "unhide": "Afficher",
+ "confirmDelete": "Êtes-vous sûr de vouloir supprimer cet avis ?",
+ "avgRating": "Note moyenne",
+ "totalRatings_many": "{{count}} notes",
+ "totalRatings_one": "{{count}} note",
+ "totalRatings_other": "{{count}} notes",
+ "totalLikes": "Total J'aime",
+ "totalComments": "Total commentaires",
+ "pendingModeration_many": "{{count}} en attente",
+ "pendingModeration_one": "{{count}} en attente",
+ "pendingModeration_other": "{{count}} en attente",
+ "totalInteractions": "Interactions totales",
+ "topRated": "Photos les mieux notées",
+ "recentComments": "Commentaires récents",
+ "wordFilters": "Filtres de mots",
+ "wordFiltersDesc": "Gérer les mots bloqués pour la modération des commentaires",
+ "manageFilters": "Gérer les filtres de mots",
+ "manage": "Gérer les avis",
+ "ratingSubmitted": "Note soumise",
+ "ratingError": "Échec de la soumission de la note",
+ "rateStar_many": "Noter {{count}} étoiles",
+ "rateStar_one": "Noter {{count}} étoile",
+ "rateStar_other": "Noter {{count}} étoiles",
+ "ratingsCount_many": "{{count}} notes",
+ "ratingsCount_one": "{{count}} note",
+ "ratingsCount_other": "{{count}} notes",
+ "likeError": "Échec de la mise à jour du j'aime",
+ "unlike": "Retirer le j'aime",
+ "like": "J'aime",
+ "favoriteError": "Échec de la mise à jour du favori",
+ "unfavorite": "Retirer des favoris",
+ "favorite": "Ajouter aux favoris",
+ "invalidEmail": "Adresse e-mail invalide",
+ "identityRequired": "Vos informations sont requises",
+ "identityReason": "Veuillez fournir votre nom et e-mail pour soumettre {{type}}.",
+ "namePlaceholder": "Entrez votre nom",
+ "emailPlaceholder": "Entrez votre e-mail",
+ "submitFeedback": "Soumettre un avis",
+ "moderationSuccess": "Avis modéré avec succès",
+ "pendingModeration": "En attente de modération",
+ "pending": "en attente",
+ "noPendingComments": "Aucun commentaire en attente de modération",
+ "onPhoto": "Sur la photo",
+ "showAll_many": "Afficher tous les {{count}} commentaires en attente",
+ "showAll_one": "Afficher le {{count}} commentaire en attente",
+ "showAll_other": "Afficher tous les {{count}} commentaires en attente",
+ "viewAllFeedback": "Voir tous les avis et paramètres"
},
"filter": {
"feedbackFilters": "Filtres d'avis",
"clear": "Effacer",
"rating": "Note",
- "allPhotos": "Toutes les photos",
- "anyRating": "Toutes les notes",
- "oneStarPlus": "1+ Étoile",
- "twoStarsPlus": "2+ Étoiles",
- "threeStarsPlus": "3+ Étoiles",
- "fourStarsPlus": "4+ Étoiles",
- "fiveStarsOnly": "5 Étoiles uniquement",
"hasLikes": "Avec J'aime",
"hasFavorites": "Avec Favoris",
- "hasComments": "Avec Commentaires"
+ "hasComments": "Avec Commentaires",
+ "combineWith": "Combiner avec",
+ "showingPhotos": "Total photos",
+ "withRatings": "Avec notes"
},
"adminLogin": {
"title": "Connexion Admin",
@@ -2278,7 +2294,6 @@
"passwordRequired": "Le mot de passe est requis",
"passwordMinLength": "Minimum 6 caractères",
"rememberMe": "Se souvenir de moi",
- "forgotPassword": "Mot de passe oublié ?",
"signIn": "Se connecter",
"loginSuccess": "Connexion réussie !",
"networkError": "Erreur réseau. Vérifiez votre connexion.",
@@ -2287,7 +2302,7 @@
"generalError": "Une erreur est survenue",
"needHelp": "Besoin d'aide ? Contactez",
"poweredBy": "Propulsé par PicPeak",
- "devModeHint": "Mode Développement : admin@exemple.com / admin123"
+ "devModeHint": "Mode Développement : admin@example.com / admin123"
},
"photoSort": {
"defaultSort": "Tri par défaut des photos",
@@ -2298,5 +2313,54 @@
"filenameAZ": "Nom de fichier (A-Z)",
"filenameZA": "Nom de fichier (Z-A)",
"dateTaken": "Date de prise de vue"
+ },
+ "clientAccess": {
+ "enterPin": "Veuillez saisir votre code PIN client",
+ "invalidPin": "Code PIN invalide. Réessayez.",
+ "loginFailed": "Échec de l'authentification. Réessayez.",
+ "title": "Accès client",
+ "description": "Vérifiez les photos et gérez leur visibilité avant que la galerie ne soit partagée avec les invités.",
+ "pinLabel": "Code PIN client",
+ "pinPlaceholder": "Saisissez votre code PIN",
+ "loginButton": "Accéder à la galerie",
+ "guestHint": "Vous cherchez la galerie invité ?",
+ "guestLink": "Aller à la vue invité",
+ "adminTitle": "Accès client",
+ "enableToggle": "Activer l'accès client",
+ "enableDescription": "Permettre aux clients de consulter et masquer des photos avant que la galerie ne soit partagée avec les invités.",
+ "pinUpdated": "Code PIN client mis à jour",
+ "setPin": "Définir le code PIN",
+ "linkLabel": "Lien d'accès client",
+ "tokenRegenerated": "Lien d'accès client régénéré",
+ "regenerateToken": "Régénérer le lien",
+ "pinHelperText": "Le client utilisera ce code PIN pour accéder à la page de révision.",
+ "banner": "Mode client",
+ "visibleCount": "{{visible}} sur {{total}} photos visibles pour les invités",
+ "hideSelected": "Masquer la sélection",
+ "showSelected": "Afficher la sélection"
+ },
+ "export": {
+ "success": "Export téléchargé avec succès",
+ "error": "Échec de l'export : ",
+ "button": "Exporter",
+ "exportSelected_many": "Exporter {{count}} sélectionnés",
+ "exportSelected_one": "Exporter {{count}} sélectionné",
+ "exportSelected_other": "Exporter {{count}} sélectionnés",
+ "exportFiltered": "Exporter les photos filtrées",
+ "hint": "Sélectionnez des photos ou appliquez des filtres pour exporter"
+ },
+ "photos": {
+ "moveToCategory_many": "Déplacer {{count}} photos vers la catégorie",
+ "moveToCategory_one": "Déplacer {{count}} photo vers la catégorie",
+ "moveToCategory_other": "Déplacer {{count}} photos vers la catégorie",
+ "selectCategory": "Sélectionner une catégorie",
+ "uncategorized": "Sans catégorie",
+ "movePhotos": "Déplacer les photos",
+ "selectedCategory": "catégorie sélectionnée",
+ "movedToCategory_many": "{{count}} photos déplacées vers {{category}}",
+ "movedToCategory_one": "{{count}} photo déplacée vers {{category}}",
+ "movedToCategory_other": "{{count}} photos déplacées vers {{category}}",
+ "moveToCategoryFailed": "Échec du déplacement des photos vers la catégorie",
+ "moveToCategory": "Déplacer vers la catégorie"
}
-}
\ No newline at end of file
+}
diff --git a/frontend/src/i18n/locales/nl.json b/frontend/src/i18n/locales/nl.json
index 3ddbb27b..04ddff82 100644
--- a/frontend/src/i18n/locales/nl.json
+++ b/frontend/src/i18n/locales/nl.json
@@ -81,8 +81,6 @@
"delete": "Verwijderen",
"edit": "Bewerken",
"add": "Toevoegen",
- "search": "Zoeken",
- "filter": "Filteren",
"sortBy": "Sorteren op",
"yes": "Ja",
"no": "Nee",
@@ -91,35 +89,41 @@
"previous": "Vorige",
"close": "Sluiten",
"logout": "Uitloggen",
- "menu": "Menu",
"change": "Wijzigen",
"remove": "Verwijderen",
"download": "Downloaden",
"downloadAll": "Alles downloaden",
- "uploading": "Uploaden...",
- "uploaded": "Geupload",
"photo": "foto",
"photos": "foto's",
"video": "video",
- "videos": "video's",
"media": "media",
- "restore": "Herstellen",
- "actions": "Acties",
- "refresh": "Vernieuwen",
- "preview": "Voorbeeld",
- "processing": "Verwerken...",
"upload": "Uploaden",
- "days": "dagen",
"customize": "Aanpassen",
"hide": "Verbergen",
"unknown": "Onbekend",
"notSet": "Niet ingesteld",
"of": "van",
- "up": "Omhoog",
- "select": "Selecteren",
"selected": "Geselecteerd",
"chunk": "Deel",
- "optional": "optioneel"
+ "optional": "optioneel",
+ "tryAgain": "Opnieuw proberen",
+ "active": "Actief",
+ "inactive": "Inactief",
+ "create": "Aanmaken",
+ "unknownDate": "Onbekende datum",
+ "pageOf": "Pagina {{current}} van {{total}}",
+ "collapse": "Inklappen",
+ "expand": "Uitklappen",
+ "submitting": "Bezig met verzenden…",
+ "copy": "Kopiëren",
+ "copied": "Gekopieerd!",
+ "applying": "Toepassen…",
+ "done": "Klaar",
+ "retry": "Opnieuw proberen",
+ "characters": "tekens",
+ "saveChanges": "Wijzigingen opslaan",
+ "resetChanges": "Wijzigingen ongedaan maken",
+ "dismiss": "Sluiten"
},
"upload": {
"photoCategory": "Fotocategorie",
@@ -127,42 +131,34 @@
"eventSpecific": "(Evenement-specifiek)",
"clickToUpload": "Klik om te uploaden of sleep bestanden hierheen",
"fileRequirements": "JPEG, PNG of WebP (max. 50 MB per bestand, {{limit}} bestanden per upload)",
- "fileRequirementsMedia": "JPEG, PNG of WebP afbeeldingen, plus MP4/MOV/WEBM video's (max. 50 MB per bestand, {{limit}} bestanden per upload)",
- "unsupportedFiles": "Sommige bestanden zijn overgeslagen omdat het formaat niet wordt ondersteund (gebruik JPEG/PNG/WebP/MP4/MOV/WEBM).",
"selectedFiles": "Geselecteerde bestanden",
"uploading": "Uploaden...",
"uploadComplete": "Upload voltooid!",
- "uploadFailed": "Upload mislukt",
"someFilesFailed": "Sommige bestanden konden niet worden geupload",
"replaceByName": "Bestaande foto's met dezelfde naam vervangen",
- "replacedFiles": "{{count}} foto('s) vervangen",
"uploadPhotos": "Foto's uploaden",
"uploadMedia": "Foto's & video's uploaden",
- "importExternal": "Importeren uit externe map",
- "externalImportInfo": "Alle afbeeldingen uit de geselecteerde map worden geimporteerd.",
- "selectExternalFolder": "Selecteer externe map onder /external-media",
- "importFromSelectedFolder": "Importeren uit geselecteerde map",
"maxFilesReached": "Maximaal {{limit}} bestanden toegestaan",
"someFilesSkipped": "Er kunnen nog maar {{allowed}} bestanden worden toegevoegd (limiet {{limit}})",
"tooManyFiles": "Maximaal {{limit}} bestanden kunnen tegelijk worden geupload",
"limitInfo": "{{selected}} van {{limit}} bestanden geselecteerd ({{remaining}} resterend)",
"limitReached": "Uploadlimiet bereikt ({{limit}} bestanden per batch)",
- "uploadingChunks": "{{count}} bestanden uploaden in {{total}} batches...",
- "mediaCategory": "Mediacategorie",
- "uploadAction": "{{count}} bestanden uploaden"
+ "replacedFiles_one": "{{count}} foto vervangen",
+ "replacedFiles_other": "{{count}} foto's vervangen",
+ "processingFailed_one": "{{count}} foto kon niet worden verwerkt",
+ "processingFailed_other": "{{count}} foto's konden niet worden verwerkt",
+ "processing": "Foto's verwerken…",
+ "processingProgress": "{{complete}} van {{total}} klaar",
+ "processingHint": "De bestanden zijn geüpload. PicPeak genereert nu miniaturen en leest metadata. U kunt deze pagina verlaten — het werk gaat op de achtergrond verder.",
+ "transferring": "Overdragen",
+ "uploadingChunks_one": "{{count}} deel wordt geüpload",
+ "uploadingChunks_other": "{{count}} delen worden geüpload",
+ "retryFailed": "Mislukte opnieuw proberen"
},
"navigation": {
"dashboard": "Dashboard",
"events": "Evenementen",
- "archives": "Archieven",
- "settings": "Instellingen",
- "eventTypes": "Evenementtypes",
- "branding": "Huisstijl",
- "analytics": "Statistieken",
- "emailSettings": "E-mailinstellingen",
- "backup": "Back-up & Herstel",
- "cmsPages": "CMS-pagina's",
- "users": "Gebruikers"
+ "settings": "Instellingen"
},
"archives": {
"title": "Archieven",
@@ -205,67 +201,44 @@
"deleteSuccess": "Archief permanent verwijderd"
},
"auth": {
- "login": "Inloggen",
"password": "Wachtwoord",
"enterPassword": "Voer het galerij-wachtwoord in",
"passwordPlaceholder": "Voer het galerij-wachtwoord in",
"invalidPassword": "Ongeldig wachtwoord",
"wrongPassword": "Onjuist wachtwoord. Controleer uw wachtwoord en probeer het opnieuw.",
"tooManyAttempts": "Te veel mislukte inlogpogingen. Probeer het later opnieuw.",
- "sessionExpired": "Sessie verlopen",
"pleaseEnterPassword": "Voer een wachtwoord in",
"passwordHint": "Het wachtwoord is verstrekt door de organisator van het evenement. Neem contact op als u het niet heeft."
},
"gallery": {
- "title": "Fotogalerij",
- "welcomeMessage": "Welkomstbericht",
- "expiresOn": "Verloopt op",
"expires": "Verloopt",
"expired": "Verlopen",
- "daysRemaining": "{{days}} dagen resterend",
- "dayRemaining": "1 dag resterend",
- "hoursRemaining": "{{hours}} uur resterend",
- "expiredMessage": "Deze galerij is verlopen op {{date}}",
"contactOrganizer": "Neem contact op met de organisator als u toegang tot deze foto's nodig heeft.",
"searchPhotos": "Zoek foto's op bestandsnaam...",
"sortByDate": "Sorteren op datum",
"sortByName": "Sorteren op naam",
"sortBySize": "Sorteren op grootte",
"allPhotos": "Alle foto's",
- "filter": "Filteren",
"feedbackFilter": "Feedbackfilter",
"all": "Alle",
"liked": "Geliked",
"favorited": "Favoriet",
"favorites": "Favorieten",
- "downloadSelected": "Download {{count}} geselecteerde",
- "shareGallery": "Galerij delen",
"needHelp": "Hulp nodig? Neem contact op via",
"noPhotosFound": "Geen foto's gevonden",
"failedToLoad": "Kan foto's niet laden",
"tryAgain": "Opnieuw proberen",
"loading": "Galerij laden...",
"expiredOn": "Deze galerij is verlopen op {{date}}.",
- "expiresIn": "Galerij verloopt over {{count}} dag",
- "expiresIn_plural": "Galerij verloopt over {{count}} dagen",
"downloadBefore": "Download uw foto's voordat ze niet meer beschikbaar zijn.",
- "publicGalleryTitle": "Deze galerij is openbaar toegankelijk",
- "publicGallerySubtitle": "Foto's worden nu geladen...",
"viewGallery": "Galerij bekijken",
"downloadAll": "Alles downloaden",
- "downloading": "{{count}} foto downloaden...",
- "downloading_plural": "{{count}} foto's downloaden...",
- "downloadedPhotos": "{{count}} foto gedownload!",
- "downloadedPhotos_plural": "{{count}} foto's gedownload!",
"downloadError": "Sommige foto's konden niet worden gedownload",
"selectPhotos": "Foto's selecteren",
"cancelSelection": "Selectie annuleren",
- "photosSelected": "{{count}} geselecteerd",
"selectAll": "Alles selecteren",
"deselectAll": "Alles deselecteren",
"deleteSelected": "Geselecteerde verwijderen",
- "photosCount": "{{count}} foto",
- "photosCount_plural": "{{count}} foto's",
"searchByFilename": "Zoeken op bestandsnaam...",
"uncategorized": "Niet gecategoriseerd",
"sortAscending": "Oplopend sorteren",
@@ -273,8 +246,6 @@
"remaining": "resterend",
"selectPhotosHint": "Tip: Gebruik Ctrl+klik (Cmd+klik op Mac) om snel meerdere foto's te selecteren",
"filters": "Filters",
- "openFilters": "Filters openen",
- "toggleSidebar": "Zijbalk in-/uitschakelen",
"toggleMenu": "Menu in-/uitschakelen",
"allCategories": "Alle categorieen",
"categories": "Categorieen",
@@ -307,14 +278,56 @@
"writeLovelyNote": "Schrijf een mooi bericht...",
"postComment": "Opmerking plaatsen",
"anonymous": "Anoniem"
- }
+ },
+ "expiresIn_one": "Galerij verloopt over {{count}} dag",
+ "expiresIn_other": "Galerij verloopt over {{count}} dagen",
+ "downloading_one": "1 foto downloaden…",
+ "downloading_other": "{{count}} foto's downloaden…",
+ "photosSelected_one": "{{count}} foto geselecteerd",
+ "photosSelected_other": "{{count}} foto's geselecteerd",
+ "downloadSelected_one": "{{count}} foto downloaden",
+ "downloadSelected_other": "{{count}} foto's downloaden",
+ "guestRecovery": {
+ "invalidEmail": "Voer een geldig e-mailadres in",
+ "codeSent": "Controleer uw inbox voor een verificatiecode.",
+ "requestError": "Kon geen code verzenden. Probeer opnieuw.",
+ "invalidCode": "Voer de 6-cijferige code in",
+ "verifyError": "Ongeldige of verlopen code.",
+ "back": "Terug",
+ "title": "Uw selecties herstellen",
+ "emailStepDescription": "Voer het e-mailadres in dat u eerder heeft gebruikt. We sturen een 6-cijferige verificatiecode.",
+ "codeStepDescription": "Voer de 6-cijferige code in die we naar uw e-mail hebben gestuurd.",
+ "emailLabel": "E-mail",
+ "sendCode": "Code verzenden",
+ "codeLabel": "Verificatiecode",
+ "verifyCode": "Verifiëren en doorgaan"
+ },
+ "guestPrompt": {
+ "nameRequired": "Naam is verplicht",
+ "invalidEmail": "Ongeldig e-mailadres",
+ "emailRequired": "E-mail is verplicht",
+ "error": "Registratie mislukt",
+ "title": "Welkom — wat is uw naam?",
+ "description": "Uw selecties worden opgeslagen onder deze naam zodat de fotograaf weet welke foto's u mooi vindt.",
+ "nameLabel": "Uw naam",
+ "namePlaceholder": "Voer uw naam in",
+ "emailLabelRequired": "E-mail",
+ "emailLabel": "E-mail (optioneel)",
+ "emailPlaceholder": "u@voorbeeld.nl",
+ "submit": "Doorgaan",
+ "alreadyHere": "Ik ben hier al eerder geweest"
+ },
+ "footer": {
+ "forgetMeConfirm": "Uw naam en selecties worden verwijderd uit deze galerij.",
+ "forgetMe": "Vergeet mij ({{name}})"
+ },
+ "photosCount_one": "{{count}} foto",
+ "photosCount_other": "{{count}} foto's",
+ "poweredBy": "Mogelijk gemaakt door PicPeak"
},
"categories": {
"title": "Fotocategorieen",
- "global": "Globale categorieen",
- "eventSpecific": "Evenement-specifieke categorieen",
"addCategory": "Categorie toevoegen",
- "organizationInfo": "Organiseer uw foto's in categorieen. Categorieen helpen gasten om specifieke soorten foto's te vinden.",
"eventSpecificCategories": "Evenement-specifieke categorieen",
"noEventSpecificCategories": "Geen evenement-specifieke categorieen. Globale categorieen zijn standaard beschikbaar.",
"globalCategoriesAlwaysAvailable": "Globale categorieen (altijd beschikbaar):",
@@ -324,10 +337,8 @@
"failedToCreateCategory": "Kan categorie niet aanmaken",
"failedToDeleteCategory": "Kan categorie niet verwijderen",
"categoryName": "Categorienaam",
- "noCategory": "Geen categorie",
"noCategoriesYet": "Nog geen categorieen. Maak uw eerste categorie aan om foto's te organiseren.",
"deleteConfirm": "Weet u zeker dat u \"{{name}}\" wilt verwijderen?",
- "cannotDelete": "Kan categorie met foto's niet verwijderen. Wijs eerst de foto's opnieuw toe.",
"setCoverPhoto": "Omslagfoto instellen",
"removeCoverPhoto": "Omslagfoto verwijderen",
"coverPhotoSet": "Omslagfoto succesvol ingesteld",
@@ -342,36 +353,16 @@
"totalViews": "Totaal weergaven",
"totalDownloads": "Totaal downloads",
"uniqueVisitors": "Unieke bezoekers",
- "createNewEvent": "Nieuw evenement aanmaken",
- "setupNewGallery": "Stel een nieuwe fotogalerij in voor uw evenement",
- "createNewEventSubtitle": "Stel een nieuwe fotogalerij in voor uw evenement",
"eventNamePlaceholder": "bijv. Bruiloft Jan & Marie",
- "welcomeMessageOptional": "Welkomstbericht (optioneel)",
"welcomeMessagePlaceholder": "Welkom bij onze bijzondere dag! Voel u vrij om deze herinneringen te downloaden en te delen...",
"hostEmailPlaceholder": "klant@voorbeeld.nl",
"adminEmailPlaceholder": "admin@voorbeeld.nl",
"adminEmailPickFromAdmins": "Kies uit beheerders:",
"adminEmailCustom": "Aangepast e-mailadres",
- "securityAndAccess": "Beveiliging & Toegang",
"accessAndSecurity": "Toegang & Beveiliging",
"enterPassword": "Voer wachtwoord in",
"passwordPlaceholder": "Voer een veilig wachtwoord in",
"confirmPasswordPlaceholder": "Bevestig wachtwoord",
- "galleryExpiresOn": "Galerij verloopt op {{date}}",
- "guestsWillReceiveWarning": "Gasten ontvangen 7 dagen voor het verlopen een waarschuwingsmail.",
- "types": {
- "wedding": "Bruiloft",
- "birthday": "Verjaardag",
- "corporate": "Zakelijk",
- "other": "Overig"
- },
- "themes": {
- "default": "Standaard",
- "oceanBlue": "Oceaanblauw",
- "royalPurple": "Koninklijk paars",
- "roseGold": "Rozegoud",
- "sunsetAmber": "Zonsondergang amber"
- },
"eventDetails": "Evenementdetails",
"eventName": "Evenementnaam",
"eventType": "Evenementtype",
@@ -380,11 +371,9 @@
"hostName": "Naam klant",
"hostNamePlaceholder": "Jan Jansen",
"adminEmail": "E-mail beheerder",
- "adminNotificationEmail": "E-mail voor beheerdersmeldingen",
"expirationDate": "Vervaldatum",
"active": "Actief",
"archived": "Gearchiveerd",
- "photoCount": "{{count}} foto's",
"totalSize": "Totale grootte",
"shareLink": "Deellink",
"copyLink": "Link kopieren",
@@ -397,10 +386,7 @@
"backToEvents": "Terug naar evenementen",
"loadingEventDetails": "Evenementdetails laden...",
"saveChanges": "Wijzigingen opslaan",
- "eventExpired": "Dit evenement is verlopen",
"eventExpiresIn": "Dit evenement verloopt over {{days}} dagen",
- "guestsNoAccess": "Gasten hebben geen toegang meer tot de galerij. Overweeg dit evenement te archiveren.",
- "warningEmailsSent": "Waarschuwingsmails zijn naar de klant verzonden.",
"overview": "Overzicht",
"photos": "Foto's",
"categories": "Categorieen",
@@ -415,7 +401,6 @@
"externalFolderEmpty": "Geen submappen",
"clearSelection": "Wissen",
"welcomeMessage": "Welkomstbericht",
- "noWelcomeMessage": "Geen welkomstbericht ingesteld",
"created": "Aangemaakt",
"expires": "Verloopt",
"shareWithGuests": "Deel deze link met gasten. Ze hebben het wachtwoord nodig om de galerij te openen.",
@@ -429,28 +414,18 @@
"managePhotos": "Foto's beheren",
"actions": "Acties",
"archivingInfo": "Archiveren maakt een ZIP-bestand van alle foto's en verwijdert de galerij uit openbare toegang.",
- "statistics": "Statistieken",
- "views": "Weergaven",
- "downloads": "Downloads",
- "noStatistics": "Nog geen statistieken beschikbaar",
- "archiveStatus": "Archiefstatus",
"archivedOn": "Gearchiveerd op",
"downloadArchive": "Archief downloaden",
"loadingPhotos": "Foto's laden...",
"photoCategories": "Fotocategorieen",
"organizeCategoriesInfo": "Organiseer uw foto's in categorieen. Categorieen helpen gasten om specifieke soorten foto's te vinden.",
"categoriesTip": "Tip: Categorieen zijn specifiek per evenement. U kunt aangepaste categorieen aanmaken zoals \"Ceremonie\", \"Receptie\", \"Portretten\", etc.",
- "contactInformation": "Contactgegevens",
- "hostEmailHelp": "Klant ontvangt meldingen over aanmaak en verloop van de galerij",
- "adminEmailHelp": "Ontvangt systeemmeldingen en archiefbevestigingen",
- "securityAccess": "Beveiliging & Toegang",
"galleryPassword": "Galerijwachtwoord",
"requirePasswordToggle": "Wachtwoord vereisen voor deze galerij",
"requirePasswordToggleHelp": "Schakel dit uit als u de galerij zonder wachtwoord wilt delen. Iedereen met de link kan de foto's bekijken.",
"publicGalleryWarning": "Openbare galerijen zijn toegankelijk voor iedereen met de link. Overweeg download-watermerken in te schakelen en activiteit te monitoren.",
"passwordHelperText": "U kunt datums gebruiken zoals \"04-07-2025\" of willekeurige tekst met 6+ tekens",
"confirmPassword": "Bevestig wachtwoord",
- "showPasswords": "Wachtwoorden tonen",
"newPasswordLabel": "Nieuw galerijwachtwoord",
"passwordReset": {
"title": "Galerijwachtwoord opnieuw instellen",
@@ -475,15 +450,10 @@
"errorMinLength": "Wachtwoord moet minimaal 6 tekens bevatten",
"errorMismatch": "Wachtwoorden komen niet overeen"
},
- "gallerySettings": "Galerijinstellingen",
"themeAndStyle": "Thema & Stijl",
- "colorTheme": "Kleurthema",
"galleryExpiration": "Galerij vervaldatum",
- "galleryExpiresIn": "Galerij verloopt over",
"daysAfterEvent": "dagen na evenementdatum",
"expiresOn": "Verloopt op",
- "galleryWillExpireOn": "Galerij verloopt op {{date}}",
- "expirationWarning": "Gasten ontvangen 7 dagen voor het verlopen een waarschuwingsmail.",
"noExpiration": "Geen vervaldatum",
"noExpirationHelp": "Deze galerij blijft actief totdat deze handmatig wordt gearchiveerd.",
"photoCap": "Fotolimiet",
@@ -495,11 +465,7 @@
"uploadCategory": "Uploadcategorie",
"selectCategory": "Selecteer een categorie voor gastuploads",
"uploadCategoryHelp": "Alle door gasten geuploade foto's worden aan deze categorie toegevoegd",
- "userUploadWarning": "Gastuploads worden gemodereerd en kunnen op elk moment door beheerders worden verwijderd.",
"allowDownloads": "Foto-downloads toestaan",
- "allowDownloadsHelp": "Gasten toestaan foto's uit deze galerij te downloaden",
- "downloadPermissions": "Downloadrechten",
- "downloadsEnabled": "Downloads ingeschakeld",
"downloadsDisabled": "Downloads uitgeschakeld",
"downloadProtection": "Downloadbeveiliging",
"disableRightClick": "Rechtermuisknop blokkeren",
@@ -548,15 +514,6 @@
"heroImageAnchorBottom": "Onder",
"heroPreview": "Hero-voorbeeld",
"noPhotosAvailable": "Geen foto's beschikbaar",
- "processingRequest": "Uw verzoek wordt verwerkt...",
- "eventTypeWedding": "Bruiloft",
- "eventTypeBirthday": "Verjaardag",
- "eventTypeCorporate": "Zakelijk",
- "eventTypeOther": "Overig",
- "days30": "30 dagen",
- "days60": "60 dagen",
- "days90": "90 dagen",
- "days365": "1 jaar",
"inactive": "Inactief",
"expired": "Verlopen",
"draft": "Concept",
@@ -564,31 +521,36 @@
"publishConfirm": "Hiermee wordt de galerij toegankelijk en wordt de notificatie-e-mail naar de klant verzonden. Doorgaan?",
"publishSuccess": "Galerij gepubliceerd en klant geïnformeerd!",
"draftBanner": "Deze galerij staat in conceptmodus. Upload je foto's en publiceer wanneer je klaar bent.",
- "daysLeft": "{{count}}d resterend",
- "daysLeft_plural": "{{count}}d resterend",
"subtitle": "Beheer uw fotogalerijen en evenementen",
- "loadingEvents": "Evenementen laden...",
"failedToLoadEvents": "Kan evenementen niet laden",
"tryAgain": "Opnieuw proberen",
- "bulkArchiveSuccess": "{{count}} evenementen succesvol gearchiveerd",
"bulkArchivePartial": "{{success}} evenementen gearchiveerd, {{failed}} mislukt",
"deleteSelected": "Geselecteerde verwijderen",
"bulkDelete": {
- "title": "{{count}} evenementen permanent verwijderen?",
"warning": "De geselecteerde evenementen, al hun foto's, archieven en auditlogboeken worden permanent verwijderd. Deze actie kan niet ongedaan worden gemaakt.",
+ "passwordLabel": "Voer ter bevestiging uw wachtwoord opnieuw in",
+ "passwordPlaceholder": "Uw beheerderswachtwoord",
+ "passwordHelp": "We vragen om uw wachtwoord als bescherming tegen onbedoelde bulkverwijderingen.",
+ "incorrectPassword": "Onjuist wachtwoord. Er zijn geen evenementen verwijderd.",
"confirmLabel": "Typ {{literal}} om te bevestigen",
"confirmHelp": "Een getypte bevestiging voorkomt onbedoelde verwijderingen en wordt niet beïnvloed door browser-autofill of passkey-snelkoppelingen.",
"submit": "{{count}} evenementen verwijderen",
"processing": "{{count}} evenementen worden verwijderd. Dit kan enkele minuten duren — sluit dit venster niet.",
"successAll": "{{count}} evenementen permanent verwijderd",
"successPartial": "{{success}} evenementen verwijderd, {{failed}} mislukt",
- "errorGeneric": "Kan evenementen niet verwijderen"
+ "errorGeneric": "Kan evenementen niet verwijderen",
+ "successAll_one": "{{count}} evenement definitief verwijderd",
+ "successAll_other": "{{count}} evenementen definitief verwijderd",
+ "title_one": "{{count}} evenement definitief verwijderen?",
+ "title_other": "{{count}} evenementen definitief verwijderen?",
+ "processing_one": "{{count}} evenement verwijderen. Dit kan enkele minuten duren — sluit dit venster niet.",
+ "processing_other": "{{count}} evenementen verwijderen. Dit kan enkele minuten duren — sluit dit venster niet.",
+ "submit_one": "{{count}} evenement verwijderen",
+ "submit_other": "{{count}} evenementen verwijderen"
},
"searchEventsPlaceholder": "Evenementen zoeken...",
"all": "Alle",
"expiring": "Verloopt binnenkort",
- "eventsSelected": "{{count}} evenement geselecteerd",
- "eventsSelected_plural": "{{count}} evenementen geselecteerd",
"clear": "Wissen",
"archiveSelected": "Geselecteerde archiveren",
"publicAccess": "Openbare toegang",
@@ -617,45 +579,20 @@
"extendSevenDays": "7 dagen verlengen",
"welcomeMessageLabel": "Welkomstbericht",
"noWelcomeMessageSet": "Geen welkomstbericht ingesteld",
- "createdOn": "Aangemaakt",
"copy": "Kopieren",
"copied": "Gekopieerd!",
- "organizingPhotosInfo": "Organiseer uw foto's in categorieen. Categorieen helpen gasten om specifieke soorten foto's te vinden.",
"archiveStatusTitle": "Archiefstatus",
"downloadingArchive": "Archief {{name}} downloaden...",
"downloadStarted": "Download gestart",
"failedToDownloadArchive": "Kan archief niet downloaden",
- "statisticsNotAvailable": "Nog geen statistieken beschikbaar",
- "photoFilters": "Fotofilters",
- "noStatisticsAvailableYet": "Nog geen statistieken beschikbaar",
- "addPlus": "Toevoegen+",
"galleryTheme": "Galerijthema",
- "customizeTheme": "Thema aanpassen",
"noThemeSet": "Geen thema ingesteld",
- "customizingTheme": "Galerijthema aanpassen",
"customizingThemeFor": "Thema aanpassen voor {{event}}",
"customCssTemplate": "Aangepast CSS-sjabloon",
"customCssTemplateDesc": "Pas een aangepast CSS-sjabloon toe om de galerij met unieke visuele effecten te stylen.",
"noTemplate": "Geen sjabloon",
"useThemeOnly": "Alleen themapreset gebruiken",
"customTemplate": "Aangepast sjabloon",
- "activeFilter": "Actief",
- "archivedFilter": "Gearchiveerd",
- "sortByName": "Op naam",
- "sortByDate": "Op datum",
- "sortByExpiration": "Op vervaldatum",
- "photosCount": "Foto's",
- "moreActions": "Meer acties",
- "copyLinkTooltip": "Link kopieren",
- "viewGalleryTooltip": "Galerij bekijken",
- "uploadPhotosTooltip": "Foto's uploaden",
- "editTooltip": "Bewerken",
- "archiveTooltip": "Archiveren",
- "noEvents": "Geen evenementen gevonden",
- "noEventsDescription": "Maak uw eerste evenement aan om te beginnen.",
- "bulkArchive": "Archiveren",
- "confirmBulkArchive": "Weet u zeker dat u {{count}} evenement(en) wilt archiveren?",
- "confirmBulkArchiveDescription": "Deze actie kan niet ongedaan worden gemaakt. Gearchiveerde evenementen zijn niet meer openbaar toegankelijk.",
"rename": {
"button": "Hernoemen",
"title": "Evenement hernoemen",
@@ -663,9 +600,44 @@
"renamingFiles": "Bestanden hernoemen...",
"complete": "Voltooid!",
"failed": "Hernoemen mislukt",
- "filesRenamed": "{{count}} bestanden bijgewerkt",
- "confirm": "Evenement hernoemen"
- }
+ "confirm": "Evenement hernoemen",
+ "success": "Evenement succesvol hernoemd!",
+ "filesRenamed_one": "{{count}} bestand bijgewerkt",
+ "filesRenamed_other": "{{count}} bestanden bijgewerkt",
+ "newLink": "Nieuwe galerijlink",
+ "currentName": "Huidige naam:",
+ "newName": "Nieuwe naam evenement",
+ "enterNewName": "Voer nieuwe naam evenement in",
+ "newUrl": "Nieuwe URL:",
+ "checkingAvailability": "Beschikbaarheid controleren…",
+ "resendEmail": "Uitnodigingsmail opnieuw verzenden met nieuwe galerijlink",
+ "emailTo": "Bijgewerkte toegangs-e-mail sturen naar",
+ "warningTitle": "Let op:",
+ "warning1": "De galerij-URL zal veranderen",
+ "warning2": "Oude URL's worden automatisch doorgestuurd naar de nieuwe URL",
+ "warning3": "Fotobestanden kunnen worden hernoemd"
+ },
+ "bulkArchiveSuccess_one": "{{count}} evenement succesvol gearchiveerd",
+ "bulkArchiveSuccess_other": "{{count}} evenementen succesvol gearchiveerd",
+ "daysLeft_one": "({{count}} dag resterend)",
+ "daysLeft_other": "({{count}} dagen resterend)",
+ "eventsSelected_one": "{{count}} evenement geselecteerd",
+ "eventsSelected_other": "{{count}} evenementen geselecteerd",
+ "paginationLabel": "{{from}}–{{to}} van {{total}}",
+ "filtered": "gefilterd",
+ "pageOf": "Pagina {{page}} van {{totalPages}}",
+ "notFound": "Evenement niet gevonden",
+ "customerPhone": "Telefoonnummer klant",
+ "customerPhonePlaceholder": "+31 6 12345678",
+ "allowPresignedDownload": "Directe S3-download toestaan (zonder watermerk, alleen S3-modus)",
+ "neverExpires": "Nooit",
+ "rightClickBlocked": "Rechtsklik geblokkeerd",
+ "devtoolsDetection": "Ontwikkelaarshulpmiddelen detectie",
+ "watermarked": "Voorzien van watermerk",
+ "importExternal": "Importeren vanuit externe map",
+ "externalImportInfo": "Alle afbeeldingen uit de geselecteerde map worden geïmporteerd.",
+ "selectExternalFolder": "Externe map selecteren onder /external-media",
+ "importFromSelectedFolder": "Importeren vanuit geselecteerde map"
},
"settings": {
"title": "Systeeminstellingen",
@@ -677,9 +649,7 @@
"siteUrl": "Site-URL",
"siteUrlHelp": "Wordt gebruikt voor het genereren van galerijlinks in e-mails",
"defaultExpiration": "Standaard vervaltijd (dagen)",
- "defaultExpirationHelp": "Hoe lang galerijen standaard actief blijven",
"maxFileSize": "Max. bestandsgrootte (MB)",
- "maxFileSizeHelp": "Maximale grootte per geuploade foto",
"maxFilesPerUpload": "Max. bestanden per upload",
"maxFilesPerUploadHelp": "Maximaal aantal foto's per uploadbatch (1-{{max}}).",
"allowedFileTypes": "Toegestane bestandstypen",
@@ -691,13 +661,7 @@
"enableShortGalleryUrlsHelp": "Verwijdert de evenement-slug uit nieuwe deellinks terwijl bestaande links blijven werken.",
"maintenanceMode": "Onderhoudsmodus inschakelen",
"language": "Taal",
- "defaultLanguage": "Standaardtaal",
"defaultLanguageHelp": "Taal die aan gasten wordt getoond voor het inloggen",
- "defaultWelcomeMessage": "Standaard welkomstbericht",
- "welcomeMessage": "Welkomstbericht",
- "welcomeMessagePlaceholder": "Voer een standaard welkomstbericht in dat wordt opgenomen in e-mails bij het aanmaken van galerijen",
- "welcomeMessageHelp": "Dit bericht wordt opgenomen in alle e-mails bij het aanmaken van galerijen, tenzij overschreven bij het aanmaken van een evenement",
- "saveSettings": "Algemene instellingen opslaan",
"saveGeneralSettings": "Algemene instellingen opslaan",
"dateTimeFormat": "Datum- & Tijdnotatie",
"dateFormat": "Datumnotatie",
@@ -715,7 +679,6 @@
"accountSaveSuccess": "Accountgegevens bijgewerkt"
},
"publicSite": {
- "tabLabel": "Openbare site",
"badge": "Openbare landingspagina",
"title": "Openbare landingspagina",
"subtitle": "Publiceer een aangepaste landingspagina voor gasten wanneer ze uw domein bezoeken.",
@@ -743,8 +706,6 @@
"htmlRequired": "Geef HTML-inhoud op voordat u de openbare site inschakelt."
},
"storage": {
- "title": "Opslag",
- "overview": "Opslagoverzicht",
"totalUsed": "Totaal gebruikt",
"archiveStorage": "Archiefopslag",
"storageLimit": "Opslaglimiet",
@@ -756,7 +717,6 @@
"diskCapacityReported": "Schijfcapaciteit (gerapporteerd)",
"diskAvailable": "Beschikbaar",
"diskAvailableReported": "Beschikbaar (gerapporteerd)",
- "diskFree": "Vrij",
"diskFreeReported": "Vrij (gerapporteerd)",
"diskMetricsUnavailable": "Schijfmetingen zijn niet beschikbaar in Docker Desktop of gevirtualiseerde omgevingen.",
"applyRecommended": "Aanbevolen gebruiken",
@@ -775,17 +735,12 @@
"capacityRequiredForAvailable": "Voer een totale capaciteit in voordat u beschikbare ruimte instelt.",
"availableExceedsCapacity": "Beschikbare ruimte kan de totale capaciteit niet overschrijden.",
"storageUsage": "Opslaggebruik",
- "storageByEvent": "Opslag per evenement",
- "storageManagement": "Opslagbeheer",
- "storageManagementHelp": "Overweeg oude evenementen te archiveren of te verwijderen om opslagruimte vrij te maken. Gearchiveerde evenementen worden gecomprimeerd en gebruiken minder opslag dan actieve galerijen.",
- "noEventsUsingStorage": "Geen evenementen gebruiken opslag",
"unlimited": "Onbeperkt"
},
"security": {
"title": "Beveiliging",
"passwordSettings": "Wachtwoordinstellingen",
"minPasswordLength": "Minimale wachtwoordlengte",
- "minPasswordLengthHelp": "Minimaal aantal tekens voor galerijwachtwoorden",
"passwordComplexity": "Wachtwoordcomplexiteit",
"passwordComplexityHelp": "Vereist beveiligingsniveau voor galerijwachtwoorden",
"complexitySimple": "Eenvoudig (6+ tekens, willekeurige tekst)",
@@ -794,7 +749,6 @@
"complexityVeryStrong": "Zeer sterk (12+ tekens, alle tekentypen)",
"sessionAuth": "Sessie & Authenticatie",
"sessionTimeout": "Sessietime-out (minuten)",
- "sessionTimeoutHelp": "Time-out voor beheerdersessie in minuten",
"maxLoginAttempts": "Max. inlogpogingen",
"maxLoginAttemptsHelp": "Maximum mislukte inlogpogingen per IP voor vergrendeling",
"attemptWindowMinutes": "Pogingenvenster (minuten)",
@@ -805,11 +759,8 @@
"recaptchaSettings": "reCAPTCHA-instellingen",
"enableRecaptcha": "reCAPTCHA inschakelen voor inlogformulieren",
"siteKey": "Sitesleutel",
- "siteKeyHelp": "Uw reCAPTCHA v2-sitesleutel (openbaar)",
"secretKey": "Geheime sleutel",
- "secretKeyHelp": "Uw reCAPTCHA v2-geheime sleutel (houd prive)",
"recaptchaHelp": "Haal uw reCAPTCHA-sleutels op bij",
- "saveSettings": "Beveiligingsinstellingen opslaan",
"saveSecuritySettings": "Beveiligingsinstellingen opslaan"
},
"categories": {
@@ -851,8 +802,6 @@
"missingDimensions": "Ontbrekende afmetingen",
"repairButton": "Afmetingen repareren",
"repairing": "Repareren...",
- "alreadyRunning": "Reparatie is al bezig",
- "started": "Reparatie gestart voor {{count}} foto's",
"noneToRepair": "Alle foto's hebben al afmetingen",
"resultSuccess": "Laatste reparatie: {{success}} bijgewerkt, {{failed}} mislukt",
"description": "Vul ontbrekende breedte/hoogte aan voor foto's die zijn geupload voordat afmetingen werden bijgehouden. Vereist voor Masonry- en Mosaic-layouts."
@@ -870,11 +819,12 @@
"sendTest": "Test-e-mail verzenden",
"saved": "Instellingen opgeslagen",
"saveError": "Kan instellingen niet opslaan",
- "emailSent": "Meldingse-mail verzonden naar {{count}} ontvangers",
"emailFailed": "Kan melding niet verzenden",
"checkSuccess": "Melding verzonden voor nieuwe versie",
"checkNoAction": "Geen melding nodig: {{reason}}",
- "checkError": "Kan niet controleren op updates"
+ "checkError": "Kan niet controleren op updates",
+ "emailSent_one": "Meldingsmail verzonden naar {{count}} ontvanger",
+ "emailSent_other": "Meldingsmail verzonden naar {{count}} ontvangers"
},
"events": {
"title": "Evenement aanmaken",
@@ -896,7 +846,13 @@
"expirationWarning": "Galerijen zonder vervaldatum blijven actief totdat ze handmatig worden gearchiveerd",
"saveSettings": "Evenementinstellingen opslaan",
"noteTitle": "Opmerking",
- "noteText": "Deze instellingen zijn alleen van toepassing op het aanmaken van nieuwe evenementen. Bestaande evenementen worden niet beinvloed. Standaard zijn alle velden verplicht."
+ "noteText": "Deze instellingen zijn alleen van toepassing op het aanmaken van nieuwe evenementen. Bestaande evenementen worden niet beinvloed. Standaard zijn alle velden verplicht.",
+ "defaultRequirePassword": "Standaard wachtwoord vereisen",
+ "defaultRequirePasswordHelp": "Pre-aangevinkt «Wachtwoord vereisen» bij het aanmaken van evenementen. Uitschakelen voor sneller aanmaken van openbare galerijen.",
+ "showGalleryFilterBar": "Filterbalk in galerijen tonen",
+ "showGalleryFilterBarHelp": "Toont de zoek-op-bestandsnaam en sorteerbediening boven rasterindelingsgalerijen. Uitschakelen voor een cleaner lay-out.",
+ "enablePhoneField": "Telefoonnummerveld inschakelen",
+ "enablePhoneFieldHelp": "Voegt een optioneel telefoonnumerinvoerveld toe aan het evenementformulier. Handig voor automatisering zoals WhatsApp-levering via n8n. Altijd optioneel, ook als ingeschakeld."
},
"imageSecurity": {
"title": "Afbeeldingsbeveiliging",
@@ -969,11 +925,6 @@
"format": "Formaat",
"fit": "Pasmodus",
"fitHelp": "Hoe afbeeldingen worden aangepast aan de miniatuurafmetingen. \"Cover\" snijdt bij om te vullen, \"Contain\" past binnen de grenzen.",
- "fit_cover": "Cover (bijsnijden om te vullen)",
- "fit_contain": "Contain (passend binnen)",
- "fit_fill": "Vullen (uitrekken)",
- "fit_inside": "Binnenkant (verkleinen om te passen)",
- "fit_outside": "Buitenkant (vergroten om te bedekken)",
"regenerateTitle": "Miniaturen opnieuw genereren",
"regenerateHelp": "Na het wijzigen van miniatuurinstellingen kunt u alle bestaande miniaturen opnieuw genereren om de nieuwe configuratie toe te passen. Dit draait op de achtergrond en kan even duren bij grote galerijen.",
"regenerateButton": "Alle miniaturen opnieuw genereren",
@@ -1036,11 +987,57 @@
"deviceTypes": "Apparaattypen op basis van user agents",
"privacy": "Privacy",
"privacyText": "IP-adressen worden gehasht voor privacy. Er worden geen persoonsgegevens opgeslagen. Statistiekgegevens worden 90 dagen bewaard."
- }
+ },
+ "groups": {
+ "general": "Algemeen",
+ "display": "Weergave",
+ "privacySecurity": "Privacy & Beveiliging",
+ "integrations": "Integraties",
+ "system": "Systeem"
+ },
+ "apiTokens": {
+ "title": "API-tokens",
+ "createError": "Aanmaken van token mislukt",
+ "revoked": "Token ingetrokken",
+ "subtitle": "Langlevende bearer-tokens voor de publieke /api/v1-interface — n8n-integraties, aangepaste apps, scripts. Tokens werken als de beheerder die ze heeft aangemaakt, beperkt tot de gekozen scopes.",
+ "copyNow": "Kopieer dit token nu — het wordt niet opnieuw getoond.",
+ "copied": "Gekopieerd",
+ "copyFailed": "Kopiëren mislukt",
+ "name": "Naam",
+ "namePlaceholder": "bijv. n8n productie",
+ "scopes": "Scopes",
+ "generate": "Token genereren",
+ "scopeHint": "admin > schrijven > lezen. Een alleen-lezen token kan niet wijzigen, zelfs niet als de eigenaar super_admin is.",
+ "existing": "Bestaande tokens",
+ "lastUsed": "Laatst gebruikt",
+ "created": "Aangemaakt",
+ "status": "Status",
+ "statusRevoked": "Ingetrokken",
+ "statusExpired": "Verlopen",
+ "statusActive": "Actief",
+ "confirmRevoke": "Dit token intrekken? Deze actie kan niet ongedaan worden gemaakt.",
+ "revoke": "Intrekken",
+ "empty": "Nog geen tokens. Genereer er een hierboven om te beginnen."
+ },
+ "webhooks": {
+ "title": "Webhooks",
+ "subtitle": "Verstuur POST-meldingen naar uw URL zodra er iets gebeurt — galerij gepubliceerd, foto geüpload, evenement gearchiveerd, etc. Ondertekend met HMAC-SHA256 in de X-PicPeak-Signature header.",
+ "piiNotice": "event.*-payloads bevatten klantcontactgegevens (naam, e-mail, telefoon) en het galerij-deeltoken indien opgeslagen. Wijs webhooks alleen toe aan vertrouwde ontvangers.",
+ "copyNow": "Kopieer dit handtekeninggeheim nu — het wordt niet opnieuw getoond.",
+ "name": "Naam",
+ "url": "Ontvanger-URL",
+ "events": "Abonneren op evenementen",
+ "filter": "Filter (JSON, optioneel)",
+ "template": "Sjabloon (optioneel)",
+ "create": "Webhook aanmaken",
+ "existing": "Bestaande webhooks",
+ "empty": "Nog geen webhooks. Maak er een aan hierboven om evenementmeldingen te ontvangen."
+ },
+ "sectionLabel": "Instellingensectie",
+ "navAriaLabel": "Instellingennavigatie"
},
"analytics": {
"title": "Statistiekendashboard",
- "titleSimple": "Statistieken",
"subtitle": "Volg galerijprestaties en bezoekerbetrokkenheid",
"detailedSubtitle": "Gedetailleerde statistieken aangedreven door Umami",
"loadingAnalytics": "Statistieken laden...",
@@ -1068,13 +1065,10 @@
"totalPhotos": "Totaal foto's",
"activeEvents": "Actieve evenementen",
"notConfigured": "Umami Analytics niet geconfigureerd",
- "configureInstructions": "Configureer Umami in uw omgevingsvariabelen en beheerdersinstellingen om echte statistieken te zien.",
- "noData": "Geen gegevens beschikbaar",
- "percentChange": "{{percent}}% ten opzichte van vorige periode"
+ "configureInstructions": "Configureer Umami in uw omgevingsvariabelen en beheerdersinstellingen om echte statistieken te zien."
},
"branding": {
"title": "Huisstijl & Thema's",
- "titleFull": "Huisstijl & Aanpassing",
"subtitle": "Pas het uiterlijk van uw galerijen aan",
"loadingBranding": "Huisstijlinstellingen laden...",
"themeAndStyle": "Thema & Stijl",
@@ -1086,18 +1080,14 @@
"supportEmail": "Support-e-mail",
"supportEmailHelp": "Contact-e-mail voor gastsupport",
"footerText": "Voettekst",
- "footerTextHelp": "Wordt onderaan galerijen weergegeven",
"logo": "Logo",
- "currentLogo": "Huidig logo",
"uploadLogo": "Logo uploaden",
- "removeLogo": "Logo verwijderen",
"logoHelp": "Aanbevolen grootte: 200x60px, PNG of JPEG",
"favicon": "Favicon",
"currentFavicon": "Huidig favicon",
"uploadFavicon": "Favicon uploaden",
"removeFavicon": "Favicon verwijderen",
"faviconHelp": "PNG- of ICO-formaat, aanbevolen grootte: 32x32px",
- "watermark": "Watermerk",
"watermarkSettings": "Watermerkinstellingen",
"enableWatermarks": "Watermerken inschakelen",
"watermarkHelp": "Voeg uw bedrijfsnaam als watermerk toe aan gedownloade foto's",
@@ -1114,11 +1104,7 @@
"watermarkSize": "Watermerkgrootte",
"theme": "Thema",
"galleryTheme": "Galerijthema",
- "themeCustomization": "Thema-aanpassing",
- "selectPreset": "Selecteer een vooringesteld thema",
"colors": "Kleuren",
- "primaryColor": "Primaire kleur",
- "secondaryColor": "Secundaire kleur",
"accentColor": "Accentkleur",
"backgroundColor": "Achtergrondkleur",
"textColor": "Tekstkleur",
@@ -1127,27 +1113,13 @@
"colorModeDark": "Donker",
"colorModeAuto": "Automatisch",
"colorModeHelp": "Automatisch volgt de systeemvoorkeur van de bezoeker.",
- "customCSS": "Aangepaste CSS",
"preview": "Voorbeeld",
- "previewInNewTab": "Voorbeeld in nieuw tabblad",
- "reset": "Herstellen",
"saveChanges": "Wijzigingen opslaan",
"applyLivePreview": "Wijzigingen direct toepassen (Live voorbeeld)",
"eventSpecificThemes": "Evenement-specifieke thema's",
"eventThemesInfo": "U kunt deze globale thema-instellingen overschrijven voor individuele evenementen bij het aanmaken of bewerken ervan.",
"themePresets": "Themapresets",
"galleryLayout": "Galerijlay-out",
- "layoutDescriptions": {
- "grid": "Klassieke rasterlay-out met gelijkmatige fotogroottes",
- "masonry": "Pinterest-achtige lay-out met variabele hoogtes",
- "carousel": "Diashow op volledig scherm met navigatie",
- "timeline": "Foto's geordend op datum",
- "hero": "Uitgelichte afbeelding met raster eronder",
- "mosaic": "Artistieke lay-out met gemengde groottes",
- "justified": "Rijgebaseerde lay-out met behoud van beeldverhoudingen",
- "gallery-premium": "Elegante lichte thema met hero en masonry (Beta)",
- "gallery-story": "Filmisch donker thema met scenesecties (Beta)"
- },
"layoutSettings": "Lay-outinstellingen",
"photoSpacing": "Foto-afstand",
"spacing": {
@@ -1204,16 +1176,6 @@
"xl": "XL — Grootste foto's"
},
"thumbnailScaleHint": "Past het aantal kolommen aan ten opzichte van de basisrasterkolommen",
- "showHeroSection": "Hero-sectie tonen",
- "showHeroSectionHint": "Toon een uitgelichte hero-afbeelding boven de justified galerij",
- "heroHeight": "Hero-sectiehoogte",
- "heroHeightOptions": {
- "small": "Klein (40-50%)",
- "medium": "Medium (50-70%)",
- "large": "Groot (60-80%)"
- },
- "heroOverlayOpacity": "Hero-overlay dekking",
- "heroOverlayHint": "Verdonker de hero-afbeelding om de leesbaarheid van tekst te verbeteren",
"typographyAndStyle": "Typografie & Stijl",
"bodyFont": "Bodytekst lettertype",
"headingFont": "Koptekst lettertype",
@@ -1259,8 +1221,6 @@
},
"resetToDefault": "Standaardwaarden herstellen",
"applyTheme": "Thema toepassen",
- "customTheme": "Aangepast thema",
- "customizeTheme": "Thema aanpassen",
"saveTheme": "Thema opslaan",
"previewLayout": "Lay-outvoorbeeld",
"livePreview": "Live voorbeeld",
@@ -1278,9 +1238,6 @@
"logoMaxHeight": "Maximale hoogte (pixels)",
"logoMaxHeightHelp": "Stel een aangepaste maximale hoogte in voor het logo (20-200 pixels)",
"logoPosition": "Logopositie in header",
- "positionLeft": "Links",
- "positionCenter": "Midden",
- "positionRight": "Rechts",
"logoDisplayMode": "Weergavemodus",
"logoOnly": "Alleen logo",
"textOnly": "Alleen bedrijfsnaam",
@@ -1291,29 +1248,8 @@
"showLogoInHeroHelp": "Toon het logo in hero-secties (voor niet-raster lay-outs)",
"headerStyle": "Headerstijl",
"headerStyleDescription": "Kies hoe de galerijheader wordt weergegeven. De headerstijl is onafhankelijk van de fotolay-out.",
- "headerStyleOptions": {
- "hero": "Hero-afbeelding",
- "standard": "Standaard",
- "banner": "Banner",
- "minimal": "Minimaal",
- "none": "Geen header"
- },
- "headerStyleDescriptions": {
- "hero": "Afbeelding op volledige hoogte met evenementinfo-overlay",
- "standard": "Compacte koptekst met evenementdetails",
- "banner": "Standaard-header met een gekleurde banner erboven",
- "minimal": "Compacte header met essentiele info",
- "none": "Header volledig verbergen"
- },
"heroDividerStyle": "Scheidingsstijl",
"heroDividerDescription": "Kies hoe de overgang tussen de hero-afbeelding en galerij-inhoud eruitziet.",
- "dividerOptions": {
- "wave": "Golf",
- "straight": "Recht",
- "angle": "Hoek",
- "curve": "Boog",
- "none": "Geen"
- },
"controlsStyle": "Bedieningsstijl",
"controlsStyleDescription": "Kies hoe galerijfilters en bedieningen worden weergegeven.",
"controlsStyleOptions": {
@@ -1327,15 +1263,43 @@
"controlsStyleHeroWarning": "Zijbalk wordt aanbevolen voor hero-headers om te voorkomen dat bedieningen boven de hero-afbeelding verschijnen.",
"betaThumbnailWarningTitle": "Lage thumbnailresolutie gedetecteerd",
"betaThumbnailWarningText": "Uw thumbnails zijn momenteel {{width}}×{{height}}px. Beta-thema's tonen foto's op grotere formaten en vereisen minimaal {{recommended}}×{{recommended}}px voor goede kwaliteit. Verhoog de thumbnail-afmetingen via Instellingen > Thumbnails en genereer opnieuw.",
- "betaThumbnailWarningLink": "Naar thumbnail-instellingen"
+ "betaThumbnailWarningLink": "Naar thumbnail-instellingen",
+ "logoSize": "Logogrootte",
+ "surfaceColor": "Oppervlak",
+ "elevatedColor": "Verhoogd",
+ "borderColor": "Rand",
+ "mutedTextColor": "Gedempte tekst",
+ "accentDarkColor": "Accent (gevuld)",
+ "syncFromBranding": "Synchroniseren vanuit huisstijl",
+ "forceColorMode": "Kleurmodus forceren",
+ "forceColorModeHelp": "Vergrendel de gehele beheer- en openbare site in donker of licht. De donker/licht-schakelaar wordt verborgen wanneer een vergrendeling actief is.",
+ "forceColorModeNone": "Niet forceren (gebruikerskeuze)",
+ "forceColorModeDark": "Donker forceren",
+ "forceColorModeLight": "Licht forceren",
+ "colorGroupSurfaces": "Oppervlakken",
+ "colorGroupSurfacesHelp": "De neutrale lagen achter uw inhoud. Achtergrond staat het verste terug; Oppervlak en Verhoogd stapelen daarboven.",
+ "backgroundColorHelp": "De pagina zelf — body-achtergrond van elke galerij, beheerpagina en CMS-pagina.",
+ "surfaceColorHelp": "Kaarten, zijbalk, headerbalk en navigatie. De eerste laag boven Achtergrond.",
+ "elevatedColorHelp": "Panelen die boven kaarten zweven: afbeeldingsplaceholders, hover/actieve rijen, modale headers, codeblokken.",
+ "borderColorHelp": "Scheidingslijnen, tabelrasterlijnen, kaartcontouren, invoerrandjes.",
+ "colorGroupText": "Tekst",
+ "colorGroupTextHelp": "Voorgrondtekstkleuren. Primair is voor alles waar lezers op focussen; Secundair is voor ondersteunende tekst.",
+ "textColorHelp": "Koppen, lopende tekst, tabelcellen, formulierinvoerwaarden, navigatielabels — de hoofdtekstkleur.",
+ "mutedTextColorHelp": "Bijschriften, helptekst onder invoervelden, tabelkolomkoppen, voettekstlinks, datums en metadata.",
+ "colorGroupAccent": "Accent",
+ "colorGroupAccentHelp": "Merkkleuren die interactieve elementen benadrukken. Gebruik een sterk kleurpaar — Accent voor contouren/tekst, Accent (gevuld) voor gevulde knoppen.",
+ "accentColorHelp": "Links, pictogrammen, focusringen, hover-states op primaire knoppen, actieve zijbalkitem-onderstreping.",
+ "accentDarkColorHelp": "Gevulde CTA-knoppen, actieve zijbalkitem-achtergrond, badges en labels. Heeft voldoende contrast nodig voor leesbare witte tekst.",
+ "cssTemplate": "CSS-sjabloon",
+ "cssTemplateDescription": "Selecteer een voorgebouwd CSS-sjabloon om applicatiebrede stijlen toe te passen op deze galerij. Sjablonen kunnen worden beheerd in Instellingen > CSS-sjablonen.",
+ "noTemplate": "Geen sjabloon",
+ "noTemplateDescription": "Alleen thema-instellingen gebruiken zonder CSS-sjabloon",
+ "templateSlot": "Slot {{slot}}",
+ "eventCustomCSS": "Evenement-specifieke aangepaste CSS"
},
"admin": {
"title": "Beheerpaneel",
- "welcome": "Welkom terug, {{name}}",
"recentActivity": "Recente activiteit",
- "systemStatus": "Systeemstatus",
- "totalEvents": "Totaal evenementen",
- "activeGalleries": "Actieve galerijen",
"storageUsed": "Gebruikte opslag",
"totalPhotos": "Totaal foto's",
"storagePercent": "{{percent}}% van limiet {{limit}}",
@@ -1345,9 +1309,6 @@
"archivedEvents": "Gearchiveerde evenementen",
"systemHealth": "Systeemgezondheid",
"health": {
- "healthy": "Gezond",
- "warning": "Waarschuwing",
- "error": "Fout",
"checking": "Controleren..."
},
"updates": {
@@ -1360,9 +1321,7 @@
"beta": "BETA",
"viewReleaseNotes": "Release-opmerkingen bekijken",
"updateAvailableShort": "v{{version}} beschikbaar",
- "checkForUpdates": "Controleren op updates",
"upToDate": "U bent up-to-date",
- "lastChecked": "Laatst gecontroleerd: {{time}}",
"updateNow": "Nu bijwerken",
"updateDialog": {
"title": "PicPeak bijwerken",
@@ -1376,8 +1335,6 @@
}
},
"notifications": "Meldingen",
- "viewAllNotifications": "Alle meldingen bekijken",
- "noNotifications": "Geen nieuwe meldingen",
"markAllRead": "Alles als gelezen markeren",
"clearAll": "Alles wissen",
"close": "Sluiten",
@@ -1387,16 +1344,13 @@
"eventArchived": "Evenement \"{{eventName}}\" is gearchiveerd",
"eventUpdated": "Evenement \"{{eventName}}\" is bijgewerkt",
"eventDeleted": "Evenement \"{{eventName}}\" is verwijderd",
- "photosUploaded": "{{count}} foto's geupload naar \"{{eventName}}\"",
"photoDeleted": "Foto verwijderd uit \"{{eventName}}\"",
- "photosBulkDeleted": "{{count}} foto's verwijderd uit \"{{eventName}}\"",
"eventExpiring": "Evenement \"{{eventName}}\" verloopt over {{days}} dagen",
"eventExpired": "Evenement \"{{eventName}}\" is verlopen",
"passwordChanged": "Wachtwoord gewijzigd door {{actorName}}",
"passwordReset": "Wachtwoord gereset voor \"{{eventName}}\"",
"settingsUpdated": "{{type}} instellingen bijgewerkt",
"emailTemplateUpdated": "E-mailsjabloon \"{{template}}\" bijgewerkt",
- "bulkDownload": "{{count}} foto's gedownload uit \"{{eventName}}\"",
"storageWarning": "Opslaggebruik op {{percentage}}%",
"adminLogout": "Beheerder {{actorName}} uitgelogd",
"categoryCreated": "Categorie \"{{name}}\" aangemaakt voor \"{{eventName}}\"",
@@ -1413,29 +1367,22 @@
"archiveDeleted": "Archief verwijderd voor \"{{eventName}}\"",
"archiveRestored": "Archief hersteld voor \"{{eventName}}\"",
"systemActivity": "Systeemactiviteit: {{type}}",
- "adminProfileUpdated": "Beheerdersprofiel bijgewerkt door {{actorName}}"
+ "adminProfileUpdated": "Beheerdersprofiel bijgewerkt door {{actorName}}",
+ "photosUploaded_one": "{{count}} foto geüpload naar \"{{eventName}}\"",
+ "photosUploaded_other": "{{count}} foto's geüpload naar \"{{eventName}}\"",
+ "photosBulkDeleted_one": "{{count}} foto verwijderd uit \"{{eventName}}\"",
+ "photosBulkDeleted_other": "{{count}} foto's verwijderd uit \"{{eventName}}\"",
+ "bulkDownload_one": "{{count}} foto gedownload uit \"{{eventName}}\"",
+ "bulkDownload_other": "{{count}} foto's gedownload uit \"{{eventName}}\""
},
"notificationToasts": {
"markedAllRead": "Alle meldingen als gelezen gemarkeerd",
- "clearedAll": "{{count}} meldingen gewist",
- "profileUpdated": "Beheerdersprofiel bijgewerkt"
+ "clearedAll_one": "{{count}} melding gewist",
+ "clearedAll_other": "{{count}} meldingen gewist"
},
- "markAsRead": "Markeren als gelezen",
- "markAllAsRead": "Alles als gelezen markeren",
- "notificationSettings": "Meldingsinstellingen",
"changePassword": "Wachtwoord wijzigen",
"darkMode": "Overschakelen naar donkere modus",
"lightMode": "Overschakelen naar lichte modus",
- "accountSettings": {
- "title": "Beheerdersaccount",
- "description": "Werk de inloggegevens bij die worden gebruikt om in te loggen bij PicPeak.",
- "username": "Gebruikersnaam",
- "usernamePlaceholder": "Beheerder",
- "email": "E-mail",
- "emailPlaceholder": "admin@voorbeeld.nl",
- "updateButton": "Profiel bijwerken"
- },
- "profileUpdateError": "Kan beheerdersprofiel niet bijwerken. Probeer het opnieuw.",
"loadingDashboard": "Dashboard laden...",
"activeEvents": "Actieve evenementen",
"expiringSoon": "Binnenkort verlopend",
@@ -1446,110 +1393,88 @@
"dashboardSubtitle": "Welkom terug! Hier ziet u wat er met uw galerijen gebeurt.",
"eventsExpiringSoon": "Binnenkort verlopende evenementen",
"noEventsExpiring": "Geen evenementen verlopen in de komende 7 dagen",
- "daysLeft": "{{count}} dag resterend",
- "daysLeft_plural": "{{count}} dagen resterend",
- "viewAllExpiringEvents": "Alle {{count}} verlopende evenementen bekijken",
"noRecentActivity": "Geen recente activiteit",
- "viewAllActivity": "Alle activiteit bekijken",
- "quickActions": "Snelle acties",
- "viewArchives": "Archieven bekijken",
- "analytics": "Statistieken",
- "activities": {
- "event_created": "Nieuw evenement aangemaakt: {{eventName}}",
- "photos_uploaded": "{{count}} foto's geupload naar {{eventName}}",
- "event_archived": "Evenement gearchiveerd: {{eventName}}",
- "archive_restored": "Archief hersteld: {{eventName}}",
- "archive_deleted": "Archief verwijderd: {{eventName}}",
- "archive_downloaded": "Archief gedownload: {{eventName}}",
- "email_config_updated": "E-mailconfiguratie bijgewerkt",
- "email_template_updated": "E-mailsjabloon bijgewerkt: {{template}}",
- "branding_updated": "Huisstijlinstellingen bijgewerkt",
- "theme_updated": "Thema-instellingen bijgewerkt",
- "bulk_download": "{{count}} foto's gedownload uit {{eventName}}",
- "gallery_password_entry": "Wachtwoord ingevoerd voor {{eventName}}",
- "expiration_warning_viewed": "Vervalwaarschuwing bekeken voor {{eventName}}",
- "feedback_settings_updated": "Feedbackinstellingen bijgewerkt",
- "feedback_moderated": "Feedback gemodereerd",
- "feedback_deleted": "Feedback verwijderd",
- "photo_like": "Foto geliked in {{eventName}}",
- "photo_favorite": "Foto favoriet gemaakt in {{eventName}}",
- "photo_rating": "Foto beoordeeld in {{eventName}}",
- "photo_comment": "Opmerking geplaatst bij foto in {{eventName}}",
- "guest_feedback_like": "Gast heeft een foto geliked in {{eventName}}",
- "guest_feedback_favorite": "Gast heeft een foto favoriet gemaakt in {{eventName}}",
- "guest_feedback_rating": "Gast heeft een foto beoordeeld in {{eventName}}",
- "guest_feedback_comment": "Gast heeft een opmerking geplaatst bij een foto in {{eventName}}",
- "word_filter_added": "Woordfilter toegevoegd",
- "external_import_completed": "Import externe media voltooid ({{imported}} geimporteerd, {{skipped}} overgeslagen)",
- "bulk_archive_completed": "Bulkarchivering voltooid",
- "event_activated": "Evenement geactiveerd: {{eventName}}",
- "event_deactivated": "Evenement gedeactiveerd: {{eventName}}",
- "photo_deleted": "Foto verwijderd uit {{eventName}}",
- "photos_bulk_deleted": "{{count}} foto's verwijderd uit {{eventName}}",
- "settings_updated": "Instellingen bijgewerkt",
- "event_updated": "Evenement bijgewerkt: {{eventName}}",
- "event_renamed": "Evenement hernoemd: {{eventName}}",
- "event_deleted": "Evenement verwijderd: {{eventName}}",
- "password_changed": "Wachtwoord gewijzigd",
- "email_resent": "Aanmaakmail opnieuw verzonden voor: {{eventName}}",
- "category_created": "Categorie aangemaakt: {{categoryName}}",
- "category_updated": "Categorie bijgewerkt: {{categoryName}}",
- "category_deleted": "Categorie verwijderd: {{categoryName}}",
- "general_settings_updated": "Algemene instellingen bijgewerkt",
- "favicon_uploaded": "Favicon geupload",
- "analytics_settings_updated": "Statistiekinstellingen bijgewerkt",
- "cms_page_updated": "CMS-pagina bijgewerkt: {{page}}",
- "security_settings_updated": "Beveiligingsinstellingen bijgewerkt",
- "password_reset": "Wachtwoord gereset voor: {{eventName}}",
- "admin_logout": "Beheerder {{actorName}} uitgelogd",
- "system_activity": "Systeemactiviteit: {{type}}",
- "unknown": "Onbekende activiteit"
- },
- "userManagement": "Gebruikersbeheer",
- "inviteUser": "Gebruiker uitnodigen",
- "pendingInvitations": "Openstaande uitnodigingen",
- "roles": {
- "super_admin": "Superbeheerder",
- "admin": "Beheerder",
- "editor": "Redacteur",
- "viewer": "Kijker"
- },
- "userStatus": {
- "active": "Actief",
- "inactive": "Inactief"
- },
- "inviteForm": {
- "email": "E-mailadres",
- "role": "Rol",
- "send": "Uitnodiging verzenden"
- },
- "acceptInvite": {
- "title": "Beheerderuitnodiging accepteren",
- "username": "Kies een gebruikersnaam",
- "password": "Wachtwoord aanmaken",
- "submit": "Account aanmaken"
- },
"photos": {
"hidden": "Verborgen",
"hideSelected": "Verbergen",
"showSelected": "Tonen",
"hiddenSuccess": "Foto's verborgen voor gasten",
- "visibleSuccess": "Foto's nu zichtbaar voor gasten"
+ "visibleSuccess": "Foto's nu zichtbaar voor gasten",
+ "processingStatus": "Verwerken…",
+ "processingFailed": "Mislukt",
+ "retryQueued": "Nieuwe poging in wachtrij"
+ },
+ "events": {
+ "tabs": {
+ "guests": "Gasten"
+ }
+ },
+ "daysLeft_one": "{{count}} dag resterend",
+ "daysLeft_other": "{{count}} dagen resterend",
+ "viewAllExpiringEvents_one": "Alle {{count}} verlopende evenementen bekijken",
+ "viewAllExpiringEvents_other": "Alle {{count}} verlopende evenementen bekijken",
+ "guests": {
+ "loading": "Laden…",
+ "aggregate": {
+ "empty": "Nog geen gastselecties.",
+ "description": "Foto's gesorteerd op het aantal afzonderlijke gasten dat ze heeft geliked of als favoriet gemarkeerd."
+ },
+ "inviteCreated": "Uitnodiging aangemaakt",
+ "inviteCreateError": "Aanmaken uitnodiging mislukt",
+ "inviteRevoked": "Uitnodiging ingetrokken",
+ "inviteRevokeError": "Intrekken uitnodiging mislukt",
+ "invitesTitle": "Gastuitnodigingen",
+ "createInvite": "Uitnodiging aanmaken",
+ "inviteName": "Gastnaam",
+ "inviteEmail": "E-mail (optioneel)",
+ "generateInvite": "Uitnodigingslink genereren",
+ "existingInvites": "Bestaande uitnodigingen",
+ "noInvites": "Nog geen uitnodigingen",
+ "copyLink": "Link kopiëren",
+ "revokeInvite": "Intrekken",
+ "deletedToast": "Gast verwijderd",
+ "deletedError": "Verwijderen gast mislukt",
+ "mergedToast": "Gasten samengevoegd",
+ "mergedError": "Samenvoegen gasten mislukt",
+ "forgetGuestConfirm": "Deze gast verwijderen? Hun selecties worden geanonimiseerd maar bewaard in geaggregeerde totalen.",
+ "exportError": "Export mislukt",
+ "mergeSelectAtLeastTwo": "Selecteer minimaal 2 gasten om samen te voegen",
+ "mergeConfirm_one": "{{count}} gast samenvoegen met {{name}}? Dit kan niet ongedaan worden gemaakt.",
+ "mergeConfirm_other": "{{count}} gasten samenvoegen met {{name}}? Dit kan niet ongedaan worden gemaakt.",
+ "backToList": "Terug naar lijst",
+ "title": "Gasten",
+ "mergeSelected_one": "{{count}} geselecteerd",
+ "mergeSelected_other": "{{count}} geselecteerd",
+ "mergeNow": "Geselecteerde samenvoegen",
+ "aggregateView": "Op populariteit",
+ "mergeMode": "Samenvoegen",
+ "exportAll": "Alles exporteren",
+ "empty": "Nog geen gasten geregistreerd.",
+ "columns": {
+ "name": "Naam",
+ "email": "E-mail",
+ "likes": "Likes",
+ "favorites": "Favorieten",
+ "comments": "Opmerkingen",
+ "ratings": "Beoordelingen",
+ "lastSeen": "Laatste bezoek"
+ },
+ "view": "Details bekijken",
+ "export": "Exporteren",
+ "forgetGuest": "Gast verwijderen",
+ "loadingDetail": "Selecties laden…",
+ "detail": {
+ "noComments": "Geen opmerkingen",
+ "empty": "Geen selecties in deze categorie"
+ }
}
},
- "permissions": {
- "insufficient": "U heeft geen toestemming om deze actie uit te voeren",
- "viewOnly": "Alleen bekijken"
- },
"acceptInvitation": {
"title": "Uitnodiging accepteren",
"subtitle": "Maak uw beheerdersaccount aan",
"validating": "Uitnodiging valideren...",
"invalidToken": "Ongeldige uitnodiging",
"invalidTokenMessage": "Deze uitnodigingslink is ongeldig of verlopen. Neem contact op met uw beheerder voor een nieuwe uitnodiging.",
- "expiredToken": "Uitnodiging verlopen",
- "expiredTokenMessage": "Deze uitnodiging is verlopen. Vraag een nieuwe uitnodiging aan bij uw beheerder.",
- "alreadyUsed": "Uitnodiging al gebruikt",
"alreadyUsedMessage": "Deze uitnodiging is al gebruikt om een account aan te maken.",
"invitedAs": "U bent uitgenodigd als",
"expiresAt": "Uitnodiging verloopt",
@@ -1576,7 +1501,6 @@
"strong": "Sterk"
},
"createAccount": "Account aanmaken",
- "creating": "Account aanmaken...",
"success": "Account aangemaakt!",
"successMessage": "Uw account is succesvol aangemaakt. U kunt nu inloggen met uw gegevens.",
"redirecting": "Doorverwijzen naar login over {{seconds}}...",
@@ -1591,23 +1515,14 @@
"usernameTooLong": "Gebruikersnaam mag maximaal 50 tekens bevatten",
"usernameInvalid": "Gebruikersnaam mag alleen letters, cijfers, underscores en koppeltekens bevatten",
"passwordRequired": "Wachtwoord is verplicht",
- "passwordTooShort": "Wachtwoord moet minimaal 12 tekens bevatten",
"passwordsDoNotMatch": "Wachtwoorden komen niet overeen",
"confirmPasswordRequired": "Bevestig uw wachtwoord",
- "usernameTaken": "Deze gebruikersnaam is al in gebruik",
- "emailTaken": "Er bestaat al een account met dit e-mailadres",
"genericError": "Kan account niet aanmaken. Probeer het opnieuw."
}
},
"errors": {
- "notFound": "Niet gevonden",
"galleryNotFound": "Galerij niet gevonden",
"galleryNotFoundMessage": "Deze galerij bestaat niet of is verwijderd.",
- "galleryArchived": "Galerij gearchiveerd",
- "galleryArchivedMessage": "Deze galerij is gearchiveerd en is niet meer toegankelijk. Neem contact op met de organisator als u toegang tot deze foto's nodig heeft.",
- "unauthorized": "Niet geautoriseerd",
- "forbidden": "Niet toegestaan",
- "serverError": "Serverfout",
"somethingWentWrong": "Er is iets misgegaan",
"tryAgainLater": "Probeer het later opnieuw",
"refreshPage": "Pagina vernieuwen",
@@ -1617,10 +1532,9 @@
"errorDetails": "Foutdetails",
"requiredFields": "Vul alle verplichte velden in",
"enterTestEmail": "Voer een test-e-mailadres in",
- "failedToCreateEvent": "Kan evenement niet aanmaken",
"eventCreationFailed": "Kan evenement niet aanmaken",
- "networkError": "Netwerkfout. Controleer uw verbinding en probeer het opnieuw.",
- "sessionExpired": "Sessie verlopen. Log opnieuw in."
+ "noShareLink": "Geen deellink beschikbaar",
+ "copyFailed": "Kopiëren van link mislukt"
},
"validation": {
"eventNameRequired": "Evenementnaam is verplicht",
@@ -1631,14 +1545,15 @@
"passwordRequired": "Wachtwoord is verplicht",
"passwordMinLength": "Wachtwoord moet minimaal 6 tekens bevatten",
"passwordsDoNotMatch": "Wachtwoorden komen niet overeen",
- "passwordSecurityRequirements": "Wachtwoord voldoet niet aan de beveiligingsvereisten",
- "expirationRange": "Vervaltijd moet tussen 1 en 365 dagen zijn"
+ "expirationRange": "Vervaltijd moet tussen 1 en 365 dagen zijn",
+ "required": "Dit veld is verplicht",
+ "expirationRequired": "Vervaldatum is verplicht.",
+ "eventDateRequired": "Evenementdatum is verplicht",
+ "passwordTooSimple": "Wachtwoord mag niet alleen uit cijfers bestaan. Gebruik een datumformaat zoals \"04.07.2025\""
},
"legal": {
"impressum": "Colofon",
- "datenschutz": "Privacybeleid",
- "termsOfService": "Algemene voorwaarden",
- "cookiePolicy": "Cookiebeleid"
+ "datenschutz": "Privacybeleid"
},
"toast": {
"saveSuccess": "Wijzigingen succesvol opgeslagen",
@@ -1647,9 +1562,6 @@
"deleteError": "Kan niet verwijderen",
"uploadSuccess": "Upload succesvol voltooid",
"uploadError": "Upload mislukt",
- "loginSuccess": "Succesvol ingelogd",
- "loginError": "Inloggen mislukt",
- "passwordChanged": "Wachtwoord succesvol gewijzigd",
"linkCopied": "Link gekopieerd naar klembord",
"eventCreated": "Evenement succesvol aangemaakt",
"eventUpdated": "Evenement succesvol bijgewerkt",
@@ -1657,14 +1569,10 @@
"settingsSaved": "Instellingen succesvol opgeslagen",
"themeUpdated": "Thema succesvol bijgewerkt",
"brandingUpdated": "Huisstijl succesvol bijgewerkt",
- "categoryAdded": "Categorie succesvol toegevoegd",
- "categoryDeleted": "Categorie succesvol verwijderd",
"categoryUpdated": "Categorie succesvol bijgewerkt",
"emailConfigSaved": "E-mailconfiguratie succesvol opgeslagen",
- "testEmailSent": "Test-e-mail succesvol verzonden",
- "pageUpdated": "Pagina succesvol bijgewerkt",
- "archiveRestored": "Archief succesvol hersteld",
- "archiveDeleted": "Archief permanent verwijderd"
+ "brandingThemeMissing": "Er is nog geen huisstijlthema opgeslagen.",
+ "brandingPaletteSynced": "Palet gesynchroniseerd vanuit Huisstijl."
},
"email": {
"title": "E-mailconfiguratie",
@@ -1672,28 +1580,9 @@
"loadingSettings": "E-mailinstellingen laden...",
"smtpConfiguration": "SMTP-configuratie",
"smtpHost": "SMTP-host",
- "smtpHostHelp": "Hostnaam van uw e-mailserver",
- "smtpPort": "SMTP-poort",
- "smtpPortHelp": "Meestal 587 voor TLS, 465 voor SSL, 25 voor onversleuteld",
- "smtpSecure": "SSL/TLS gebruiken",
- "smtpSecureHelp": "Inschakelen voor veilige e-mailverzending",
- "smtpUsername": "SMTP-gebruikersnaam",
- "smtpUsernameHelp": "Gebruikersnaam van uw e-mailaccount",
- "smtpPassword": "SMTP-wachtwoord",
- "smtpPasswordHelp": "Wachtwoord van uw e-mailaccount",
- "fromDetails": "Afzendergegevens",
"fromEmail": "Afzender-e-mail",
- "fromEmailHelp": "E-mailadres dat als afzender wordt weergegeven",
"fromName": "Afzendernaam",
- "fromNameHelp": "Naam die als afzender wordt weergegeven",
- "testConfiguration": "Configuratie testen",
- "testEmail": "Test-e-mailadres",
- "testEmailHelp": "Stuur een test-e-mail om de instellingen te verifiëren",
- "sendTestEmail": "Test-e-mail verzenden",
- "saveConfiguration": "Configuratie opslaan",
"emailTemplates": "E-mailsjablonen",
- "templateVariables": "Beschikbare variabelen",
- "previewTemplate": "Sjabloonvoorbeeld",
"smtpSettings": "SMTP-instellingen",
"testEmailSuccess": "Test-e-mail succesvol verzonden",
"saveSmtpSettings": "SMTP-instellingen opslaan",
@@ -1711,23 +1600,18 @@
"emailBody": "E-mailtekst",
"preview": "Voorbeeld",
"save": "Opslaan",
- "saveChanges": "Wijzigingen opslaan",
"templates": "Sjablonen",
- "variableHelp": "Gebruik deze variabelen in uw sjabloon. Ze worden vervangen door werkelijke waarden wanneer e-mails worden verzonden.",
"port": "Poort",
"security": "Beveiliging",
"username": "Gebruikersnaam",
"password": "Wachtwoord",
"enterPassword": "Voer wachtwoord in",
- "required": "verplicht",
"ignoreSslErrors": "SSL/TLS-certificaatfouten negeren",
"ignoreSslWarning": "Waarschuwing: Het uitschakelen van certificaatverificatie maakt de verbinding kwetsbaar voor man-in-the-middle-aanvallen. Schakel dit alleen in als u de SMTP-server vertrouwt en de beveiligingsimplicaties begrijpt.",
"brandingTitle": "E-mail huisstijl",
"brandingDescription": "Pas de kleuren aan die in e-mailsjablonen worden gebruikt. Wijzigingen zijn van toepassing op de headerbalk, knoppen, links en voettekstachtergrond.",
"primaryColor": "Primaire kleur",
- "primaryColorHint": "Gebruikt voor header, knoppen en links",
"secondaryColor": "Voettekstachtergrond",
- "secondaryColorHint": "Gebruikt voor de achtergrond van de voettekst",
"saveEmailColors": "E-mailkleuren opslaan",
"editor": {
"bold": "Vet",
@@ -1753,7 +1637,23 @@
"copiedFromLanguage": "Inhoud gekopieerd van {{language}}",
"noTranslation": "Nog geen vertaling",
"noTranslationYet": "Er bestaat nog geen vertaling voor deze taal. Kopieer van een bestaande taal om te beginnen:",
- "copyFrom": "Kopiëren van"
+ "copyFrom": "Kopiëren van",
+ "syncedFromBranding": "E-mailkleuren gesynchroniseerd vanuit Huisstijl. Klik op Opslaan om toe te passen.",
+ "syncFromBranding": "Synchroniseren vanuit huisstijl",
+ "primaryColorHelp": "Headerbalk, H2-koppen, knopachtergrond, linkkleur. Komt overeen met Huisstijl → Accent (gevuld).",
+ "secondaryColorHelp": "Achtergrond van de voettekstbalk. Komt overeen met Huisstijl → Oppervlak.",
+ "bodyBgColor": "Paginaachtergrond",
+ "bodyBgColorHelp": "De wrapper rondom de e-mailkaart — wat de ontvanger achter de e-mail ziet. Komt overeen met Huisstijl → Achtergrond.",
+ "containerBgColor": "E-mailkaart",
+ "containerBgColorHelp": "De witte kaart die de e-mailinhoud bevat. Komt overeen met Huisstijl → Oppervlak.",
+ "listBgColor": "Infopaneel",
+ "listBgColorHelp": "Achtergrond van de opsommingsinfopanelen in de e-mailtekst. Komt overeen met Huisstijl → Verhoogd.",
+ "bodyTextColor": "Bodytekst",
+ "bodyTextColorHelp": "Kleur van alinea's en vetgedrukte tekst. Komt overeen met Huisstijl → Primaire tekst.",
+ "mutedTextColor": "Voetteksttekst",
+ "mutedTextColorHelp": "Voetteksttekst en copyrightregel. Komt overeen met Huisstijl → Secundaire tekst.",
+ "buttonTextColor": "Knoptekst",
+ "buttonTextColorHelp": "Tekstkleur op gevulde knoppen. Moet goed contrasteren met de primaire kleur. Doorgaans wit."
},
"cms": {
"title": "CMS-pagina's",
@@ -1767,17 +1667,22 @@
"pageTitle": "Paginatitel",
"pageContent": "Pagina-inhoud",
"pageTitlePlaceholder": "Voer paginatitel in...",
- "saveChanges": "Wijzigingen opslaan",
"lastUpdated": "Laatst bijgewerkt:",
- "impressum": "Colofon",
- "datenschutz": "Privacybeleid",
"pageUpdated": "Pagina succesvol bijgewerkt",
"useExternalUrl": "Externe URL gebruiken",
"useExternalUrlHelp": "Bezoekers worden doorgestuurd naar een externe pagina in plaats van de interne inhoud te zien. De interne titel en inhoud blijven als fallback opgeslagen.",
"externalUrl": "Externe URL",
"externalUrlPlaceholder": "https://example.com/impressum",
"externalUrlInvalid": "Moet een geldige https://-URL zijn",
- "externalUrlActive": "Externe URL is actief — interne inhoud blijft bewaard maar wordt niet aan bezoekers getoond."
+ "externalUrlActive": "Externe URL is actief — interne inhoud blijft bewaard maar wordt niet aan bezoekers getoond.",
+ "logoUploaded": "Logo geüpload",
+ "logoCleared": "Logo verwijderd",
+ "pageLogo": "Paginalogo",
+ "pageLogoHelp": "Optioneel. Indien ingesteld, wordt dit gebruikt in plaats van het globale huisstijllogo op deze pagina.",
+ "noLogo": "geen overschrijving",
+ "replaceLogo": "Logo vervangen",
+ "uploadLogo": "Logo uploaden",
+ "clearLogo": "Sitestandaard gebruiken"
},
"eventTypes": {
"title": "Evenementtypes",
@@ -1828,12 +1733,6 @@
}
},
"backup": {
- "external": {
- "warning": {
- "title": "Externe media uitgesloten",
- "body": "Deze installatie verwijst naar foto's vanuit /external-media. Deze originelen zijn uitgesloten van back-ups. Miniaturen en database worden wel geback-upt."
- }
- },
"title": "Back-upbeheer",
"subtitle": "Beheer systeemback-ups, configureer geautomatiseerde back-ups en herstel vanuit eerdere back-ups.",
"tabs": {
@@ -1854,22 +1753,12 @@
"actions": {
"runBackupNow": "Nu back-up maken",
"starting": "Starten...",
- "running": "Bezig...",
"testConnection": "Verbinding testen",
- "save": "Configuratie opslaan",
"delete": "Verwijderen",
"view": "Details bekijken",
- "download": "Downloaden",
- "refresh": "Vernieuwen"
+ "download": "Downloaden"
},
"dashboard": {
- "backupHealth": "Back-upstatus",
- "healthStatus": {
- "excellent": "Uitstekend",
- "good": "Goed",
- "warning": "Waarschuwing",
- "critical": "Kritiek"
- },
"health": {
"title": "Back-upstatus"
},
@@ -1879,9 +1768,7 @@
"upToDate": "Back-up is actueel",
"recent": "Back-up is recent",
"gettingOld": "Back-up wordt oud",
- "outdated": "Back-up is verouderd",
- "failed": "Laatste back-up mislukt",
- "old": "Back-up wordt oud"
+ "outdated": "Back-up is verouderd"
},
"stats": {
"totalBackups": "Totaal back-ups",
@@ -1890,7 +1777,6 @@
"backupStatus": "Back-upstatus",
"last": "Laatste",
"files": "bestanden",
- "minutes": "{{count}}m",
"active": "Actief",
"inactive": "Inactief",
"noBackupsYet": "Nog geen back-ups"
@@ -1908,16 +1794,10 @@
},
"coverage": {
"title": "Back-updekking",
- "database": "Database",
- "photos": "Foto's",
- "archives": "Archieven",
- "systemFiles": "Systeembestanden",
"included": "Inbegrepen",
- "excluded": "Uitgesloten",
- "optional": "Optioneel"
+ "excluded": "Uitgesloten"
},
"storageDestination": "Opslagbestemming",
- "nextScheduledBackup": "Volgende geplande back-up",
"backupType": "{{type}} back-up",
"noDestinationSet": "Geen bestemming ingesteld"
},
@@ -1944,42 +1824,24 @@
"destinationPathHelp": "Lokaal mappad voor het opslaan van back-ups",
"destinationPathPlaceholder": "/pad/naar/back-up/map",
"rsyncHost": "Externe host",
- "rsyncHostHelp": "SSH-hostnaam of IP-adres",
"rsyncHostPlaceholder": "backup.voorbeeld.nl",
"rsyncUser": "SSH-gebruiker",
- "rsyncUserHelp": "Gebruikersnaam voor SSH-verbinding",
"rsyncUserPlaceholder": "backup-gebruiker",
"rsyncPath": "Extern pad",
- "rsyncPathHelp": "Mappad op externe server",
"rsyncPathPlaceholder": "/home/backup/photo-sharing",
"rsyncSshKey": "SSH-prive-sleutel",
"rsyncSshKeyHelp": "SSH-prive-sleutel voor authenticatie (optioneel)",
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
"s3Endpoint": "S3-eindpunt",
"s3EndpointHelp": "S3 API-eindpunt (bijv. s3.amazonaws.com)",
- "s3EndpointPlaceholder": "https://s3.amazonaws.com",
"s3Bucket": "Bucketnaam",
- "s3BucketHelp": "S3-bucket voor het opslaan van back-ups",
- "s3BucketPlaceholder": "mijn-backup-bucket",
"s3AccessKey": "Toegangssleutel-ID",
- "s3AccessKeyHelp": "AWS/S3 toegangssleutel-ID",
- "s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXAMPLE",
"s3SecretKey": "Geheime toegangssleutel",
- "s3SecretKeyHelp": "AWS/S3 geheime toegangssleutel",
- "s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
- "s3Region": "Regio",
- "s3RegionHelp": "S3-regio (bijv. us-east-1)",
- "s3RegionPlaceholder": "us-east-1"
+ "s3Region": "Regio"
},
"schedule": {
"title": "Back-upschema",
"scheduleType": "Schematype",
- "scheduleOptions": {
- "hourly": "Elk uur",
- "daily": "Dagelijks",
- "weekly": "Wekelijks",
- "custom": "Aangepaste cron-expressie"
- },
"options": {
"hourly": "Elk uur",
"daily": "Dagelijks",
@@ -2001,9 +1863,7 @@
"archives": "Archieven",
"archivesHelp": "Gearchiveerde evenement-ZIP-bestanden",
"thumbnails": "Miniaturen",
- "thumbnailsHelp": "Gegenereerde miniatuurafbeeldingen (kunnen opnieuw worden aangemaakt)",
- "tempFiles": "Tijdelijke bestanden",
- "tempFilesHelp": "Tijdelijke upload- en verwerkingsbestanden"
+ "thumbnailsHelp": "Gegenereerde miniatuurafbeeldingen (kunnen opnieuw worden aangemaakt)"
},
"advancedOptions": {
"title": "Geavanceerde opties",
@@ -2012,15 +1872,7 @@
"encryption": "Versleuteling inschakelen",
"encryptionHelp": "Versleutel back-ups voor extra beveiliging",
"encryptionPassphrase": "Versleutelingswachtwoord",
- "encryptionPassphraseHelp": "Sterk wachtwoord voor back-upversleuteling",
- "confirmPassphrase": "Bevestig wachtwoord",
- "passphrasesDontMatch": "Wachtwoorden komen niet overeen"
- },
- "validation": {
- "requiredFields": "Vul alle verplichte velden in",
- "invalidCron": "Ongeldige cron-expressie",
- "connectionTestFailed": "Verbindingstest mislukt",
- "connectionTestSuccess": "Verbindingstest geslaagd!"
+ "encryptionPassphraseHelp": "Sterk wachtwoord voor back-upversleuteling"
},
"messages": {
"requiredFields": "Vul alle verplichte velden in",
@@ -2033,23 +1885,6 @@
},
"history": {
"searchPlaceholder": "Back-ups zoeken...",
- "allStatus": "Alle statussen",
- "status": {
- "completed": "Voltooid",
- "failed": "Mislukt",
- "running": "Bezig",
- "partial": "Gedeeltelijk"
- },
- "deleteConfirm": "Weet u zeker dat u deze back-up van {{date}} wilt verwijderen?",
- "noBackups": "Geen back-ups gevonden",
- "tableHeaders": {
- "date": "Datum",
- "type": "Type",
- "status": "Status",
- "size": "Grootte",
- "duration": "Duur",
- "actions": "Acties"
- },
"columns": {
"status": "Status",
"dateTime": "Datum & Tijd",
@@ -2067,35 +1902,10 @@
"errorDetails": "Foutdetails",
"manifest": "Manifest"
},
- "statistics": "Statistieken",
- "errors": "Fouten",
- "backupDetails": {
- "backupId": "Back-up-ID",
- "startTime": "Starttijd",
- "endTime": "Eindtijd",
- "destination": "Bestemming",
- "filesProcessed": "Verwerkte bestanden",
- "totalSize": "Totale grootte",
- "compressionRatio": "Compressieverhouding",
- "errorLog": "Foutenlog",
- "noErrors": "Geen fouten opgetreden"
- },
"pagination": {
"showing": "{{from}}-{{to}} van {{total}} back-ups weergegeven",
"previous": "Vorige",
"next": "Volgende"
- },
- "filter": {
- "allStatus": "Alle statussen",
- "completed": "Voltooid",
- "failed": "Mislukt",
- "running": "Bezig",
- "partial": "Gedeeltelijk"
- },
- "noBackupsFound": "Geen back-ups gevonden",
- "backupsWillAppear": "Back-ups verschijnen hier zodra ze zijn aangemaakt",
- "messages": {
- "deleteSuccess": "Back-up succesvol verwijderd"
}
},
"restore": {
@@ -2208,12 +2018,6 @@
"current": "Huidig",
"statusDetails": "Statusdetails",
"restoreLogs": "Hersteltlogs",
- "steps": {
- "completed": "Voltooid",
- "running": "Bezig",
- "failed": "Mislukt",
- "pending": "In afwachting"
- },
"success": {
"title": "Herstel succesvol voltooid",
"message": "Uw gegevens zijn hersteld. Controleer of alles correct werkt."
@@ -2226,20 +2030,13 @@
"starting": "Starten...",
"validating": "Valideren...",
"startNewRestore": "Nieuw herstel starten"
- },
- "messages": {
- "restoreStarted": "Herstel succesvol gestart"
}
},
"messages": {
"backupStarted": "Back-up succesvol gestart",
"backupFailed": "Kan back-up niet starten",
"configUpdated": "Back-upconfiguratie bijgewerkt",
- "configUpdateFailed": "Kan configuratie niet bijwerken",
- "backupDeleted": "Back-up succesvol verwijderd",
- "deleteFailed": "Kan back-up niet verwijderen",
- "testEmailSent": "Verbindingstest geslaagd!",
- "testEmailFailed": "Verbindingstest mislukt"
+ "configUpdateFailed": "Kan configuratie niet bijwerken"
}
},
"cssTemplates": {
@@ -2266,8 +2063,6 @@
"maintenance": {
"title": "Systeemonderhoud",
"message": "We voeren momenteel gepland onderhoud uit om onze service te verbeteren. We zijn binnenkort weer online.",
- "expectedCompletion": "Verwachte voltooiingstijd:",
- "checkBackLater": "Probeer het later opnieuw",
"urgentMatters": "Voor dringende zaken, neem contact op met"
},
"passwordChange": {
@@ -2346,18 +2141,7 @@
"pendingApproval": "In afwachting van goedkeuring",
"noComments": "Nog geen opmerkingen. Wees de eerste om een opmerking te plaatsen!",
"rating": "Beoordeling",
- "ratePhoto": "Beoordeel deze foto",
- "yourRating": "Uw beoordeling",
- "averageRating": "Gemiddelde beoordeling",
- "totalRatings": "beoordelingen",
"likes": "Likes",
- "favorites": "Favorieten",
- "likePhoto": "Like deze foto",
- "favoritePhoto": "Toevoegen aan favorieten",
- "photoFeedback": "Fotofeedback",
- "hasFeedback": "Heeft feedback",
- "hasComments": "Heeft opmerkingen",
- "hasRating": "Heeft beoordeling",
"settings": {
"title": "Gastfeedbackinstellingen",
"enableFeedback": "Feedback inschakelen",
@@ -2369,33 +2153,117 @@
"comments": "Opmerkingen",
"commentsDesc": "Tekstopmerkingen bij foto's",
"favorites": "Favorieten",
- "favoritesDesc": "Foto's als favoriet markeren"
- }
+ "favoritesDesc": "Foto's als favoriet markeren",
+ "identityMode": "Identiteitsmodus",
+ "identityModeSimple": "Eenvoudige feedback",
+ "identityModeSimpleDesc": "Anoniem, apparaatgebaseerd. Alle bezoekers op hetzelfde apparaat delen de toestand.",
+ "identityModeGuest": "Selecties per gast",
+ "identityModeGuestDesc": "Elke bezoeker voert zijn naam in. Maakt tracking per gast en beheerdersinzichten mogelijk.",
+ "privacyModeration": "Privacy & Moderatie",
+ "requireInfo": "Naam en e-mail vereisen",
+ "requireInfoDesc": "Gasten moeten naam en e-mail opgeven om feedback te plaatsen",
+ "moderateComments": "Opmerkingen modereren",
+ "moderateCommentsDesc": "Opmerkingen vereisen goedkeuring voordat ze zichtbaar zijn",
+ "showToGuests": "Feedback tonen aan gasten",
+ "showToGuestsDesc": "Andere gasten kunnen beoordelingen, likes en goedgekeurde opmerkingen zien",
+ "enableRateLimiting": "Snelheidsbeperking inschakelen",
+ "rateLimitingDesc": "Voorkom spam door de feedbackfrequentie te beperken",
+ "timeWindow": "Tijdvenster (minuten)",
+ "maxRequests": "Max. verzoeken"
+ },
+ "settingsUpdated": "Feedbackinstellingen bijgewerkt",
+ "settingsUpdateError": "Bijwerken instellingen mislukt",
+ "moderated": "Feedback gemodereerd",
+ "deleted": "Feedback verwijderd",
+ "exported": "Feedback geëxporteerd",
+ "exportError": "Exporteren feedback mislukt",
+ "title": "Feedbackbeheer",
+ "exportCSV": "CSV exporteren",
+ "exportJSON": "JSON exporteren",
+ "tabs": {
+ "settings": "Instellingen",
+ "feedback": "Feedback",
+ "analytics": "Statistieken",
+ "moderation": "Moderatie"
+ },
+ "allTypes": "Alle typen",
+ "types": {
+ "rating": "Beoordelingen",
+ "like": "Likes",
+ "comment": "Opmerkingen",
+ "favorite": "Favorieten"
+ },
+ "allStatuses": "Alle statussen",
+ "status": {
+ "pending": "In behandeling",
+ "approved": "Goedgekeurd",
+ "hidden": "Verborgen"
+ },
+ "noFeedback": "Geen feedback gevonden",
+ "approve": "Goedkeuren",
+ "hide": "Verbergen",
+ "unhide": "Zichtbaar maken",
+ "confirmDelete": "Weet u zeker dat u deze feedback wilt verwijderen?",
+ "avgRating": "Gemiddelde beoordeling",
+ "totalRatings_one": "{{count}} beoordeling",
+ "totalRatings_other": "{{count}} beoordelingen",
+ "totalLikes": "Totaal likes",
+ "totalComments": "Totaal opmerkingen",
+ "pendingModeration_one": "{{count}} in behandeling",
+ "pendingModeration_other": "{{count}} in behandeling",
+ "totalInteractions": "Totale interacties",
+ "topRated": "Hoogst beoordeelde foto's",
+ "recentComments": "Recente opmerkingen",
+ "wordFilters": "Woordfilters",
+ "wordFiltersDesc": "Beheer geblokkeerde woorden voor opmerkingenmoderatie",
+ "manageFilters": "Woordfilters beheren",
+ "manage": "Feedback beheren",
+ "ratingSubmitted": "Beoordeling ingediend",
+ "ratingError": "Indienen beoordeling mislukt",
+ "rateStar_one": "{{count}} ster beoordelen",
+ "rateStar_other": "{{count}} sterren beoordelen",
+ "ratingsCount_one": "{{count}} beoordeling",
+ "ratingsCount_other": "{{count}} beoordelingen",
+ "likeError": "Bijwerken like mislukt",
+ "unlike": "Like verwijderen",
+ "like": "Like",
+ "favoriteError": "Bijwerken favoriet mislukt",
+ "unfavorite": "Uit favorieten verwijderen",
+ "favorite": "Aan favorieten toevoegen",
+ "invalidEmail": "Ongeldig e-mailadres",
+ "identityRequired": "Uw informatie vereist",
+ "identityReason": "Geef uw naam en e-mail op om {{type}} in te dienen.",
+ "namePlaceholder": "Voer uw naam in",
+ "emailPlaceholder": "Voer uw e-mail in",
+ "submitFeedback": "Feedback verzenden",
+ "moderationSuccess": "Feedback succesvol gemodereerd",
+ "pendingModeration": "In afwachting van moderatie",
+ "pending": "in behandeling",
+ "noPendingComments": "Geen opmerkingen in afwachting van moderatie",
+ "onPhoto": "Op foto",
+ "showAll_one": "Alle {{count}} openstaande opmerking tonen",
+ "showAll_other": "Alle {{count}} openstaande opmerkingen tonen",
+ "viewAllFeedback": "Alle feedback en instellingen bekijken"
},
"filter": {
"feedbackFilters": "Feedbackfilters",
"clear": "Wissen",
"rating": "Beoordeling",
- "allPhotos": "Alle foto's",
- "anyRating": "Elke beoordeling",
- "oneStarPlus": "1+ sterren",
- "twoStarsPlus": "2+ sterren",
- "threeStarsPlus": "3+ sterren",
- "fourStarsPlus": "4+ sterren",
- "fiveStarsOnly": "Alleen 5 sterren",
"hasLikes": "Heeft likes",
"hasFavorites": "Heeft favorieten",
"hasComments": "Heeft opmerkingen",
"showingPhotos": "Totaal foto's",
- "withRatings": "Met beoordelingen"
+ "withRatings": "Met beoordelingen",
+ "combineWith": "Combineren met"
},
"export": {
"button": "Exporteren",
"success": "Export succesvol gedownload",
"error": "Export mislukt: ",
- "exportSelected": "{{count}} geselecteerde exporteren",
"exportFiltered": "Gefilterde foto's exporteren",
- "hint": "Selecteer foto's of pas filters toe om te exporteren"
+ "hint": "Selecteer foto's of pas filters toe om te exporteren",
+ "exportSelected_one": "{{count}} geselecteerde exporteren",
+ "exportSelected_other": "{{count}} geselecteerde exporteren"
},
"adminLogin": {
"title": "Beheerder login",
@@ -2410,7 +2278,6 @@
"passwordRequired": "Wachtwoord is verplicht",
"passwordMinLength": "Wachtwoord moet minimaal 6 tekens bevatten",
"rememberMe": "Onthoud mij",
- "forgotPassword": "Wachtwoord vergeten?",
"signIn": "Inloggen",
"loginSuccess": "Succesvol ingelogd!",
"networkError": "Netwerkfout. Controleer uw verbinding en probeer het opnieuw.",
@@ -2455,5 +2322,17 @@
"filenameAZ": "Bestandsnaam (A-Z)",
"filenameZA": "Bestandsnaam (Z-A)",
"dateTaken": "Opnamedatum"
+ },
+ "photos": {
+ "moveToCategory_one": "{{count}} foto naar categorie verplaatsen",
+ "moveToCategory_other": "{{count}} foto's naar categorie verplaatsen",
+ "selectCategory": "Categorie selecteren",
+ "uncategorized": "Niet gecategoriseerd",
+ "movePhotos": "Foto's verplaatsen",
+ "selectedCategory": "geselecteerde categorie",
+ "movedToCategory_one": "{{count}} foto verplaatst naar {{category}}",
+ "movedToCategory_other": "{{count}} foto's verplaatst naar {{category}}",
+ "moveToCategoryFailed": "Verplaatsen naar categorie mislukt",
+ "moveToCategory": "Naar categorie verplaatsen"
}
}
diff --git a/frontend/src/i18n/locales/pt.json b/frontend/src/i18n/locales/pt.json
index b864b187..b3678f04 100644
--- a/frontend/src/i18n/locales/pt.json
+++ b/frontend/src/i18n/locales/pt.json
@@ -81,8 +81,6 @@
"delete": "Excluir",
"edit": "Editar",
"add": "Adicionar",
- "search": "Buscar",
- "filter": "Filtrar",
"sortBy": "Ordenar por",
"yes": "Sim",
"no": "Não",
@@ -91,35 +89,41 @@
"previous": "Anterior",
"close": "Fechar",
"logout": "Sair",
- "menu": "Menu",
"change": "Alterar",
"remove": "Remover",
"download": "Baixar",
"downloadAll": "Baixar Todos",
- "uploading": "Enviando...",
- "uploaded": "Enviado",
"photo": "foto",
"photos": "fotos",
"video": "vídeo",
- "videos": "vídeos",
"media": "mídia",
- "restore": "Restaurar",
- "actions": "Ações",
- "refresh": "Atualizar",
- "preview": "Prévia",
- "processing": "Processando...",
"upload": "Enviar",
- "days": "dias",
"customize": "Customizar",
"hide": "Ocultar",
"unknown": "Desconhecido",
"notSet": "Não definido",
"of": "de",
- "up": "Cima",
- "select": "Selecionar",
"selected": "Selecionado",
"chunk": "Fragmento",
- "optional": "opcional"
+ "optional": "opcional",
+ "tryAgain": "Tentar novamente",
+ "active": "Ativo",
+ "inactive": "Inativo",
+ "create": "Criar",
+ "unknownDate": "Data desconhecida",
+ "pageOf": "Página {{current}} de {{total}}",
+ "collapse": "Recolher",
+ "expand": "Expandir",
+ "submitting": "A enviar…",
+ "copy": "Copiar",
+ "copied": "Copiado!",
+ "applying": "A aplicar…",
+ "done": "Concluído",
+ "retry": "Tentar novamente",
+ "characters": "caracteres",
+ "saveChanges": "Guardar alterações",
+ "resetChanges": "Repor alterações",
+ "dismiss": "Dispensar"
},
"upload": {
"photoCategory": "Categoria da Foto",
@@ -127,42 +131,37 @@
"eventSpecific": "(Específico do evento)",
"clickToUpload": "Clique para enviar ou arraste e solte",
"fileRequirements": "JPEG, PNG ou WebP (máx. 50MB por arquivo, {{limit}} arquivos por envio)",
- "fileRequirementsMedia": "Imagens JPEG, PNG ou WebP, além de vídeos MP4/MOV/WEBM (máx. 50MB por arquivo, {{limit}} arquivos por envio)",
- "unsupportedFiles": "Alguns arquivos foram ignorados pois o formato não é suportado (use JPEG/PNG/WebP/MP4/MOV/WEBM).",
"selectedFiles": "Arquivos selecionados",
"uploading": "Enviando...",
"uploadComplete": "Envio concluído!",
- "uploadFailed": "Falha no envio",
"someFilesFailed": "Falha ao enviar alguns arquivos",
"replaceByName": "Substituir fotos existentes com o mesmo nome",
- "replacedFiles": "{{count}} foto(s) substituída(s)",
"uploadPhotos": "Enviar Fotos",
"uploadMedia": "Enviar Fotos e Vídeos",
- "importExternal": "Importar de Pasta Externa",
- "externalImportInfo": "Todas as imagens da pasta selecionada serão importadas.",
- "selectExternalFolder": "Selecione a pasta externa em /external-media",
- "importFromSelectedFolder": "Importar da pasta selecionada",
"maxFilesReached": "Máximo de {{limit}} arquivos permitido",
"someFilesSkipped": "Apenas {{allowed}} arquivos adicionais podem ser adicionados (limite {{limit}})",
"tooManyFiles": "O limite máximo é de {{limit}} arquivos por vez",
"limitInfo": "{{selected}} de {{limit}} arquivos selecionados ({{remaining}} restantes)",
"limitReached": "Limite de envio atingido ({{limit}} arquivos por lote)",
- "uploadingChunks": "Enviando {{count}} arquivos em {{total}} lotes...",
- "mediaCategory": "Categoria de mídia",
- "uploadAction": "Enviar {{count}} arquivos"
+ "replacedFiles_many": "{{count}} fotos substituídas",
+ "replacedFiles_one": "{{count}} foto substituída",
+ "replacedFiles_other": "{{count}} fotos substituídas",
+ "processingFailed_many": "{{count}} fotos falharam ao processar",
+ "processingFailed_one": "{{count}} foto falhou ao processar",
+ "processingFailed_other": "{{count}} fotos falharam ao processar",
+ "processing": "A processar fotos…",
+ "processingProgress": "{{complete}} de {{total}} concluídos",
+ "processingHint": "Os ficheiros foram enviados. O PicPeak está a gerar miniaturas e a ler metadados. Pode sair desta página — o trabalho continua em segundo plano.",
+ "transferring": "A transferir",
+ "uploadingChunks_many": "{{count}} fragmentos a enviar",
+ "uploadingChunks_one": "{{count}} fragmento a enviar",
+ "uploadingChunks_other": "{{count}} fragmentos a enviar",
+ "retryFailed": "Tentar novamente os falhados"
},
"navigation": {
"dashboard": "Painel",
"events": "Eventos",
- "archives": "Arquivos",
- "settings": "Configurações",
- "eventTypes": "Tipos de Evento",
- "branding": "Identidade Visual",
- "analytics": "Análise",
- "emailSettings": "Configurações de E-mail",
- "backup": "Backup e Restauração",
- "cmsPages": "Páginas CMS",
- "users": "Usuários"
+ "settings": "Configurações"
},
"archives": {
"title": "Arquivos",
@@ -205,67 +204,44 @@
"deleteSuccess": "Arquivo excluído permanentemente"
},
"auth": {
- "login": "Entrar",
"password": "Senha",
"enterPassword": "Digite a Senha da Galeria",
"passwordPlaceholder": "Digite a senha da galeria",
"invalidPassword": "Senha inválida",
"wrongPassword": "Senha incorreta. Verifique e tente novamente.",
"tooManyAttempts": "Muitas tentativas falhas. Tente novamente mais tarde.",
- "sessionExpired": "Sessão expirada",
"pleaseEnterPassword": "Por favor, digite uma senha",
"passwordHint": "A senha foi fornecida pelo organizador do evento. Entre em contato se não a tiver."
},
"gallery": {
- "title": "Galeria de Fotos",
- "welcomeMessage": "Mensagem de Boas-vindas",
- "expiresOn": "Expira em",
"expires": "Expira",
"expired": "Expirada",
- "daysRemaining": "{{days}} dias restantes",
- "dayRemaining": "1 dia restante",
- "hoursRemaining": "{{hours}} horas restantes",
- "expiredMessage": "Esta galeria expirou em {{date}}",
"contactOrganizer": "Entre em contato com o organizador do evento se precisar de acesso a estas fotos",
"searchPhotos": "Buscar fotos por nome de arquivo...",
"sortByDate": "Ordenar por Data",
"sortByName": "Ordenar por Nome",
"sortBySize": "Ordenar por Tamanho",
"allPhotos": "Todas as Fotos",
- "filter": "Filtrar",
"feedbackFilter": "Filtro de Feedback",
"all": "Todos",
"liked": "Curtidas",
"favorited": "Favoritadas",
"favorites": "Favoritas",
- "downloadSelected": "Baixar {{count}} Selecionadas",
- "shareGallery": "Compartilhar Galeria",
"needHelp": "Precisa de ajuda? Contate-nos em",
"noPhotosFound": "Nenhuma foto encontrada",
"failedToLoad": "Falha ao carregar fotos",
"tryAgain": "Tentar Novamente",
"loading": "Carregando galeria...",
"expiredOn": "Esta galeria expirou em {{date}}.",
- "expiresIn": "A galeria expira em {{count}} dia",
- "expiresIn_plural": "A galeria expira em {{count}} dias",
"downloadBefore": "Baixe suas fotos antes que fiquem indisponíveis.",
- "publicGalleryTitle": "Esta galeria é acessível ao público",
- "publicGallerySubtitle": "Carregando as fotos agora...",
"viewGallery": "Ver Galeria",
"downloadAll": "Baixar Todas",
- "downloading": "Baixando {{count}} foto...",
- "downloading_plural": "Baixando {{count}} fotos...",
- "downloadedPhotos": "{{count}} foto baixada!",
- "downloadedPhotos_plural": "{{count}} fotos baixadas!",
"downloadError": "Algumas fotos não puderam ser baixadas",
"selectPhotos": "Selecionar Fotos",
"cancelSelection": "Cancelar Seleção",
- "photosSelected": "{{count}} selecionadas",
"selectAll": "Selecionar Todas",
"deselectAll": "Desmarcar Todas",
"deleteSelected": "Excluir Selecionadas",
- "photosCount": "{{count}} foto",
- "photosCount_plural": "{{count}} fotos",
"searchByFilename": "Buscar por nome do arquivo...",
"uncategorized": "Sem categoria",
"sortAscending": "Ordem crescente",
@@ -273,8 +249,6 @@
"remaining": "restantes",
"selectPhotosHint": "Dica: Use Ctrl+Clique (Cmd+Clique no Mac) para selecionar várias fotos rapidamente",
"filters": "Filtros",
- "openFilters": "Abrir filtros",
- "toggleSidebar": "Alternar barra lateral",
"toggleMenu": "Alternar menu",
"allCategories": "Todas as Categorias",
"categories": "Categorias",
@@ -307,14 +281,61 @@
"anonymous": "Anônimo"
},
"rated": "Avaliado",
- "commented": "Comentado"
+ "commented": "Comentado",
+ "expiresIn_many": "A galeria expira em {{count}} dias",
+ "expiresIn_one": "A galeria expira em {{count}} dia",
+ "expiresIn_other": "A galeria expira em {{count}} dias",
+ "downloading_many": "A descarregar {{count}} fotos…",
+ "downloading_one": "A descarregar 1 foto…",
+ "downloading_other": "A descarregar {{count}} fotos…",
+ "photosSelected_many": "{{count}} fotos selecionadas",
+ "photosSelected_one": "{{count}} foto selecionada",
+ "photosSelected_other": "{{count}} fotos selecionadas",
+ "downloadSelected_many": "Descarregar {{count}} fotos",
+ "downloadSelected_one": "Descarregar {{count}} foto",
+ "downloadSelected_other": "Descarregar {{count}} fotos",
+ "guestRecovery": {
+ "invalidEmail": "Introduza um endereço de e-mail válido",
+ "codeSent": "Verifique a sua caixa de entrada para um código de verificação.",
+ "requestError": "Não foi possível enviar o código. Tente novamente.",
+ "invalidCode": "Introduza o código de 6 dígitos",
+ "verifyError": "Código inválido ou expirado.",
+ "back": "Voltar",
+ "title": "Recuperar as suas seleções",
+ "emailStepDescription": "Introduza o e-mail que utilizou anteriormente. Enviaremos um código de verificação de 6 dígitos.",
+ "codeStepDescription": "Introduza o código de 6 dígitos que enviámos para o seu e-mail.",
+ "emailLabel": "E-mail",
+ "sendCode": "Enviar código",
+ "codeLabel": "Código de verificação",
+ "verifyCode": "Verificar e continuar"
+ },
+ "guestPrompt": {
+ "nameRequired": "O nome é obrigatório",
+ "invalidEmail": "Endereço de e-mail inválido",
+ "emailRequired": "O e-mail é obrigatório",
+ "error": "Falha no registo",
+ "title": "Bem-vindo — qual é o seu nome?",
+ "description": "As suas seleções serão guardadas com este nome para que o fotógrafo saiba quais as fotos de que gosta.",
+ "nameLabel": "O seu nome",
+ "namePlaceholder": "Introduza o seu nome",
+ "emailLabelRequired": "E-mail",
+ "emailLabel": "E-mail (opcional)",
+ "emailPlaceholder": "voce@exemplo.pt",
+ "submit": "Continuar",
+ "alreadyHere": "Já estive aqui antes"
+ },
+ "footer": {
+ "forgetMeConfirm": "O seu nome e seleções serão removidos desta galeria.",
+ "forgetMe": "Esquecer-me ({{name}})"
+ },
+ "photosCount_many": "{{count}} fotos",
+ "photosCount_one": "{{count}} foto",
+ "photosCount_other": "{{count}} fotos",
+ "poweredBy": "Desenvolvido por PicPeak"
},
"categories": {
"title": "Categorias de Fotos",
- "global": "Categorias Globais",
- "eventSpecific": "Categorias Específicas do Evento",
"addCategory": "Adicionar Categoria",
- "organizationInfo": "Organize suas fotos em categorias. Elas ajudam os convidados a navegar e encontrar tipos específicos de fotos.",
"eventSpecificCategories": "Categorias Específicas do Evento",
"noEventSpecificCategories": "Sem categorias específicas. As categorias globais estão disponíveis por padrão.",
"globalCategoriesAlwaysAvailable": "Categorias Globais (sempre disponíveis):",
@@ -324,10 +345,8 @@
"failedToCreateCategory": "Falha ao criar categoria",
"failedToDeleteCategory": "Falha ao excluir categoria",
"categoryName": "Nome da categoria",
- "noCategory": "Sem categoria",
"noCategoriesYet": "Ainda não há categorias. Crie sua primeira categoria para organizar as fotos.",
"deleteConfirm": "Tem certeza que deseja excluir \"{{name}}\"?",
- "cannotDelete": "Não é possível excluir uma categoria com fotos. Reatribua as fotos primeiro.",
"setCoverPhoto": "Definir Foto de Capa",
"removeCoverPhoto": "Remover Foto de Capa",
"coverPhotoSet": "Foto de capa definida com sucesso",
@@ -342,36 +361,16 @@
"totalViews": "Visualizações Totais",
"totalDownloads": "Downloads Totais",
"uniqueVisitors": "Visitantes Únicos",
- "createNewEvent": "Criar Novo Evento",
- "setupNewGallery": "Configure uma nova galeria para seu evento",
- "createNewEventSubtitle": "Configure uma nova galeria de fotos para seu evento",
"eventNamePlaceholder": "ex: Casamento de João e Maria",
- "welcomeMessageOptional": "Mensagem de Boas-vindas (Opcional)",
"welcomeMessagePlaceholder": "Bem-vindo ao nosso dia especial! Sinta-se à vontade para baixar e compartilhar...",
"hostEmailPlaceholder": "cliente@exemplo.com",
"adminEmailPlaceholder": "admin@exemplo.com",
"adminEmailPickFromAdmins": "Escolher entre administradores:",
"adminEmailCustom": "E-mail personalizado",
- "securityAndAccess": "Segurança e Acesso",
"accessAndSecurity": "Acesso e Segurança",
"enterPassword": "Digite a senha",
"passwordPlaceholder": "Digite uma senha segura",
"confirmPasswordPlaceholder": "Confirme a senha",
- "galleryExpiresOn": "A galeria expirará em {{date}}",
- "guestsWillReceiveWarning": "Os convidados receberão um e-mail de aviso 7 dias antes da expiração.",
- "types": {
- "wedding": "Casamento",
- "birthday": "Aniversário",
- "corporate": "Corporativo",
- "other": "Outro"
- },
- "themes": {
- "default": "Padrão",
- "oceanBlue": "Azul Oceano",
- "royalPurple": "Roxo Real",
- "roseGold": "Rosa Ouro",
- "sunsetAmber": "Âmbar Pôr do Sol"
- },
"eventDetails": "Detalhes do Evento",
"eventName": "Nome do Evento",
"eventType": "Tipo de Evento",
@@ -380,11 +379,9 @@
"hostName": "Nome do Cliente",
"hostNamePlaceholder": "João Silva",
"adminEmail": "E-mail do Administrador",
- "adminNotificationEmail": "E-mail de Notificação do Admin",
"expirationDate": "Data de Expiração",
"active": "Ativo",
"archived": "Arquivado",
- "photoCount": "{{count}} fotos",
"totalSize": "Tamanho Total",
"shareLink": "Link de Compartilhamento",
"copyLink": "Copiar Link",
@@ -397,10 +394,7 @@
"backToEvents": "Voltar para Eventos",
"loadingEventDetails": "Carregando detalhes do evento...",
"saveChanges": "Salvar Alterações",
- "eventExpired": "Este evento expirou",
"eventExpiresIn": "Este evento expira em {{days}} dias",
- "guestsNoAccess": "Convidados não podem mais acessar a galeria. Considere arquivar este evento.",
- "warningEmailsSent": "E-mails de aviso foram enviados para o cliente.",
"overview": "Visão Geral",
"photos": "Fotos",
"categories": "Categorias",
@@ -415,7 +409,6 @@
"externalFolderEmpty": "Sem subpastas",
"clearSelection": "Limpar",
"welcomeMessage": "Mensagem de Boas-vindas",
- "noWelcomeMessage": "Nenhuma mensagem definida",
"created": "Criado",
"expires": "Expira",
"shareWithGuests": "Compartilhe este link com os convidados. Eles precisarão da senha para acessar.",
@@ -429,28 +422,18 @@
"managePhotos": "Gerenciar Fotos",
"actions": "Ações",
"archivingInfo": "O arquivamento criará um arquivo ZIP de todas as fotos e removerá a galeria do acesso público.",
- "statistics": "Estatísticas",
- "views": "Visualizações",
- "downloads": "Downloads",
- "noStatistics": "Nenhuma estatística disponível ainda",
- "archiveStatus": "Status do Arquivamento",
"archivedOn": "Arquivado em",
"downloadArchive": "Baixar Arquivo",
"loadingPhotos": "Carregando fotos...",
"photoCategories": "Categorias de Fotos",
"organizeCategoriesInfo": "Organize suas fotos em categorias para ajudar na navegação.",
"categoriesTip": "Dica: Categorias são específicas de cada evento. Crie nomes como \"Cerimônia\", \"Recepção\", etc.",
- "contactInformation": "Informações de Contato",
- "hostEmailHelp": "O cliente receberá notificações de criação e expiração da galeria",
- "adminEmailHelp": "Receberá notificações do sistema e confirmações de arquivamento",
- "securityAccess": "Segurança e Acesso",
"galleryPassword": "Senha da Galeria",
"requirePasswordToggle": "Exigir senha para esta galeria",
"requirePasswordToggleHelp": "Desative se quiser compartilhar a galeria sem senha. Qualquer pessoa com o link poderá ver as fotos.",
"publicGalleryWarning": "Galerias públicas são acessíveis a qualquer pessoa com o link. Considere ativar marcas d'água.",
"passwordHelperText": "Você pode usar datas como \"04.07.2025\" ou qualquer texto com mais de 6 caracteres",
"confirmPassword": "Confirmar Senha",
- "showPasswords": "Mostrar senhas",
"newPasswordLabel": "Nova Senha da Galeria",
"passwordReset": {
"title": "Redefinir Senha da Galeria",
@@ -475,15 +458,10 @@
"errorMinLength": "A senha deve ter pelo menos 6 caracteres",
"errorMismatch": "As senhas não coincidem"
},
- "gallerySettings": "Configurações da Galeria",
"themeAndStyle": "Tema e Estilo",
- "colorTheme": "Tema de Cores",
"galleryExpiration": "Expiração da Galeria",
- "galleryExpiresIn": "Galeria Expira Em",
"daysAfterEvent": "dias após a data do evento",
"expiresOn": "Expira em",
- "galleryWillExpireOn": "A galeria expirará em {{date}}",
- "expirationWarning": "Os convidados receberão um e-mail de aviso 7 dias antes da expiração.",
"noExpiration": "Sem Expiração",
"noExpirationHelp": "Esta galeria permanecerá ativa até ser arquivada manualmente.",
"photoCap": "Limite de Fotos",
@@ -495,11 +473,7 @@
"uploadCategory": "Categoria de Upload",
"selectCategory": "Selecione uma categoria para os uploads dos usuários",
"uploadCategoryHelp": "Todas as fotos enviadas por usuários serão adicionadas a esta categoria",
- "userUploadWarning": "Uploads de usuários podem ser removidos pelos admins a qualquer momento.",
"allowDownloads": "Permitir download de fotos",
- "allowDownloadsHelp": "Permitir que convidados baixem fotos desta galeria",
- "downloadPermissions": "Permissões de Download",
- "downloadsEnabled": "Downloads Ativados",
"downloadsDisabled": "Downloads Desativados",
"downloadProtection": "Proteção de Download",
"disableRightClick": "Bloquear menu do botão direito",
@@ -548,15 +522,6 @@
"heroImageAnchorBottom": "Base",
"heroPreview": "Prévia do Destaque",
"noPhotosAvailable": "Nenhuma foto disponível",
- "processingRequest": "Processando sua solicitação...",
- "eventTypeWedding": "Casamento",
- "eventTypeBirthday": "Aniversário",
- "eventTypeCorporate": "Corporativo",
- "eventTypeOther": "Outro",
- "days30": "30 dias",
- "days60": "60 dias",
- "days90": "90 dias",
- "days365": "1 ano",
"inactive": "Inativo",
"expired": "Expirado",
"draft": "Rascunho",
@@ -564,31 +529,40 @@
"publishConfirm": "Isso tornará a galeria acessível e enviará o e-mail de notificação ao cliente. Continuar?",
"publishSuccess": "Galeria publicada e cliente notificado!",
"draftBanner": "Esta galeria está em modo rascunho. Envie suas fotos e publique quando estiver pronto.",
- "daysLeft": "{{count}}d restante",
- "daysLeft_plural": "{{count}}d restantes",
"subtitle": "Gerencie suas galerias de fotos e eventos",
- "loadingEvents": "Carregando eventos...",
"failedToLoadEvents": "Falha ao carregar eventos",
"tryAgain": "Tentar Novamente",
- "bulkArchiveSuccess": "{{count}} eventos arquivados com sucesso",
"bulkArchivePartial": "{{success}} eventos arquivados, {{failed}} falharam",
"deleteSelected": "Excluir selecionados",
"bulkDelete": {
- "title": "Excluir permanentemente {{count}} eventos?",
"warning": "Os eventos selecionados, todas as suas fotos, arquivos e logs de auditoria serão excluídos permanentemente. Esta ação não pode ser desfeita.",
+ "passwordLabel": "Digite sua senha novamente para confirmar",
+ "passwordPlaceholder": "Sua senha de administrador",
+ "passwordHelp": "Solicitamos sua senha como proteção contra exclusões em massa acidentais.",
+ "incorrectPassword": "Senha incorreta. Nenhum evento foi excluído.",
"confirmLabel": "Digite {{literal}} para confirmar",
"confirmHelp": "Uma confirmação digitada evita exclusões acidentais e não é afetada pelo autopreenchimento do navegador ou atalhos de passkey.",
"submit": "Excluir {{count}} eventos",
"processing": "Excluindo {{count}} eventos. Isso pode levar alguns minutos — não feche esta janela.",
"successAll": "{{count}} eventos excluídos permanentemente",
"successPartial": "{{success}} eventos excluídos, {{failed}} com falha",
- "errorGeneric": "Falha ao excluir eventos"
+ "errorGeneric": "Falha ao excluir eventos",
+ "successAll_many": "{{count}} eventos eliminados permanentemente",
+ "successAll_one": "{{count}} evento eliminado permanentemente",
+ "successAll_other": "{{count}} eventos eliminados permanentemente",
+ "title_many": "Eliminar permanentemente {{count}} eventos?",
+ "title_one": "Eliminar permanentemente {{count}} evento?",
+ "title_other": "Eliminar permanentemente {{count}} eventos?",
+ "processing_many": "A eliminar {{count}} eventos. Pode demorar alguns minutos — não feche esta janela.",
+ "processing_one": "A eliminar {{count}} evento. Pode demorar alguns minutos — não feche esta janela.",
+ "processing_other": "A eliminar {{count}} eventos. Pode demorar alguns minutos — não feche esta janela.",
+ "submit_many": "Eliminar {{count}} eventos",
+ "submit_one": "Eliminar {{count}} evento",
+ "submit_other": "Eliminar {{count}} eventos"
},
"searchEventsPlaceholder": "Buscar eventos...",
"all": "Todos",
"expiring": "Expirando",
- "eventsSelected": "{{count}} evento selecionado",
- "eventsSelected_plural": "{{count}} eventos selecionados",
"clear": "Limpar",
"archiveSelected": "Arquivar Selecionados",
"publicAccess": "Acesso público",
@@ -617,22 +591,14 @@
"extendSevenDays": "Estender 7 Dias",
"welcomeMessageLabel": "Mensagem de Boas-vindas",
"noWelcomeMessageSet": "Nenhuma mensagem definida",
- "createdOn": "Criado em",
"copy": "Copiar",
"copied": "Copiado!",
- "organizingPhotosInfo": "Organize suas fotos em categorias para facilitar a navegação.",
"archiveStatusTitle": "Status do Arquivo",
"downloadingArchive": "Baixando arquivo de {{name}}...",
"downloadStarted": "Download iniciado",
"failedToDownloadArchive": "Falha ao baixar arquivo",
- "statisticsNotAvailable": "Estatísticas não disponíveis ainda",
- "photoFilters": "Filtros de Fotos",
- "noStatisticsAvailableYet": "Ainda sem estatísticas",
- "addPlus": "Adicionar+",
"galleryTheme": "Tema da Galeria",
- "customizeTheme": "Customizar Tema",
"noThemeSet": "Nenhum tema configurado",
- "customizingTheme": "Customizando tema da galeria",
"customizingThemeFor": "Customizando tema para {{event}}",
"customCssTemplate": "Modelo CSS Personalizado",
"customCssTemplateDesc": "Aplique um modelo CSS para estilizar a galeria com efeitos visuais únicos.",
@@ -646,26 +612,48 @@
"renamingFiles": "Renomeando arquivos...",
"complete": "Concluído!",
"failed": "Falha ao renomear",
- "filesRenamed": "{{count}} arquivos atualizados",
- "confirm": "Renomear Evento"
+ "confirm": "Renomear Evento",
+ "success": "Evento renomeado com sucesso!",
+ "filesRenamed_many": "{{count}} ficheiros atualizados",
+ "filesRenamed_one": "{{count}} ficheiro atualizado",
+ "filesRenamed_other": "{{count}} ficheiros atualizados",
+ "newLink": "Novo link da galeria",
+ "currentName": "Nome atual:",
+ "newName": "Novo nome do evento",
+ "enterNewName": "Introduza o novo nome do evento",
+ "newUrl": "Nova URL:",
+ "checkingAvailability": "A verificar disponibilidade…",
+ "resendEmail": "Reenviar e-mail de convite com o novo link da galeria",
+ "emailTo": "Enviar e-mail de acesso atualizado para",
+ "warningTitle": "Atenção:",
+ "warning1": "O URL da galeria irá mudar",
+ "warning2": "Os URLs antigos serão automaticamente redirecionados para o novo URL",
+ "warning3": "Os ficheiros de fotos podem ser renomeados"
},
- "activeFilter": "Ativos",
- "archivedFilter": "Arquivados",
- "sortByName": "Por nome",
- "sortByDate": "Por data",
- "sortByExpiration": "Por expiração",
- "photosCount": "Fotos",
- "moreActions": "Mais ações",
- "copyLinkTooltip": "Copiar link",
- "viewGalleryTooltip": "Ver galeria",
- "uploadPhotosTooltip": "Enviar fotos",
- "editTooltip": "Editar",
- "archiveTooltip": "Arquivar",
- "noEvents": "Nenhum evento encontrado",
- "noEventsDescription": "Crie seu primeiro evento para começar.",
- "bulkArchive": "Arquivar",
- "confirmBulkArchive": "Tem certeza de que deseja arquivar {{count}} evento(s)?",
- "confirmBulkArchiveDescription": "Esta ação não pode ser desfeita. Eventos arquivados não serão mais acessíveis publicamente."
+ "bulkArchiveSuccess_many": "{{count}} eventos arquivados com sucesso",
+ "bulkArchiveSuccess_one": "{{count}} evento arquivado com sucesso",
+ "bulkArchiveSuccess_other": "{{count}} eventos arquivados com sucesso",
+ "daysLeft_many": "({{count}} dias restantes)",
+ "daysLeft_one": "({{count}} dia restante)",
+ "daysLeft_other": "({{count}} dias restantes)",
+ "eventsSelected_many": "{{count}} eventos selecionados",
+ "eventsSelected_one": "{{count}} evento selecionado",
+ "eventsSelected_other": "{{count}} eventos selecionados",
+ "paginationLabel": "{{from}}–{{to}} de {{total}}",
+ "filtered": "filtrado",
+ "pageOf": "Página {{page}} de {{totalPages}}",
+ "notFound": "Evento não encontrado",
+ "customerPhone": "Telefone do cliente",
+ "customerPhonePlaceholder": "+351 912 345 678",
+ "allowPresignedDownload": "Permitir download direto S3 (sem marca d'água, apenas modo S3)",
+ "neverExpires": "Nunca",
+ "rightClickBlocked": "Clique direito bloqueado",
+ "devtoolsDetection": "Deteção de ferramentas de desenvolvedor",
+ "watermarked": "Com marca d'água",
+ "importExternal": "Importar de pasta externa",
+ "externalImportInfo": "Todas as imagens da pasta selecionada serão importadas.",
+ "selectExternalFolder": "Selecionar pasta externa em /external-media",
+ "importFromSelectedFolder": "Importar da pasta selecionada"
},
"settings": {
"title": "Configurações do Sistema",
@@ -677,9 +665,7 @@
"siteUrl": "URL do Site",
"siteUrlHelp": "Usada para gerar links de galeria nos e-mails",
"defaultExpiration": "Expiração Padrão (dias)",
- "defaultExpirationHelp": "Quanto tempo as galerias ficam ativas por padrão",
"maxFileSize": "Tamanho Máx. do Arquivo (MB)",
- "maxFileSizeHelp": "Tamanho máximo por foto enviada",
"maxFilesPerUpload": "Máx. de Arquivos por Envio",
"maxFilesPerUploadHelp": "Número máximo de fotos permitidas em um único lote (1-{{max}}).",
"allowedFileTypes": "Tipos de Arquivos Permitidos",
@@ -691,13 +677,7 @@
"enableShortGalleryUrlsHelp": "Remove o slug do evento de novos links, mantendo os antigos funcionando.",
"maintenanceMode": "Ativar modo de manutenção",
"language": "Idioma",
- "defaultLanguage": "Idioma Padrão",
"defaultLanguageHelp": "Idioma exibido aos convidados antes do login",
- "defaultWelcomeMessage": "Mensagem de Boas-vindas Padrão",
- "welcomeMessage": "Mensagem de Boas-vindas",
- "welcomeMessagePlaceholder": "Digite a mensagem padrão que será incluída nos e-mails de criação",
- "welcomeMessageHelp": "Esta mensagem será incluída em todos os e-mails, a menos que seja substituída no evento",
- "saveSettings": "Salvar Configurações Gerais",
"saveGeneralSettings": "Salvar Configurações Gerais",
"dateTimeFormat": "Formato de Data e Hora",
"dateFormat": "Formato de Data",
@@ -715,7 +695,6 @@
"accountSaveSuccess": "Detalhes da conta atualizados"
},
"publicSite": {
- "tabLabel": "Site Público",
"badge": "Landing Page",
"title": "Página Inicial Pública",
"subtitle": "Publique uma landing page customizada quando visitarem seu domínio.",
@@ -743,8 +722,6 @@
"htmlRequired": "Forneça conteúdo HTML antes de ativar o site público."
},
"storage": {
- "title": "Armazenamento",
- "overview": "Visão Geral do Armazenamento",
"totalUsed": "Total Utilizado",
"archiveStorage": "Armazenamento de Arquivos",
"storageLimit": "Limite de Armazenamento",
@@ -756,7 +733,6 @@
"diskCapacityReported": "Capacidade (reportada)",
"diskAvailable": "Disponível",
"diskAvailableReported": "Disponível (reportada)",
- "diskFree": "Livre",
"diskFreeReported": "Livre (reportada)",
"diskMetricsUnavailable": "Métricas de disco não estão disponíveis em ambientes virtualizados ou Docker Desktop.",
"applyRecommended": "Usar recomendado",
@@ -775,17 +751,12 @@
"capacityRequiredForAvailable": "Insira a capacidade total antes de definir o espaço disponível.",
"availableExceedsCapacity": "O espaço disponível não pode exceder a capacidade total.",
"storageUsage": "Uso de Armazenamento",
- "storageByEvent": "Armazenamento por Evento",
- "storageManagement": "Gerenciamento de Armazenamento",
- "storageManagementHelp": "Considere arquivar ou excluir eventos antigos. Eventos arquivados ocupam menos espaço.",
- "noEventsUsingStorage": "Nenhum evento utilizando armazenamento",
"unlimited": "Ilimitado"
},
"security": {
"title": "Segurança",
"passwordSettings": "Configurações de Senha",
"minPasswordLength": "Comprimento Mínimo da Senha",
- "minPasswordLengthHelp": "Número mínimo de caracteres para senhas de galeria",
"passwordComplexity": "Complexidade da Senha",
"passwordComplexityHelp": "Nível de segurança exigido para senhas",
"complexitySimple": "Simples (6+ caracteres, qualquer texto)",
@@ -794,7 +765,6 @@
"complexityVeryStrong": "Muito Forte (12+ caracteres, todos os tipos)",
"sessionAuth": "Sessão e Autenticação",
"sessionTimeout": "Tempo de Sessão (minutos)",
- "sessionTimeoutHelp": "Tempo de inatividade antes de deslogar o admin",
"maxLoginAttempts": "Máximo de Tentativas de Login",
"maxLoginAttemptsHelp": "Falhas permitidas por IP antes do bloqueio",
"attemptWindowMinutes": "Janela de Tentativas (minutos)",
@@ -805,11 +775,8 @@
"recaptchaSettings": "Configurações de reCAPTCHA",
"enableRecaptcha": "Ativar reCAPTCHA nos formulários de login",
"siteKey": "Chave do Site",
- "siteKeyHelp": "Sua chave pública do reCAPTCHA v2",
"secretKey": "Chave Secreta",
- "secretKeyHelp": "Sua chave privada (mantenha em segredo)",
"recaptchaHelp": "Obtenha suas chaves em",
- "saveSettings": "Salvar Configurações de Segurança",
"saveSecuritySettings": "Salvar Configurações de Segurança"
},
"categories": {
@@ -851,8 +818,6 @@
"missingDimensions": "Sem Dimensões",
"repairButton": "Reparar Dimensões",
"repairing": "Reparando...",
- "alreadyRunning": "O reparo já está em execução",
- "started": "Reparo iniciado para {{count}} fotos",
"noneToRepair": "Todas as fotos já possuem dimensões",
"resultSuccess": "Último reparo: {{success}} atualizadas, {{failed}} falhas",
"description": "Preenche larguras/alturas ausentes para fotos antigas. Necessário para layouts Masonry e Mosaic."
@@ -870,11 +835,13 @@
"sendTest": "Enviar E-mail de Teste",
"saved": "Configurações salvas",
"saveError": "Falha ao salvar configurações",
- "emailSent": "E-mail enviado para {{count}} destinatários",
"emailFailed": "Falha ao enviar notificação",
"checkSuccess": "Notificação enviada para nova versão",
"checkNoAction": "Nenhuma ação necessária: {{reason}}",
- "checkError": "Falha ao verificar atualizações"
+ "checkError": "Falha ao verificar atualizações",
+ "emailSent_many": "E-mail de notificação enviado para {{count}} destinatários",
+ "emailSent_one": "E-mail de notificação enviado para {{count}} destinatário",
+ "emailSent_other": "E-mail de notificação enviado para {{count}} destinatários"
},
"events": {
"title": "Criação de Eventos",
@@ -896,7 +863,13 @@
"expirationWarning": "Galerias sem expiração ficarão ativas até arquivamento manual",
"saveSettings": "Salvar Configurações de Evento",
"noteTitle": "Nota",
- "noteText": "Estas configurações afetam apenas novos eventos. O padrão exige todos os campos."
+ "noteText": "Estas configurações afetam apenas novos eventos. O padrão exige todos os campos.",
+ "defaultRequirePassword": "Exigir senha por padrão",
+ "defaultRequirePasswordHelp": "Pré-marcar «Exigir senha» ao criar novos eventos. Desative para criar galerias públicas mais rapidamente.",
+ "showGalleryFilterBar": "Mostrar barra de filtros nas galerias",
+ "showGalleryFilterBarHelp": "Exibe a pesquisa por nome de ficheiro e os controlos de ordenação acima das galerias em grelha. Desative para um layout mais limpo.",
+ "enablePhoneField": "Ativar campo de número de telefone",
+ "enablePhoneFieldHelp": "Adiciona um campo opcional de número de telefone ao formulário de evento. Útil para automatizações como entrega via WhatsApp com n8n. Sempre opcional mesmo quando ativado."
},
"imageSecurity": {
"title": "Proteção de Imagem",
@@ -969,11 +942,6 @@
"format": "Formato",
"fit": "Modo de Ajuste",
"fitHelp": "Como as imagens são redimensionadas. \"Cover\" corta para preencher, \"Contain\" ajusta aos limites.",
- "fit_cover": "Cover (cortar para preencher)",
- "fit_contain": "Contain (ajustar ao espaço)",
- "fit_fill": "Fill (esticar)",
- "fit_inside": "Inside (encolher para caber)",
- "fit_outside": "Outside (expandir para cobrir)",
"regenerateTitle": "Regenerar Miniaturas",
"regenerateHelp": "Após alterar as configurações, regenere as miniaturas existentes. Isso pode demorar.",
"regenerateButton": "Regenerar Todas as Miniaturas",
@@ -1036,11 +1004,57 @@
"deviceTypes": "Tipos de dispositivos",
"privacy": "Privacidade",
"privacyText": "Endereços IP são anonimizados. Dados são retidos por 90 dias."
- }
+ },
+ "groups": {
+ "general": "Geral",
+ "display": "Apresentação",
+ "privacySecurity": "Privacidade e Segurança",
+ "integrations": "Integrações",
+ "system": "Sistema"
+ },
+ "apiTokens": {
+ "title": "Tokens de API",
+ "createError": "Falha ao criar token",
+ "revoked": "Token revogado",
+ "subtitle": "Tokens bearer de longa duração para a interface pública /api/v1 — integrações n8n, apps personalizadas, scripts. Os tokens atuam como o utilizador administrador que os criou, com as permissões escolhidas.",
+ "copyNow": "Copie este token agora — não será mostrado novamente.",
+ "copied": "Copiado",
+ "copyFailed": "Falha ao copiar",
+ "name": "Nome",
+ "namePlaceholder": "ex.: n8n produção",
+ "scopes": "Âmbitos",
+ "generate": "Gerar token",
+ "scopeHint": "admin > escrita > leitura. Um token só de leitura não pode fazer alterações, mesmo que o proprietário seja super_admin.",
+ "existing": "Tokens existentes",
+ "lastUsed": "Último uso",
+ "created": "Criado",
+ "status": "Estado",
+ "statusRevoked": "Revogado",
+ "statusExpired": "Expirado",
+ "statusActive": "Ativo",
+ "confirmRevoke": "Revogar este token? Esta ação é irreversível.",
+ "revoke": "Revogar",
+ "empty": "Ainda sem tokens. Gere um acima para começar."
+ },
+ "webhooks": {
+ "title": "Webhooks",
+ "subtitle": "Envie notificações POST para o seu URL quando algo acontecer — galeria publicada, foto enviada, evento arquivado, etc. Assinado com HMAC-SHA256 no cabeçalho X-PicPeak-Signature.",
+ "piiNotice": "Os payloads event.* incluem informações de contacto do cliente (nome, e-mail, telefone) e o token de partilha da galeria se estiverem guardados. Aponte webhooks apenas para recetores em que confia.",
+ "copyNow": "Copie este segredo de assinatura agora — não será mostrado novamente.",
+ "name": "Nome",
+ "url": "URL do recetor",
+ "events": "Subscrever eventos",
+ "filter": "Filtro (JSON, opcional)",
+ "template": "Modelo (opcional)",
+ "create": "Criar webhook",
+ "existing": "Webhooks existentes",
+ "empty": "Ainda sem webhooks. Crie um acima para começar a receber notificações."
+ },
+ "sectionLabel": "Secção de configurações",
+ "navAriaLabel": "Navegação de configurações"
},
"analytics": {
"title": "Painel de Análise",
- "titleSimple": "Análises",
"subtitle": "Acompanhe a performance das galerias e o engajamento",
"detailedSubtitle": "Análises detalhadas via Umami",
"loadingAnalytics": "Carregando análises...",
@@ -1068,13 +1082,10 @@
"totalPhotos": "Total de Fotos",
"activeEvents": "Eventos Ativos",
"notConfigured": "Umami Analytics não configurado",
- "configureInstructions": "Para ver dados reais, configure o Umami nas variáveis de ambiente e no painel admin.",
- "noData": "Dados não disponíveis",
- "percentChange": "{{percent}}% em relação ao período anterior"
+ "configureInstructions": "Para ver dados reais, configure o Umami nas variáveis de ambiente e no painel admin."
},
"branding": {
"title": "Marca e Temas",
- "titleFull": "Identidade Visual e Customização",
"subtitle": "Personalize a aparência das suas galerias",
"loadingBranding": "Carregando identidade visual...",
"themeAndStyle": "Tema e Estilo",
@@ -1086,18 +1097,14 @@
"supportEmail": "E-mail de Suporte",
"supportEmailHelp": "E-mail de contato para convidados",
"footerText": "Texto do Rodapé",
- "footerTextHelp": "Exibido na parte inferior das galerias",
"logo": "Logo",
- "currentLogo": "Logo atual",
"uploadLogo": "Enviar Logo",
- "removeLogo": "Remover Logo",
"logoHelp": "Tamanho recomendado: 200x60px, PNG ou JPEG",
"favicon": "Favicon",
"currentFavicon": "Favicon atual",
"uploadFavicon": "Enviar Favicon",
"removeFavicon": "Remover Favicon",
"faviconHelp": "Formato PNG ou ICO, recomendado 32x32px",
- "watermark": "Marca d'água",
"watermarkSettings": "Configurações de Marca d'água",
"enableWatermarks": "Ativar Marcas d'água",
"watermarkHelp": "Adiciona o nome da sua empresa nas fotos baixadas",
@@ -1114,11 +1121,7 @@
"watermarkSize": "Tamanho",
"theme": "Tema",
"galleryTheme": "Tema da Galeria",
- "themeCustomization": "Customização do Tema",
- "selectPreset": "Selecione um tema pronto",
"colors": "Cores",
- "primaryColor": "Cor Primária",
- "secondaryColor": "Cor Secundária",
"accentColor": "Cor de Destaque",
"backgroundColor": "Cor de Fundo",
"textColor": "Cor do Texto",
@@ -1127,27 +1130,13 @@
"colorModeDark": "Escuro",
"colorModeAuto": "Automático",
"colorModeHelp": "Segue a preferência do sistema do visitante.",
- "customCSS": "CSS Personalizado",
"preview": "Prévia",
- "previewInNewTab": "Abrir prévia em nova aba",
- "reset": "Redefinir",
"saveChanges": "Salvar Alterações",
"applyLivePreview": "Aplicar alterações imediatamente (Prévia ao Vivo)",
"eventSpecificThemes": "Temas Específicos por Evento",
"eventThemesInfo": "Você pode sobrepor estas configurações para eventos individuais.",
"themePresets": "Temas Prontos",
"galleryLayout": "Layout da Galeria",
- "layoutDescriptions": {
- "grid": "Grade clássica com tamanhos consistentes",
- "masonry": "Estilo Pinterest com alturas variadas",
- "carousel": "Slideshow em tela cheia",
- "timeline": "Fotos organizadas por data",
- "hero": "Destaque no topo e grade abaixo",
- "mosaic": "Layout artístico com tamanhos mistos",
- "justified": "Layout em linhas preservando proporções",
- "gallery-premium": "Tema claro elegante com Hero e Masonry (Beta)",
- "gallery-story": "Tema escuro cinematográfico com seções (Beta)"
- },
"layoutSettings": "Configurações de Layout",
"photoSpacing": "Espaçamento entre Fotos",
"spacing": {
@@ -1204,16 +1193,6 @@
"xl": "XL — Fotos grandes"
},
"thumbnailScaleHint": "Ajusta a contagem de colunas em relação às colunas base da grade",
- "showHeroSection": "Mostrar Seção Hero",
- "showHeroSectionHint": "Exibe uma imagem de destaque acima da galeria",
- "heroHeight": "Altura da Seção Hero",
- "heroHeightOptions": {
- "small": "Pequena (40-50%)",
- "medium": "Média (50-70%)",
- "large": "Grande (60-80%)"
- },
- "heroOverlayOpacity": "Opacidade da Sobreposição Hero",
- "heroOverlayHint": "Escurece a imagem de destaque para melhorar o contraste do texto",
"typographyAndStyle": "Tipografia e Estilo",
"bodyFont": "Fonte do Corpo",
"headingFont": "Fonte de Títulos",
@@ -1259,8 +1238,6 @@
},
"resetToDefault": "Redefinir para o Padrão",
"applyTheme": "Aplicar Tema",
- "customTheme": "Tema Personalizado",
- "customizeTheme": "Personalizar Tema",
"saveTheme": "Salvar Tema",
"previewLayout": "Visualizar Layout",
"livePreview": "Prévia ao Vivo",
@@ -1278,9 +1255,6 @@
"logoMaxHeight": "Altura Máxima (pixels)",
"logoMaxHeightHelp": "Define uma altura máxima para a logo (20-200 px)",
"logoPosition": "Posição da Logo no Cabeçalho",
- "positionLeft": "Esquerda",
- "positionCenter": "Centro",
- "positionRight": "Direita",
"logoDisplayMode": "Modo de Exibição",
"logoOnly": "Apenas Logo",
"textOnly": "Apenas Nome da Empresa",
@@ -1291,29 +1265,8 @@
"showLogoInHeroHelp": "Exibe a logo na seção de destaque",
"headerStyle": "Estilo do Cabeçalho",
"headerStyleDescription": "Escolha como o topo da galeria aparece.",
- "headerStyleOptions": {
- "hero": "Imagem de Destaque (Hero)",
- "standard": "Banner Padrão",
- "banner": "Banner",
- "minimal": "Minimalista",
- "none": "Sem Cabeçalho"
- },
- "headerStyleDescriptions": {
- "hero": "Imagem de tela cheia com info sobreposta",
- "standard": "Banner clássico com detalhes do evento",
- "banner": "Cabeçalho padrão com banner colorido acima",
- "minimal": "Cabeçalho compacto com o essencial",
- "none": "Oculta o cabeçalho completamente"
- },
"heroDividerStyle": "Estilo do Divisor",
"heroDividerDescription": "Transição entre a imagem de destaque e o conteúdo.",
- "dividerOptions": {
- "wave": "Onda",
- "straight": "Reto",
- "angle": "Ângulo",
- "curve": "Curva",
- "none": "Nenhum"
- },
"controlsStyle": "Estilo dos Controles",
"controlsStyleDescription": "Escolha como filtros e controles são exibidos.",
"controlsStyleOptions": {
@@ -1327,15 +1280,43 @@
"controlsStyleHeroWarning": "A barra lateral é recomendada para cabeçalhos Hero.",
"betaThumbnailWarningTitle": "Baixa resolução de miniatura detectada",
"betaThumbnailWarningText": "Suas miniaturas são atualmente {{width}}×{{height}}px. Temas beta exibem fotos em tamanhos maiores e requerem pelo menos {{recommended}}×{{recommended}}px para boa qualidade. Aumente as dimensões das miniaturas em Configurações > Miniaturas e regenere.",
- "betaThumbnailWarningLink": "Ir para configurações de miniaturas"
+ "betaThumbnailWarningLink": "Ir para configurações de miniaturas",
+ "logoSize": "Tamanho do logótipo",
+ "surfaceColor": "Superfície",
+ "elevatedColor": "Elevado",
+ "borderColor": "Borda",
+ "mutedTextColor": "Texto atenuado",
+ "accentDarkColor": "Destaque (preenchido)",
+ "syncFromBranding": "Sincronizar com identidade visual",
+ "forceColorMode": "Forçar modo de cor",
+ "forceColorModeHelp": "Bloqueia todo o site de administração e público em modo escuro ou claro. O botão de alternância escuro/claro fica oculto quando um bloqueio está ativo.",
+ "forceColorModeNone": "Sem forçar (escolha do utilizador)",
+ "forceColorModeDark": "Forçar modo escuro",
+ "forceColorModeLight": "Forçar modo claro",
+ "colorGroupSurfaces": "Superfícies",
+ "colorGroupSurfacesHelp": "As camadas neutras atrás do seu conteúdo. O fundo fica mais atrás; Superfície e Elevado ficam por cima.",
+ "backgroundColorHelp": "A própria página — fundo de cada galeria, página de administração e página CMS.",
+ "surfaceColorHelp": "Cartões, barra lateral, cabeçalho e navegação. A primeira camada acima do fundo.",
+ "elevatedColorHelp": "Painéis que flutuam acima dos cartões: espaços reservados para imagens, linhas ao passar o rato, cabeçalhos modais, blocos de código.",
+ "borderColorHelp": "Divisores, linhas de grelha de tabelas, contornos de cartões, bordas de inputs.",
+ "colorGroupText": "Texto",
+ "colorGroupTextHelp": "Cores de texto em primeiro plano. Primário para tudo em que os leitores se focam; Secundário para texto de apoio.",
+ "textColorHelp": "Títulos, corpo de texto, células de tabelas, valores de inputs, etiquetas de navegação — a cor principal do texto.",
+ "mutedTextColorHelp": "Legendas, texto de ajuda sob inputs, cabeçalhos de colunas, links de rodapé, datas e metadados.",
+ "colorGroupAccent": "Destaque",
+ "colorGroupAccentHelp": "Cores de marca que realçam elementos interativos. Use um par de cores forte — Destaque para contornos/texto, Destaque (preenchido) para botões preenchidos.",
+ "accentColorHelp": "Links, ícones, anéis de foco, estados ao passar o rato em botões primários, sublinhado do item ativo da barra lateral.",
+ "accentDarkColorHelp": "Botões CTA preenchidos, fundo do item ativo da barra lateral, distintivos e etiquetas. Necessita contraste suficiente para texto branco legível.",
+ "cssTemplate": "Modelo CSS",
+ "cssTemplateDescription": "Selecione um modelo CSS pré-construído para aplicar estilos globais a esta galeria. Os modelos podem ser geridos em Configurações > Modelos CSS.",
+ "noTemplate": "Sem modelo",
+ "noTemplateDescription": "Usar apenas as definições de tema sem modelo CSS",
+ "templateSlot": "Posição {{slot}}",
+ "eventCustomCSS": "CSS personalizado por evento"
},
"admin": {
"title": "Painel Admin",
- "welcome": "Bem-vindo de volta, {{name}}",
"recentActivity": "Atividade Recente",
- "systemStatus": "Status do Sistema",
- "totalEvents": "Total de Eventos",
- "activeGalleries": "Galerias Ativas",
"storageUsed": "Espaço Utilizado",
"totalPhotos": "Total de Fotos",
"storagePercent": "{{percent}}% do limite de {{limit}}",
@@ -1345,9 +1326,6 @@
"archivedEvents": "Eventos Arquivados",
"systemHealth": "Saúde do Sistema",
"health": {
- "healthy": "Saudável",
- "warning": "Aviso",
- "error": "Erro",
"checking": "Verificando..."
},
"updates": {
@@ -1360,9 +1338,7 @@
"beta": "BETA",
"viewReleaseNotes": "Ver Notas de Lançamento",
"updateAvailableShort": "v{{version}} disponível",
- "checkForUpdates": "Verificar Atualizações",
"upToDate": "Sistema atualizado",
- "lastChecked": "Última verificação: {{time}}",
"updateNow": "Atualizar Agora",
"updateDialog": {
"title": "Atualizar PicPeak",
@@ -1376,8 +1352,6 @@
}
},
"notifications": "Notificações",
- "viewAllNotifications": "Ver todas as notificações",
- "noNotifications": "Sem novas notificações",
"markAllRead": "Marcar tudo como lido",
"clearAll": "Limpar tudo",
"close": "Fechar",
@@ -1387,16 +1361,13 @@
"eventArchived": "Evento \"{{eventName}}\" arquivado",
"eventUpdated": "Evento \"{{eventName}}\" atualizado",
"eventDeleted": "Evento \"{{eventName}}\" excluído",
- "photosUploaded": "{{count}} fotos enviadas para \"{{eventName}}\"",
"photoDeleted": "Foto excluída de \"{{eventName}}\"",
- "photosBulkDeleted": "{{count}} fotos excluídas de \"{{eventName}}\"",
"eventExpiring": "O evento \"{{eventName}}\" expira em {{days}} dias",
"eventExpired": "O evento \"{{eventName}}\" expirou",
"passwordChanged": "Senha alterada por {{actorName}}",
"passwordReset": "Senha redefinida para \"{{eventName}}\"",
"settingsUpdated": "Configurações de {{type}} atualizadas",
"emailTemplateUpdated": "Modelo de e-mail \"{{template}}\" atualizado",
- "bulkDownload": "{{count}} fotos baixadas de \"{{eventName}}\"",
"storageWarning": "Uso de armazenamento em {{percentage}}%",
"adminLogout": "Admin {{actorName}} saiu do sistema",
"categoryCreated": "Categoria \"{{name}}\" criada para \"{{eventName}}\"",
@@ -1413,29 +1384,26 @@
"archiveDeleted": "Arquivo excluído de \"{{eventName}}\"",
"archiveRestored": "Arquivo restaurado para \"{{eventName}}\"",
"systemActivity": "Atividade do sistema: {{type}}",
- "adminProfileUpdated": "Perfil admin atualizado por {{actorName}}"
+ "adminProfileUpdated": "Perfil admin atualizado por {{actorName}}",
+ "photosUploaded_many": "{{count}} fotos enviadas para \"{{eventName}}\"",
+ "photosUploaded_one": "{{count}} foto enviada para \"{{eventName}}\"",
+ "photosUploaded_other": "{{count}} fotos enviadas para \"{{eventName}}\"",
+ "photosBulkDeleted_many": "{{count}} fotos eliminadas de \"{{eventName}}\"",
+ "photosBulkDeleted_one": "{{count}} foto eliminada de \"{{eventName}}\"",
+ "photosBulkDeleted_other": "{{count}} fotos eliminadas de \"{{eventName}}\"",
+ "bulkDownload_many": "{{count}} fotos descarregadas de \"{{eventName}}\"",
+ "bulkDownload_one": "{{count}} foto descarregada de \"{{eventName}}\"",
+ "bulkDownload_other": "{{count}} fotos descarregadas de \"{{eventName}}\""
},
"notificationToasts": {
"markedAllRead": "Todas as notificações marcadas como lidas",
- "clearedAll": "Limpas {{count}} notificações",
- "profileUpdated": "Perfil admin atualizado"
+ "clearedAll_many": "{{count}} notificações removidas",
+ "clearedAll_one": "{{count}} notificação removida",
+ "clearedAll_other": "{{count}} notificações removidas"
},
- "markAsRead": "Marcar como lida",
- "markAllAsRead": "Marcar todas como lidas",
- "notificationSettings": "Configurações de Notificação",
"changePassword": "Alterar Senha",
"darkMode": "Alternar para modo escuro",
"lightMode": "Alternar para modo claro",
- "accountSettings": {
- "title": "Conta Admin",
- "description": "Atualize as credenciais de acesso ao PicPeak.",
- "username": "Usuário",
- "usernamePlaceholder": "Admin",
- "email": "E-mail",
- "emailPlaceholder": "admin@exemplo.com",
- "updateButton": "Atualizar perfil"
- },
- "profileUpdateError": "Não foi possível atualizar o perfil. Tente novamente.",
"loadingDashboard": "Carregando painel...",
"activeEvents": "Eventos Ativos",
"expiringSoon": "Expirando em Breve",
@@ -1446,110 +1414,92 @@
"dashboardSubtitle": "Bem-vindo! Confira o que está acontecendo nas suas galerias.",
"eventsExpiringSoon": "Eventos Expirando em Breve",
"noEventsExpiring": "Nenhum evento expira nos próximos 7 dias",
- "daysLeft": "{{count}} dia restante",
- "daysLeft_plural": "{{count}} dias restantes",
- "viewAllExpiringEvents": "Ver todos os {{count}} eventos expirando",
"noRecentActivity": "Nenhuma atividade recente",
- "viewAllActivity": "Ver toda a atividade",
- "quickActions": "Ações Rápidas",
- "viewArchives": "Ver Arquivos",
- "analytics": "Análises",
- "activities": {
- "event_created": "Novo evento criado: {{eventName}}",
- "photos_uploaded": "{{count}} fotos enviadas para {{eventName}}",
- "event_archived": "Evento arquivado: {{eventName}}",
- "archive_restored": "Arquivo restaurado: {{eventName}}",
- "archive_deleted": "Arquivo excluído: {{eventName}}",
- "archive_downloaded": "Arquivo baixado: {{eventName}}",
- "email_config_updated": "Configuração de e-mail atualizada",
- "email_template_updated": "Modelo de e-mail atualizado: {{template}}",
- "branding_updated": "Identidade visual atualizada",
- "theme_updated": "Configurações de tema atualizadas",
- "bulk_download": "{{count}} fotos baixadas de {{eventName}}",
- "gallery_password_entry": "Senha inserida para {{eventName}}",
- "expiration_warning_viewed": "Aviso de expiração visualizado para {{eventName}}",
- "feedback_settings_updated": "Configurações de feedback atualizadas",
- "feedback_moderated": "Feedback moderado",
- "feedback_deleted": "Feedback excluído",
- "photo_like": "Foto curtida em {{eventName}}",
- "photo_favorite": "Foto favoritada em {{eventName}}",
- "photo_rating": "Foto avaliada em {{eventName}}",
- "photo_comment": "Foto comentada em {{eventName}}",
- "guest_feedback_like": "Convidado curtiu uma foto em {{eventName}}",
- "guest_feedback_favorite": "Convidado favoritou uma foto em {{eventName}}",
- "guest_feedback_rating": "Convidado avaliou uma foto em {{eventName}}",
- "guest_feedback_comment": "Convidado comentou em uma foto em {{eventName}}",
- "word_filter_added": "Filtro de palavras adicionado",
- "external_import_completed": "Importação de mídia externa concluída ({{imported}} importadas, {{skipped}} ignoradas)",
- "bulk_archive_completed": "Arquivamento em lote concluído",
- "event_activated": "Evento ativado: {{eventName}}",
- "event_deactivated": "Evento desativado: {{eventName}}",
- "photo_deleted": "Foto excluída de {{eventName}}",
- "photos_bulk_deleted": "{{count}} fotos excluídas de {{eventName}}",
- "settings_updated": "Configurações atualizadas",
- "event_updated": "Evento atualizado: {{eventName}}",
- "event_renamed": "Evento renomeado: {{eventName}}",
- "event_deleted": "Evento excluído: {{eventName}}",
- "password_changed": "Senha alterada",
- "email_resent": "E-mail de criação reenviado para: {{eventName}}",
- "category_created": "Categoria criada: {{categoryName}}",
- "category_updated": "Categoria atualizada: {{categoryName}}",
- "category_deleted": "Categoria excluída: {{categoryName}}",
- "general_settings_updated": "Configurações gerais atualizadas",
- "favicon_uploaded": "Favicon enviado",
- "analytics_settings_updated": "Configurações de análise atualizadas",
- "cms_page_updated": "Página CMS atualizada: {{page}}",
- "security_settings_updated": "Configurações de segurança atualizadas",
- "password_reset": "Senha redefinida para: {{eventName}}",
- "admin_logout": "Admin {{actorName}} saiu",
- "system_activity": "Atividade do sistema: {{type}}",
- "unknown": "Atividade desconhecida"
- },
- "userManagement": "Gerenciamento de Usuários",
- "inviteUser": "Convidar Usuário",
- "pendingInvitations": "Convites Pendentes",
- "roles": {
- "super_admin": "Super Admin",
- "admin": "Admin",
- "editor": "Editor",
- "viewer": "Visualizador"
- },
- "userStatus": {
- "active": "Ativo",
- "inactive": "Inativo"
- },
- "inviteForm": {
- "email": "Endereço de E-mail",
- "role": "Função",
- "send": "Enviar Convite"
- },
- "acceptInvite": {
- "title": "Aceitar Convite de Admin",
- "username": "Escolha um Usuário",
- "password": "Crie uma Senha",
- "submit": "Criar Conta"
- },
"photos": {
"hidden": "Oculta",
"hideSelected": "Ocultar",
"showSelected": "Exibir",
"hiddenSuccess": "Fotos ocultadas dos visitantes",
- "visibleSuccess": "Fotos agora visíveis aos visitantes"
+ "visibleSuccess": "Fotos agora visíveis aos visitantes",
+ "processingStatus": "A processar…",
+ "processingFailed": "Falhado",
+ "retryQueued": "Nova tentativa em fila"
+ },
+ "events": {
+ "tabs": {
+ "guests": "Convidados"
+ }
+ },
+ "daysLeft_many": "{{count}} dias restantes",
+ "daysLeft_one": "{{count}} dia restante",
+ "daysLeft_other": "{{count}} dias restantes",
+ "viewAllExpiringEvents_many": "Ver todos os {{count}} eventos a expirar",
+ "viewAllExpiringEvents_one": "Ver o {{count}} evento a expirar",
+ "viewAllExpiringEvents_other": "Ver todos os {{count}} eventos a expirar",
+ "guests": {
+ "loading": "A carregar…",
+ "aggregate": {
+ "empty": "Ainda sem seleções de convidados.",
+ "description": "Fotos ordenadas pelo número de convidados distintos que as gostaram ou marcaram como favoritas."
+ },
+ "inviteCreated": "Convite criado",
+ "inviteCreateError": "Falha ao criar convite",
+ "inviteRevoked": "Convite revogado",
+ "inviteRevokeError": "Falha ao revogar convite",
+ "invitesTitle": "Convites de convidados",
+ "createInvite": "Criar convite",
+ "inviteName": "Nome do convidado",
+ "inviteEmail": "E-mail (opcional)",
+ "generateInvite": "Gerar link de convite",
+ "existingInvites": "Convites existentes",
+ "noInvites": "Ainda sem convites",
+ "copyLink": "Copiar link",
+ "revokeInvite": "Revogar",
+ "deletedToast": "Convidado removido",
+ "deletedError": "Falha ao remover convidado",
+ "mergedToast": "Convidados fundidos",
+ "mergedError": "Falha ao fundir convidados",
+ "forgetGuestConfirm": "Remover este convidado? As suas seleções serão anonimizadas mas mantidas nos totais agregados.",
+ "exportError": "Falha na exportação",
+ "mergeSelectAtLeastTwo": "Selecione pelo menos 2 convidados para fundir",
+ "mergeConfirm_many": "Fundir {{count}} convidados com {{name}}? Esta ação é irreversível.",
+ "mergeConfirm_one": "Fundir {{count}} convidado com {{name}}? Esta ação é irreversível.",
+ "mergeConfirm_other": "Fundir {{count}} convidados com {{name}}? Esta ação é irreversível.",
+ "backToList": "Voltar à lista",
+ "title": "Convidados",
+ "mergeSelected_many": "{{count}} selecionados",
+ "mergeSelected_one": "{{count}} selecionado",
+ "mergeSelected_other": "{{count}} selecionados",
+ "mergeNow": "Fundir selecionados",
+ "aggregateView": "Por popularidade",
+ "mergeMode": "Fundir",
+ "exportAll": "Exportar tudo",
+ "empty": "Ainda sem convidados registados.",
+ "columns": {
+ "name": "Nome",
+ "email": "E-mail",
+ "likes": "Gostos",
+ "favorites": "Favoritos",
+ "comments": "Comentários",
+ "ratings": "Avaliações",
+ "lastSeen": "Última visita"
+ },
+ "view": "Ver detalhes",
+ "export": "Exportar",
+ "forgetGuest": "Remover convidado",
+ "loadingDetail": "A carregar seleções…",
+ "detail": {
+ "noComments": "Sem comentários",
+ "empty": "Sem seleções nesta categoria"
+ }
}
},
- "permissions": {
- "insufficient": "Você não tem permissão para realizar esta ação",
- "viewOnly": "Apenas Visualização"
- },
"acceptInvitation": {
"title": "Aceitar Convite",
"subtitle": "Crie sua conta administrativa",
"validating": "Validando convite...",
"invalidToken": "Convite Inválido",
"invalidTokenMessage": "Este link de convite é inválido ou expirou. Contate o administrador.",
- "expiredToken": "Convite Expirado",
- "expiredTokenMessage": "Este convite expirou. Solicite um novo convite.",
- "alreadyUsed": "Convite Já Utilizado",
"alreadyUsedMessage": "Este convite já foi usado para criar uma conta.",
"invitedAs": "Você foi convidado como",
"expiresAt": "O convite expira em",
@@ -1576,7 +1526,6 @@
"strong": "Forte"
},
"createAccount": "Criar Conta",
- "creating": "Criando conta...",
"success": "Conta Criada!",
"successMessage": "Sua conta foi criada com sucesso. Você já pode fazer login.",
"redirecting": "Redirecionando para login em {{seconds}}s...",
@@ -1591,23 +1540,14 @@
"usernameTooLong": "Usuário deve ter no máximo 50 caracteres",
"usernameInvalid": "O usuário só pode conter letras, números, sublinhados e hífens",
"passwordRequired": "Senha é obrigatória",
- "passwordTooShort": "A senha deve ter pelo menos 12 caracteres",
"passwordsDoNotMatch": "As senhas não coincidem",
"confirmPasswordRequired": "Confirme sua senha",
- "usernameTaken": "Este nome de usuário já está em uso",
- "emailTaken": "Uma conta com este e-mail já existe",
"genericError": "Falha ao criar conta. Tente novamente."
}
},
"errors": {
- "notFound": "Não Encontrado",
"galleryNotFound": "Galeria Não Encontrada",
"galleryNotFoundMessage": "Esta galeria não existe ou foi removida.",
- "galleryArchived": "Galeria Arquivada",
- "galleryArchivedMessage": "Esta galeria foi arquivada e não está mais acessível. Contate o organizador se precisar de acesso.",
- "unauthorized": "Não autorizado",
- "forbidden": "Proibido",
- "serverError": "Erro no Servidor",
"somethingWentWrong": "Algo deu errado",
"tryAgainLater": "Tente novamente mais tarde",
"refreshPage": "Atualizar Página",
@@ -1617,10 +1557,9 @@
"errorDetails": "Detalhes do Erro",
"requiredFields": "Preencha todos os campos obrigatórios",
"enterTestEmail": "Insira um endereço de e-mail para teste",
- "failedToCreateEvent": "Falha ao criar evento",
"eventCreationFailed": "Criação de evento falhou",
- "networkError": "Erro de rede. Verifique sua conexão e tente novamente.",
- "sessionExpired": "Sessão expirada. Faça login novamente."
+ "noShareLink": "Nenhum link de partilha disponível",
+ "copyFailed": "Falha ao copiar link"
},
"validation": {
"eventNameRequired": "O nome do evento é obrigatório",
@@ -1631,14 +1570,15 @@
"passwordRequired": "Senha é obrigatória",
"passwordMinLength": "A senha deve ter pelo menos 6 caracteres",
"passwordsDoNotMatch": "As senhas não coincidem",
- "passwordSecurityRequirements": "A senha não atende aos requisitos de segurança",
- "expirationRange": "A expiração deve ser entre 1 e 365 dias"
+ "expirationRange": "A expiração deve ser entre 1 e 365 dias",
+ "required": "Este campo é obrigatório",
+ "expirationRequired": "A data de expiração é obrigatória.",
+ "eventDateRequired": "A data do evento é obrigatória",
+ "passwordTooSimple": "A senha não pode ser apenas números. Considere um formato como \"04.07.2025\""
},
"legal": {
"impressum": "Aviso Legal",
- "datenschutz": "Política de Privacidade",
- "termsOfService": "Termos de Serviço",
- "cookiePolicy": "Política de Cookies"
+ "datenschutz": "Política de Privacidade"
},
"toast": {
"saveSuccess": "Alterações salvas com sucesso",
@@ -1647,9 +1587,6 @@
"deleteError": "Falha ao excluir",
"uploadSuccess": "Envio concluído com sucesso",
"uploadError": "Falha no envio",
- "loginSuccess": "Login realizado com sucesso",
- "loginError": "Falha no login",
- "passwordChanged": "Senha alterada com sucesso",
"linkCopied": "Link copiado para a área de transferência",
"eventCreated": "Evento criado com sucesso",
"eventUpdated": "Evento atualizado com sucesso",
@@ -1657,14 +1594,10 @@
"settingsSaved": "Configurações salvas com sucesso",
"themeUpdated": "Tema atualizado com sucesso",
"brandingUpdated": "Identidade visual atualizada com sucesso",
- "categoryAdded": "Categoria adicionada com sucesso",
- "categoryDeleted": "Categoria excluída com sucesso",
"categoryUpdated": "Categoria atualizada com sucesso",
"emailConfigSaved": "Configuração de e-mail salva com sucesso",
- "testEmailSent": "E-mail de teste enviado com sucesso",
- "pageUpdated": "Página atualizada com sucesso",
- "archiveRestored": "Arquivo restaurado com sucesso",
- "archiveDeleted": "Arquivo excluído permanentemente"
+ "brandingThemeMissing": "Ainda não foi guardado nenhum tema de identidade visual.",
+ "brandingPaletteSynced": "Paleta sincronizada com a identidade visual."
},
"email": {
"title": "Configuração de E-mail",
@@ -1672,28 +1605,9 @@
"loadingSettings": "Carregando configurações de e-mail...",
"smtpConfiguration": "Configuração SMTP",
"smtpHost": "Servidor SMTP",
- "smtpHostHelp": "O hostname do seu servidor de e-mail",
- "smtpPort": "Porta SMTP",
- "smtpPortHelp": "Geralmente 587 (TLS), 465 (SSL) ou 25",
- "smtpSecure": "Usar SSL/TLS",
- "smtpSecureHelp": "Ative para transmissão segura de e-mail",
- "smtpUsername": "Usuário SMTP",
- "smtpUsernameHelp": "Seu usuário da conta de e-mail",
- "smtpPassword": "Senha SMTP",
- "smtpPasswordHelp": "Sua senha da conta de e-mail",
- "fromDetails": "Detalhes do Remetente",
"fromEmail": "E-mail de Origem",
- "fromEmailHelp": "Endereço que aparecerá como remetente",
"fromName": "Nome do Remetente",
- "fromNameHelp": "Nome que aparecerá como remetente",
- "testConfiguration": "Testar Configuração",
- "testEmail": "E-mail de Teste",
- "testEmailHelp": "Envie um e-mail para verificar as configurações",
- "sendTestEmail": "Enviar E-mail de Teste",
- "saveConfiguration": "Salvar Configuração",
"emailTemplates": "Modelos de E-mail",
- "templateVariables": "Variáveis Disponíveis",
- "previewTemplate": "Visualizar Modelo",
"smtpSettings": "Configurações SMTP",
"testEmailSuccess": "E-mail de teste enviado com sucesso",
"saveSmtpSettings": "Salvar Ajustes SMTP",
@@ -1711,23 +1625,18 @@
"emailBody": "Corpo do E-mail",
"preview": "Visualizar",
"save": "Salvar",
- "saveChanges": "Salvar Alterações",
"templates": "Modelos",
- "variableHelp": "Use estas variáveis no seu modelo. Elas serão substituídas por valores reais no envio.",
"port": "Porta",
"security": "Segurança",
"username": "Usuário",
"password": "Senha",
"enterPassword": "Digite a senha",
- "required": "obrigatório",
"ignoreSslErrors": "Ignorar erros de certificado SSL/TLS",
"ignoreSslWarning": "Aviso: Desabilitar a verificação torna a conexão vulnerável. Ative apenas se confiar no servidor.",
"brandingTitle": "Identidade Visual do Email",
"brandingDescription": "Personalize as cores usadas nos modelos de email. As alterações se aplicam à barra de cabeçalho, botões, links e fundo do rodapé.",
"primaryColor": "Cor Primária",
- "primaryColorHint": "Usada para cabeçalho, botões e links",
"secondaryColor": "Fundo do Rodapé",
- "secondaryColorHint": "Usada para o fundo da seção de rodapé",
"saveEmailColors": "Salvar Cores do Email",
"editor": {
"bold": "Negrito",
@@ -1753,7 +1662,23 @@
"copiedFromLanguage": "Conteúdo copiado de {{language}}",
"noTranslation": "Ainda sem tradução",
"noTranslationYet": "Ainda não existe tradução para este idioma. Copie de um idioma existente para começar:",
- "copyFrom": "Copiar de"
+ "copyFrom": "Copiar de",
+ "syncedFromBranding": "Cores de e-mail sincronizadas com a identidade visual. Clique em Guardar para aplicar.",
+ "syncFromBranding": "Sincronizar com identidade visual",
+ "primaryColorHelp": "Barra de cabeçalho, títulos H2, fundo dos botões, cor dos links. Corresponde a Identidade Visual → Destaque (preenchido).",
+ "secondaryColorHelp": "Fundo da barra de rodapé. Corresponde a Identidade Visual → Superfície.",
+ "bodyBgColor": "Fundo da página",
+ "bodyBgColorHelp": "O envoltório à volta do cartão de e-mail — o que o destinatário vê atrás do e-mail. Corresponde a Identidade Visual → Fundo.",
+ "containerBgColor": "Cartão de e-mail",
+ "containerBgColorHelp": "O cartão branco que contém o conteúdo do e-mail. Corresponde a Identidade Visual → Superfície.",
+ "listBgColor": "Painel de informação",
+ "listBgColorHelp": "Fundo dos painéis de informação com marcadores no corpo do e-mail. Corresponde a Identidade Visual → Elevado.",
+ "bodyTextColor": "Texto do corpo",
+ "bodyTextColorHelp": "Cor de parágrafos e texto a negrito. Corresponde a Identidade Visual → Texto primário.",
+ "mutedTextColor": "Texto do rodapé",
+ "mutedTextColorHelp": "Texto do rodapé e linha de copyright. Corresponde a Identidade Visual → Texto secundário.",
+ "buttonTextColor": "Texto dos botões",
+ "buttonTextColorHelp": "Cor do texto em botões preenchidos. Deve contrastar bem com a cor primária. Geralmente branco."
},
"cms": {
"title": "Páginas CMS",
@@ -1767,17 +1692,22 @@
"pageTitle": "Título da Página",
"pageContent": "Conteúdo da Página",
"pageTitlePlaceholder": "Digite o título da página...",
- "saveChanges": "Salvar Alterações",
"lastUpdated": "Última atualização:",
- "impressum": "Aviso Legal",
- "datenschutz": "Política de Privacidade",
"pageUpdated": "Página atualizada com sucesso",
"useExternalUrl": "Usar URL externa",
"useExternalUrlHelp": "Redirecione os visitantes para uma página externa em vez de mostrar o conteúdo interno. O título e o conteúdo internos permanecem salvos como fallback.",
"externalUrl": "URL externa",
"externalUrlPlaceholder": "https://example.com/impressum",
"externalUrlInvalid": "Deve ser uma URL https:// válida",
- "externalUrlActive": "URL externa está ativa — o conteúdo interno é preservado, mas não é exibido aos visitantes."
+ "externalUrlActive": "URL externa está ativa — o conteúdo interno é preservado, mas não é exibido aos visitantes.",
+ "logoUploaded": "Logótipo enviado",
+ "logoCleared": "Logótipo removido",
+ "pageLogo": "Logótipo da página",
+ "pageLogoHelp": "Opcional. Se definido, é usado em vez do logótipo global da identidade visual nesta página.",
+ "noLogo": "sem substituição",
+ "replaceLogo": "Substituir logótipo",
+ "uploadLogo": "Enviar logótipo",
+ "clearLogo": "Usar padrão do site"
},
"eventTypes": {
"title": "Tipos de Evento",
@@ -1828,12 +1758,6 @@
}
},
"backup": {
- "external": {
- "warning": {
- "title": "Mídia externa excluída",
- "body": "Esta instalação referencia fotos em /external-media. Os arquivos originais estão excluídos dos backups. Miniaturas e banco de dados continuam incluídos."
- }
- },
"title": "Gerenciamento de Backup",
"subtitle": "Gerencie backups do sistema, configure backups automáticos e restaure dados.",
"tabs": {
@@ -1854,22 +1778,12 @@
"actions": {
"runBackupNow": "Executar Backup Agora",
"starting": "Iniciando...",
- "running": "Executando...",
"testConnection": "Testar Conexão",
- "save": "Salvar Configuração",
"delete": "Excluir",
"view": "Ver Detalhes",
- "download": "Baixar",
- "refresh": "Atualizar"
+ "download": "Baixar"
},
"dashboard": {
- "backupHealth": "Saúde do Backup",
- "healthStatus": {
- "excellent": "Excelente",
- "good": "Boa",
- "warning": "Aviso",
- "critical": "Crítica"
- },
"health": {
"title": "Saúde do Backup"
},
@@ -1879,9 +1793,7 @@
"upToDate": "Backup atualizado",
"recent": "Backup recente",
"gettingOld": "Backup ficando antigo",
- "outdated": "Backup desatualizado",
- "failed": "Último backup falhou",
- "old": "Backup está ficando antigo"
+ "outdated": "Backup desatualizado"
},
"stats": {
"totalBackups": "Total de Backups",
@@ -1890,7 +1802,6 @@
"backupStatus": "Status do Backup",
"last": "Último",
"files": "arquivos",
- "minutes": "{{count}}m",
"active": "Ativo",
"inactive": "Inativo",
"noBackupsYet": "Ainda sem backups"
@@ -1908,16 +1819,10 @@
},
"coverage": {
"title": "Cobertura do Backup",
- "database": "Banco de Dados",
- "photos": "Fotos",
- "archives": "Arquivos",
- "systemFiles": "Arquivos do Sistema",
"included": "Incluído",
- "excluded": "Excluído",
- "optional": "Opcional"
+ "excluded": "Excluído"
},
"storageDestination": "Destino do Armazenamento",
- "nextScheduledBackup": "Próximo Backup Agendado",
"backupType": "Backup {{type}}",
"noDestinationSet": "Nenhum destino definido"
},
@@ -1944,42 +1849,24 @@
"destinationPathHelp": "Diretório local para armazenar os backups",
"destinationPathPlaceholder": "/caminho/para/diretorio/de/backup",
"rsyncHost": "Host Remoto",
- "rsyncHostHelp": "Hostname ou IP via SSH",
"rsyncHostPlaceholder": "backup.exemplo.com",
"rsyncUser": "Usuário SSH",
- "rsyncUserHelp": "Usuário para conexão SSH",
"rsyncUserPlaceholder": "usuario-backup",
"rsyncPath": "Caminho Remoto",
- "rsyncPathHelp": "Diretório no servidor remoto",
"rsyncPathPlaceholder": "/home/backup/fotos",
"rsyncSshKey": "Chave Privada SSH",
"rsyncSshKeyHelp": "Chave SSH para autenticação (opcional)",
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
"s3Endpoint": "Endpoint S3",
"s3EndpointHelp": "URL da API S3 (ex: s3.amazonaws.com)",
- "s3EndpointPlaceholder": "https://s3.amazonaws.com",
"s3Bucket": "Nome do Bucket",
- "s3BucketHelp": "Bucket S3 para os backups",
- "s3BucketPlaceholder": "meu-bucket-de-backup",
"s3AccessKey": "ID da Chave de Acesso",
- "s3AccessKeyHelp": "ID da chave AWS/S3",
- "s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXEMPLO",
"s3SecretKey": "Chave de Acesso Secreta",
- "s3SecretKeyHelp": "Chave secreta AWS/S3",
- "s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXEMPLO",
- "s3Region": "Região",
- "s3RegionHelp": "Região S3 (ex: us-east-1)",
- "s3RegionPlaceholder": "us-east-1"
+ "s3Region": "Região"
},
"schedule": {
"title": "Agendamento de Backup",
"scheduleType": "Tipo de Agendamento",
- "scheduleOptions": {
- "hourly": "A cada hora",
- "daily": "Diário",
- "weekly": "Semanal",
- "custom": "Expressão cron personalizada"
- },
"options": {
"hourly": "A cada hora",
"daily": "Diário",
@@ -2001,9 +1888,7 @@
"archives": "Arquivos",
"archivesHelp": "Arquivos ZIP de eventos arquivados",
"thumbnails": "Miniaturas",
- "thumbnailsHelp": "Imagens de prévia geradas (podem ser recriadas)",
- "tempFiles": "Arquivos Temporários",
- "tempFilesHelp": "Arquivos temporários de upload e processamento"
+ "thumbnailsHelp": "Imagens de prévia geradas (podem ser recriadas)"
},
"advancedOptions": {
"title": "Opções Avançadas",
@@ -2012,15 +1897,7 @@
"encryption": "Ativar Criptografia",
"encryptionHelp": "Criptografa os backups para maior segurança",
"encryptionPassphrase": "Frase de Senha da Criptografia",
- "encryptionPassphraseHelp": "Senha forte para criptografar os backups",
- "confirmPassphrase": "Confirmar Frase de Senha",
- "passphrasesDontMatch": "As senhas não coincidem"
- },
- "validation": {
- "requiredFields": "Preencha todos os campos obrigatórios",
- "invalidCron": "Expressão cron inválida",
- "connectionTestFailed": "Teste de conexão falhou",
- "connectionTestSuccess": "Teste de conexão bem-sucedido!"
+ "encryptionPassphraseHelp": "Senha forte para criptografar os backups"
},
"messages": {
"requiredFields": "Preencha todos os campos obrigatórios",
@@ -2033,23 +1910,6 @@
},
"history": {
"searchPlaceholder": "Buscar backups...",
- "allStatus": "Todos os Status",
- "status": {
- "completed": "Concluído",
- "failed": "Falhou",
- "running": "Executando",
- "partial": "Parcial"
- },
- "deleteConfirm": "Tem certeza que deseja excluir o backup de {{date}}?",
- "noBackups": "Nenhum backup encontrado",
- "tableHeaders": {
- "date": "Data",
- "type": "Tipo",
- "status": "Status",
- "size": "Tamanho",
- "duration": "Duração",
- "actions": "Ações"
- },
"columns": {
"status": "Status",
"dateTime": "Data e Hora",
@@ -2067,35 +1927,10 @@
"errorDetails": "Detalhes do Erro",
"manifest": "Manifesto"
},
- "statistics": "Estatísticas",
- "errors": "Erros",
- "backupDetails": {
- "backupId": "ID do Backup",
- "startTime": "Hora de Início",
- "endTime": "Hora de Término",
- "destination": "Destino",
- "filesProcessed": "Arquivos Processados",
- "totalSize": "Tamanho Total",
- "compressionRatio": "Taxa de Compressão",
- "errorLog": "Log de Erros",
- "noErrors": "Nenhum erro ocorrido"
- },
"pagination": {
"showing": "Mostrando {{from}}-{{to}} de {{total}} backups",
"previous": "Anterior",
"next": "Próximo"
- },
- "filter": {
- "allStatus": "Todos os Status",
- "completed": "Concluído",
- "failed": "Falhou",
- "running": "Executando",
- "partial": "Parcial"
- },
- "noBackupsFound": "Nenhum backup encontrado",
- "backupsWillAppear": "Backups aparecerão aqui quando criados",
- "messages": {
- "deleteSuccess": "Backup excluído com sucesso"
}
},
"restore": {
@@ -2208,12 +2043,6 @@
"current": "Atual",
"statusDetails": "Detalhes do Status",
"restoreLogs": "Logs da Restauração",
- "steps": {
- "completed": "Concluído",
- "running": "Executando",
- "failed": "Falhou",
- "pending": "Pendente"
- },
"success": {
"title": "Restauração Concluída com Sucesso",
"message": "Seus dados foram restaurados. Verifique se tudo está funcionando corretamente."
@@ -2226,20 +2055,13 @@
"starting": "Iniciando...",
"validating": "Validando...",
"startNewRestore": "Iniciar Nova Restauração"
- },
- "messages": {
- "restoreStarted": "Restauração iniciada com sucesso"
}
},
"messages": {
"backupStarted": "Backup iniciado com sucesso",
"backupFailed": "Falha ao iniciar backup",
"configUpdated": "Configuração de backup atualizada",
- "configUpdateFailed": "Falha ao atualizar configuração",
- "backupDeleted": "Backup excluído com sucesso",
- "deleteFailed": "Falha ao excluir backup",
- "testEmailSent": "Teste de conexão bem-sucedido!",
- "testEmailFailed": "Teste de conexão falhou"
+ "configUpdateFailed": "Falha ao atualizar configuração"
}
},
"cssTemplates": {
@@ -2266,8 +2088,6 @@
"maintenance": {
"title": "Manutenção do Sistema",
"message": "Estamos realizando uma manutenção programada para melhorar nosso serviço. Voltaremos em breve.",
- "expectedCompletion": "Previsão de conclusão:",
- "checkBackLater": "Por favor, tente novamente mais tarde",
"urgentMatters": "Para assuntos urgentes, contate"
},
"passwordChange": {
@@ -2346,18 +2166,7 @@
"pendingApproval": "Aguardando aprovação",
"noComments": "Ainda sem comentários. Seja o primeiro!",
"rating": "Avaliação",
- "ratePhoto": "Avalie esta foto",
- "yourRating": "Sua avaliação",
- "averageRating": "Avaliação média",
- "totalRatings": "avaliações",
"likes": "Curtidas",
- "favorites": "Favoritos",
- "likePhoto": "Curtir esta foto",
- "favoritePhoto": "Adicionar aos favoritos",
- "photoFeedback": "Feedback da Foto",
- "hasFeedback": "Possui feedback",
- "hasComments": "Possui comentários",
- "hasRating": "Possui avaliação",
"settings": {
"title": "Configurações de Feedback de Convidados",
"enableFeedback": "Ativar feedback",
@@ -2369,25 +2178,113 @@
"comments": "Comentários",
"commentsDesc": "Comentários em texto nas fotos",
"favorites": "Favoritos",
- "favoritesDesc": "Marcar fotos como favoritas"
- }
+ "favoritesDesc": "Marcar fotos como favoritas",
+ "identityMode": "Modo de identidade",
+ "identityModeSimple": "Feedback simples",
+ "identityModeSimpleDesc": "Anónimo, baseado no dispositivo. Todos os visitantes no mesmo dispositivo partilham o estado.",
+ "identityModeGuest": "Seleções por convidado",
+ "identityModeGuestDesc": "Cada visitante introduz o seu nome. Ativa o rastreamento por convidado e informações de administração.",
+ "privacyModeration": "Privacidade e Moderação",
+ "requireInfo": "Exigir nome e e-mail",
+ "requireInfoDesc": "Os convidados devem fornecer nome e e-mail para deixar feedback",
+ "moderateComments": "Moderar comentários",
+ "moderateCommentsDesc": "Os comentários necessitam de aprovação antes de serem visíveis",
+ "showToGuests": "Mostrar feedback aos convidados",
+ "showToGuestsDesc": "Outros convidados podem ver avaliações, gostos e comentários aprovados",
+ "enableRateLimiting": "Ativar limitação de taxa",
+ "rateLimitingDesc": "Previne spam limitando a frequência de feedback",
+ "timeWindow": "Janela de tempo (minutos)",
+ "maxRequests": "Pedidos máx."
+ },
+ "settingsUpdated": "Definições de feedback atualizadas",
+ "settingsUpdateError": "Falha ao atualizar definições",
+ "moderated": "Feedback moderado",
+ "deleted": "Feedback eliminado",
+ "exported": "Feedback exportado",
+ "exportError": "Falha ao exportar feedback",
+ "title": "Gestão de feedback",
+ "exportCSV": "Exportar CSV",
+ "exportJSON": "Exportar JSON",
+ "tabs": {
+ "settings": "Definições",
+ "feedback": "Feedback",
+ "analytics": "Análise",
+ "moderation": "Moderação"
+ },
+ "allTypes": "Todos os tipos",
+ "types": {
+ "rating": "Avaliações",
+ "like": "Gostos",
+ "comment": "Comentários",
+ "favorite": "Favoritos"
+ },
+ "allStatuses": "Todos os estados",
+ "status": {
+ "pending": "Pendente",
+ "approved": "Aprovado",
+ "hidden": "Oculto"
+ },
+ "noFeedback": "Sem feedback encontrado",
+ "approve": "Aprovar",
+ "hide": "Ocultar",
+ "unhide": "Mostrar",
+ "confirmDelete": "Tem a certeza que quer eliminar este feedback?",
+ "avgRating": "Avaliação média",
+ "totalRatings_many": "{{count}} avaliações",
+ "totalRatings_one": "{{count}} avaliação",
+ "totalRatings_other": "{{count}} avaliações",
+ "totalLikes": "Total de gostos",
+ "totalComments": "Total de comentários",
+ "pendingModeration_many": "{{count}} pendentes",
+ "pendingModeration_one": "{{count}} pendente",
+ "pendingModeration_other": "{{count}} pendentes",
+ "totalInteractions": "Interações totais",
+ "topRated": "Fotos mais bem avaliadas",
+ "recentComments": "Comentários recentes",
+ "wordFilters": "Filtros de palavras",
+ "wordFiltersDesc": "Gerir palavras bloqueadas para moderação de comentários",
+ "manageFilters": "Gerir filtros de palavras",
+ "manage": "Gerir feedback",
+ "ratingSubmitted": "Avaliação submetida",
+ "ratingError": "Falha ao submeter avaliação",
+ "rateStar_many": "Avaliar {{count}} estrelas",
+ "rateStar_one": "Avaliar {{count}} estrela",
+ "rateStar_other": "Avaliar {{count}} estrelas",
+ "ratingsCount_many": "{{count}} avaliações",
+ "ratingsCount_one": "{{count}} avaliação",
+ "ratingsCount_other": "{{count}} avaliações",
+ "likeError": "Falha ao atualizar gosto",
+ "unlike": "Remover gosto",
+ "like": "Gostar",
+ "favoriteError": "Falha ao atualizar favorito",
+ "unfavorite": "Remover dos favoritos",
+ "favorite": "Adicionar aos favoritos",
+ "invalidEmail": "Endereço de e-mail inválido",
+ "identityRequired": "A sua informação é necessária",
+ "identityReason": "Por favor forneça o seu nome e e-mail para submeter {{type}}.",
+ "namePlaceholder": "Introduza o seu nome",
+ "emailPlaceholder": "Introduza o seu e-mail",
+ "submitFeedback": "Submeter feedback",
+ "moderationSuccess": "Feedback moderado com sucesso",
+ "pendingModeration": "Pendente de moderação",
+ "pending": "pendente",
+ "noPendingComments": "Sem comentários pendentes de moderação",
+ "onPhoto": "Na foto",
+ "showAll_many": "Mostrar todos os {{count}} comentários pendentes",
+ "showAll_one": "Mostrar o {{count}} comentário pendente",
+ "showAll_other": "Mostrar todos os {{count}} comentários pendentes",
+ "viewAllFeedback": "Ver todo o feedback e definições"
},
"filter": {
"feedbackFilters": "Filtros de Feedback",
"clear": "Limpar",
"rating": "Avaliação",
- "allPhotos": "Todas as Fotos",
- "anyRating": "Qualquer Avaliação",
- "oneStarPlus": "1+ Estrela",
- "twoStarsPlus": "2+ Estrelas",
- "threeStarsPlus": "3+ Estrelas",
- "fourStarsPlus": "4+ Estrelas",
- "fiveStarsOnly": "Apenas 5 Estrelas",
"hasLikes": "Possui curtidas",
"hasFavorites": "Possui favoritos",
"hasComments": "Possui comentários",
"showingPhotos": "Total de fotos",
- "withRatings": "Com avaliações"
+ "withRatings": "Com avaliações",
+ "combineWith": "Combinar com"
},
"adminLogin": {
"title": "Login Administrativo",
@@ -2402,7 +2299,6 @@
"passwordRequired": "A senha é obrigatória",
"passwordMinLength": "A senha deve ter pelo menos 6 caracteres",
"rememberMe": "Lembrar-me",
- "forgotPassword": "Esqueceu a senha?",
"signIn": "Entrar",
"loginSuccess": "Login realizado com sucesso!",
"networkError": "Erro de rede. Verifique sua conexão.",
@@ -2442,9 +2338,11 @@
"button": "Exportar",
"success": "Exportação baixada com sucesso",
"error": "Falha na exportação: ",
- "exportSelected": "Exportar {{count}} selecionados",
"exportFiltered": "Exportar fotos filtradas",
- "hint": "Selecione fotos ou aplique filtros para exportar"
+ "hint": "Selecione fotos ou aplique filtros para exportar",
+ "exportSelected_many": "Exportar {{count}} selecionados",
+ "exportSelected_one": "Exportar {{count}} selecionado",
+ "exportSelected_other": "Exportar {{count}} selecionados"
},
"photoSort": {
"defaultSort": "Ordenação padrão das fotos",
@@ -2455,5 +2353,19 @@
"filenameAZ": "Nome do arquivo (A-Z)",
"filenameZA": "Nome do arquivo (Z-A)",
"dateTaken": "Data da captura"
+ },
+ "photos": {
+ "moveToCategory_many": "Mover {{count}} fotos para categoria",
+ "moveToCategory_one": "Mover {{count}} foto para categoria",
+ "moveToCategory_other": "Mover {{count}} fotos para categoria",
+ "selectCategory": "Selecionar categoria",
+ "uncategorized": "Sem categoria",
+ "movePhotos": "Mover fotos",
+ "selectedCategory": "categoria selecionada",
+ "movedToCategory_many": "{{count}} fotos movidas para {{category}}",
+ "movedToCategory_one": "{{count}} foto movida para {{category}}",
+ "movedToCategory_other": "{{count}} fotos movidas para {{category}}",
+ "moveToCategoryFailed": "Falha ao mover fotos para categoria",
+ "moveToCategory": "Mover para categoria"
}
}
diff --git a/frontend/src/i18n/locales/ru.json b/frontend/src/i18n/locales/ru.json
index 53b5a44b..d4f5177b 100644
--- a/frontend/src/i18n/locales/ru.json
+++ b/frontend/src/i18n/locales/ru.json
@@ -81,8 +81,6 @@
"delete": "Удалить",
"edit": "Редактировать",
"add": "Добавить",
- "search": "Поиск",
- "filter": "Фильтр",
"sortBy": "Сортировать по",
"yes": "Да",
"no": "Нет",
@@ -91,35 +89,41 @@
"previous": "Назад",
"close": "Закрыть",
"logout": "Выйти",
- "menu": "Меню",
"change": "Изменить",
"remove": "Удалить",
"download": "Скачать",
"downloadAll": "Скачать все",
- "uploading": "Загрузка...",
- "uploaded": "Загружено",
"photo": "фото",
"photos": "фото",
"video": "видео",
- "videos": "видео",
"media": "медиа",
- "restore": "Восстановить",
- "actions": "Действия",
- "refresh": "Обновить",
- "preview": "Предпросмотр",
- "processing": "Обработка",
"upload": "Загрузить",
- "days": "дней",
"customize": "Настроить",
"hide": "Скрыть",
"unknown": "Неизвестно",
"notSet": "Не задано",
"of": "из",
- "up": "Вверх",
- "select": "Выбрать",
"selected": "Выбрано",
"chunk": "Пакет",
- "optional": "необязательно"
+ "optional": "необязательно",
+ "tryAgain": "Повторить",
+ "active": "Активный",
+ "inactive": "Неактивный",
+ "create": "Создать",
+ "unknownDate": "Неизвестная дата",
+ "pageOf": "Страница {{current}} из {{total}}",
+ "collapse": "Свернуть",
+ "expand": "Развернуть",
+ "submitting": "Отправка…",
+ "copy": "Копировать",
+ "copied": "Скопировано!",
+ "applying": "Применение…",
+ "done": "Готово",
+ "retry": "Повторить",
+ "characters": "символов",
+ "saveChanges": "Сохранить изменения",
+ "resetChanges": "Сбросить изменения",
+ "dismiss": "Закрыть"
},
"upload": {
"photoCategory": "Категория фото",
@@ -127,42 +131,40 @@
"eventSpecific": "(Для конкретного события)",
"clickToUpload": "Нажмите для загрузки или перетащите файлы",
"fileRequirements": "JPEG, PNG или WebP (макс. 50 МБ на файл, {{limit}} файлов за загрузку)",
- "fileRequirementsMedia": "Изображения JPEG, PNG или WebP, а также видео MP4/MOV/WEBM (макс. 50 МБ на файл, {{limit}} файлов за загрузку)",
- "unsupportedFiles": "Некоторые файлы пропущены, так как формат не поддерживается (используйте JPEG/PNG/WebP/MP4/MOV/WEBM).",
"selectedFiles": "Выбранные файлы",
"uploading": "Загрузка...",
"uploadComplete": "Загрузка завершена!",
- "uploadFailed": "Ошибка загрузки",
"someFilesFailed": "Не удалось загрузить некоторые файлы",
"replaceByName": "Заменить существующие фото с таким же именем",
- "replacedFiles": "{{count}} фото заменено",
"uploadPhotos": "Загрузить фото",
"uploadMedia": "Загрузить фото и видео",
- "importExternal": "Импортировать из внешней папки",
- "externalImportInfo": "Все изображения из выбранной папки будут импортированы.",
- "selectExternalFolder": "Выберите внешнюю папку в /external-media",
- "importFromSelectedFolder": "Импортировать из выбранной папки",
"maxFilesReached": "Максимальное количество файлов: {{limit}}",
"someFilesSkipped": "Можно добавить ещё только {{allowed}} файла(ов) (лимит {{limit}})",
"tooManyFiles": "За один раз можно загрузить не более {{limit}} файлов",
"limitInfo": "{{selected}} из {{limit}} файлов выбрано (осталось {{remaining}})",
"limitReached": "Достигнут лимит загрузки ({{limit}} файлов за раз)",
- "uploadingChunks": "Загрузка {{count}} файлов в {{total}} пакетах...",
- "mediaCategory": "Категория медиа",
- "uploadAction": "Загрузить {{count}} файлов"
+ "replacedFiles_few": "{{count}} фото заменено",
+ "replacedFiles_many": "{{count}} фото заменено",
+ "replacedFiles_one": "{{count}} фото заменено",
+ "replacedFiles_other": "{{count}} фото заменено",
+ "processingFailed_few": "{{count}} фото не удалось обработать",
+ "processingFailed_many": "{{count}} фото не удалось обработать",
+ "processingFailed_one": "{{count}} фото не удалось обработать",
+ "processingFailed_other": "{{count}} фото не удалось обработать",
+ "processing": "Обработка фото…",
+ "processingProgress": "{{complete}} из {{total}} готово",
+ "processingHint": "Файлы загружены. PicPeak создаёт миниатюры и читает метаданные. Вы можете покинуть страницу — работа продолжается в фоне.",
+ "transferring": "Передача",
+ "uploadingChunks_few": "{{count}} пакета загружается",
+ "uploadingChunks_many": "{{count}} пакетов загружается",
+ "uploadingChunks_one": "{{count}} пакет загружается",
+ "uploadingChunks_other": "{{count}} пакета загружается",
+ "retryFailed": "Повторить неудавшиеся"
},
"navigation": {
"dashboard": "Панель управления",
"events": "События",
- "archives": "Архивы",
- "settings": "Настройки",
- "eventTypes": "Типы событий",
- "branding": "Брендинг",
- "analytics": "Аналитика",
- "emailSettings": "Настройки email",
- "backup": "Резервное копирование",
- "cmsPages": "Страницы CMS",
- "users": "Пользователи"
+ "settings": "Настройки"
},
"archives": {
"title": "Архивы",
@@ -205,67 +207,44 @@
"deleteSuccess": "Архив безвозвратно удалён"
},
"auth": {
- "login": "Войти",
"password": "Пароль",
"enterPassword": "Введите пароль галереи",
"passwordPlaceholder": "Введите пароль галереи",
"invalidPassword": "Неверный пароль",
"wrongPassword": "Неверный пароль. Проверьте пароль и попробуйте снова.",
"tooManyAttempts": "Слишком много неудачных попыток входа. Попробуйте позже.",
- "sessionExpired": "Сессия истекла",
"pleaseEnterPassword": "Пожалуйста, введите пароль",
"passwordHint": "Пароль предоставлен организатором события. Свяжитесь с ним, если у вас его нет."
},
"gallery": {
- "title": "Фотогалерея",
- "welcomeMessage": "Приветственное сообщение",
- "expiresOn": "Истекает",
"expires": "Истекает",
"expired": "Истекла",
- "daysRemaining": "Осталось {{days}} дней",
- "dayRemaining": "Остался 1 день",
- "hoursRemaining": "Осталось {{hours}} часов",
- "expiredMessage": "Эта галерея истекла {{date}}",
"contactOrganizer": "Свяжитесь с организатором события, если вам нужен доступ к этим фотографиям",
"searchPhotos": "Поиск фото по имени файла...",
"sortByDate": "Сортировать по дате",
"sortByName": "Сортировать по имени",
"sortBySize": "Сортировать по размеру",
"allPhotos": "Все фото",
- "filter": "Фильтр",
"feedbackFilter": "Фильтр по отзывам",
"all": "Все",
"liked": "Понравившиеся",
"favorited": "Избранные",
"favorites": "Избранное",
- "downloadSelected": "Скачать выбранные ({{count}})",
- "shareGallery": "Поделиться галереей",
"needHelp": "Нужна помощь? Напишите нам:",
"noPhotosFound": "Фотографии не найдены",
"failedToLoad": "Не удалось загрузить фото",
"tryAgain": "Попробовать снова",
"loading": "Загрузка галереи...",
"expiredOn": "Эта галерея истекла {{date}}.",
- "expiresIn": "Галерея истекает через {{count}} день",
- "expiresIn_plural": "Галерея истекает через {{count}} дней",
"downloadBefore": "Скачайте ваши фото, пока они ещё доступны.",
- "publicGalleryTitle": "Эта галерея доступна публично",
- "publicGallerySubtitle": "Загрузка фотографий...",
"viewGallery": "Просмотреть галерею",
"downloadAll": "Скачать все",
- "downloading": "Скачивание {{count}} фото...",
- "downloading_plural": "Скачивание {{count}} фото...",
- "downloadedPhotos": "Скачано {{count}} фото!",
- "downloadedPhotos_plural": "Скачано {{count}} фото!",
"downloadError": "Не удалось скачать некоторые фото",
"selectPhotos": "Выбрать фото",
"cancelSelection": "Отменить выбор",
- "photosSelected": "{{count}} выбрано",
"selectAll": "Выбрать все",
"deselectAll": "Снять выбор",
"deleteSelected": "Удалить выбранные",
- "photosCount": "{{count}} фото",
- "photosCount_plural": "{{count}} фото",
"searchByFilename": "Поиск по имени файла...",
"uncategorized": "Без категории",
"sortAscending": "По возрастанию",
@@ -273,8 +252,6 @@
"remaining": "осталось",
"selectPhotosHint": "Совет: используйте Ctrl+Click (Cmd+Click на Mac) для быстрого выбора нескольких фото",
"filters": "Фильтры",
- "openFilters": "Открыть фильтры",
- "toggleSidebar": "Переключить боковую панель",
"toggleMenu": "Переключить меню",
"allCategories": "Все категории",
"categories": "Категории",
@@ -307,14 +284,66 @@
"anonymous": "Аноним"
},
"rated": "Оценено",
- "commented": "Прокомментировано"
+ "commented": "Прокомментировано",
+ "expiresIn_few": "Галерея истекает через {{count}} дня",
+ "expiresIn_many": "Галерея истекает через {{count}} дней",
+ "expiresIn_one": "Галерея истекает через {{count}} день",
+ "expiresIn_other": "Галерея истекает через {{count}} дня",
+ "downloading_few": "Загрузка {{count}} фото…",
+ "downloading_many": "Загрузка {{count}} фото…",
+ "downloading_one": "Загрузка 1 фото…",
+ "downloading_other": "Загрузка {{count}} фото…",
+ "photosSelected_few": "Выбрано {{count}} фото",
+ "photosSelected_many": "Выбрано {{count}} фото",
+ "photosSelected_one": "Выбрано {{count}} фото",
+ "photosSelected_other": "Выбрано {{count}} фото",
+ "downloadSelected_few": "Скачать {{count}} фото",
+ "downloadSelected_many": "Скачать {{count}} фото",
+ "downloadSelected_one": "Скачать {{count}} фото",
+ "downloadSelected_other": "Скачать {{count}} фото",
+ "guestRecovery": {
+ "invalidEmail": "Введите корректный адрес электронной почты",
+ "codeSent": "Проверьте входящие: вам отправлен код подтверждения.",
+ "requestError": "Не удалось отправить код. Попробуйте снова.",
+ "invalidCode": "Введите 6-значный код",
+ "verifyError": "Код недействителен или истёк.",
+ "back": "Назад",
+ "title": "Восстановить выборки",
+ "emailStepDescription": "Введите адрес электронной почты, который вы использовали ранее. Мы отправим 6-значный код подтверждения.",
+ "codeStepDescription": "Введите 6-значный код, отправленный на ваш адрес электронной почты.",
+ "emailLabel": "Электронная почта",
+ "sendCode": "Отправить код",
+ "codeLabel": "Код подтверждения",
+ "verifyCode": "Подтвердить и продолжить"
+ },
+ "guestPrompt": {
+ "nameRequired": "Имя обязательно",
+ "invalidEmail": "Неверный адрес электронной почты",
+ "emailRequired": "Электронная почта обязательна",
+ "error": "Регистрация не удалась",
+ "title": "Добро пожаловать — как вас зовут?",
+ "description": "Ваши выборки будут сохранены под этим именем, чтобы фотограф знал, какие фото вам нравятся.",
+ "nameLabel": "Ваше имя",
+ "namePlaceholder": "Введите ваше имя",
+ "emailLabelRequired": "Электронная почта",
+ "emailLabel": "Электронная почта (необязательно)",
+ "emailPlaceholder": "вы@пример.рф",
+ "submit": "Продолжить",
+ "alreadyHere": "Я уже был здесь раньше"
+ },
+ "footer": {
+ "forgetMeConfirm": "Ваше имя и выборки будут удалены из этой галереи.",
+ "forgetMe": "Забыть меня ({{name}})"
+ },
+ "photosCount_few": "{{count}} фото",
+ "photosCount_many": "{{count}} фото",
+ "photosCount_one": "{{count}} фото",
+ "photosCount_other": "{{count}} фото",
+ "poweredBy": "Работает на PicPeak"
},
"categories": {
"title": "Категории фото",
- "global": "Глобальные категории",
- "eventSpecific": "Категории конкретного события",
"addCategory": "Добавить категорию",
- "organizationInfo": "Организуйте фотографии по категориям. Категории помогают гостям ориентироваться и находить нужные снимки.",
"eventSpecificCategories": "Категории конкретного события",
"noEventSpecificCategories": "Нет категорий для этого события. По умолчанию доступны глобальные категории.",
"globalCategoriesAlwaysAvailable": "Глобальные категории (всегда доступны):",
@@ -324,10 +353,8 @@
"failedToCreateCategory": "Не удалось создать категорию",
"failedToDeleteCategory": "Не удалось удалить категорию",
"categoryName": "Название категории",
- "noCategory": "Без категории",
"noCategoriesYet": "Категорий пока нет. Создайте первую категорию для организации фото.",
"deleteConfirm": "Вы уверены, что хотите удалить «{{name}}»?",
- "cannotDelete": "Нельзя удалить категорию с фотографиями. Сначала переназначьте фото.",
"setCoverPhoto": "Установить обложку",
"removeCoverPhoto": "Убрать обложку",
"coverPhotoSet": "Обложка успешно установлена",
@@ -342,36 +369,16 @@
"totalViews": "Всего просмотров",
"totalDownloads": "Всего скачиваний",
"uniqueVisitors": "Уникальных посетителей",
- "createNewEvent": "Создать новое событие",
- "setupNewGallery": "Настройте новую фотогалерею для вашего события",
- "createNewEventSubtitle": "Настройте новую фотогалерею для вашего события",
"eventNamePlaceholder": "например, Свадьба Ивана и Марии",
- "welcomeMessageOptional": "Приветственное сообщение (необязательно)",
"welcomeMessagePlaceholder": "Добро пожаловать на наш особый день! Скачивайте и делитесь этими воспоминаниями...",
"hostEmailPlaceholder": "client@example.com",
"adminEmailPlaceholder": "admin@example.com",
"adminEmailPickFromAdmins": "Выбрать из админов:",
"adminEmailCustom": "Произвольный e-mail",
- "securityAndAccess": "Безопасность и доступ",
"accessAndSecurity": "Доступ и безопасность",
"enterPassword": "Введите пароль",
"passwordPlaceholder": "Введите надёжный пароль",
"confirmPasswordPlaceholder": "Подтвердите пароль",
- "galleryExpiresOn": "Галерея истекает {{date}}",
- "guestsWillReceiveWarning": "Гости получат предупреждение по email за 7 дней до истечения.",
- "types": {
- "wedding": "Свадьба",
- "birthday": "День рождения",
- "corporate": "Корпоратив",
- "other": "Прочее"
- },
- "themes": {
- "default": "По умолчанию",
- "oceanBlue": "Океанский синий",
- "royalPurple": "Королевский фиолетовый",
- "roseGold": "Розовое золото",
- "sunsetAmber": "Закатный янтарь"
- },
"eventDetails": "Детали события",
"eventName": "Название события",
"eventType": "Тип события",
@@ -380,11 +387,9 @@
"hostName": "Имя клиента",
"hostNamePlaceholder": "Иван Иванов",
"adminEmail": "Email администратора",
- "adminNotificationEmail": "Email для уведомлений администратора",
"expirationDate": "Дата истечения",
"active": "Активный",
"archived": "В архиве",
- "photoCount": "{{count}} фото",
"totalSize": "Общий размер",
"shareLink": "Ссылка для доступа",
"copyLink": "Копировать ссылку",
@@ -397,10 +402,7 @@
"backToEvents": "Назад к событиям",
"loadingEventDetails": "Загрузка деталей события...",
"saveChanges": "Сохранить изменения",
- "eventExpired": "Это событие истекло",
"eventExpiresIn": "Это событие истекает через {{days}} дней",
- "guestsNoAccess": "Гости больше не могут получить доступ к галерее. Рассмотрите архивирование события.",
- "warningEmailsSent": "Предупреждающие письма отправлены клиенту.",
"overview": "Обзор",
"photos": "Фотографии",
"categories": "Категории",
@@ -415,7 +417,6 @@
"externalFolderEmpty": "Нет вложенных папок",
"clearSelection": "Очистить",
"welcomeMessage": "Приветственное сообщение",
- "noWelcomeMessage": "Приветственное сообщение не задано",
"created": "Создано",
"expires": "Истекает",
"shareWithGuests": "Поделитесь этой ссылкой с гостями. Им понадобится пароль для доступа к галерее.",
@@ -429,28 +430,18 @@
"managePhotos": "Управление фото",
"actions": "Действия",
"archivingInfo": "При архивировании будет создан ZIP-файл всех фотографий, и галерея станет недоступна публично.",
- "statistics": "Статистика",
- "views": "Просмотры",
- "downloads": "Скачивания",
- "noStatistics": "Статистика пока недоступна",
- "archiveStatus": "Статус архива",
"archivedOn": "Архивировано",
"downloadArchive": "Скачать архив",
"loadingPhotos": "Загрузка фото...",
"photoCategories": "Категории фото",
"organizeCategoriesInfo": "Организуйте фотографии по категориям. Категории помогают гостям ориентироваться и находить нужные снимки.",
"categoriesTip": "Совет: категории привязаны к событию. Создавайте пользовательские категории, например «Церемония», «Банкет», «Портреты».",
- "contactInformation": "Контактная информация",
- "hostEmailHelp": "Клиент будет получать уведомления о создании и истечении галереи",
- "adminEmailHelp": "Будет получать системные уведомления и подтверждения архивирования",
- "securityAccess": "Безопасность и доступ",
"galleryPassword": "Пароль галереи",
"requirePasswordToggle": "Требовать пароль для этой галереи",
"requirePasswordToggleHelp": "Отключите, если хотите открыть галерею без пароля. Любой, у кого есть ссылка, сможет просматривать фото.",
"publicGalleryWarning": "Публичные галереи доступны всем, у кого есть ссылка. Рассмотрите включение водяных знаков и мониторинга активности.",
"passwordHelperText": "Можно использовать даты, например «04.07.2025», или любой текст из 6+ символов",
"confirmPassword": "Подтвердить пароль",
- "showPasswords": "Показать пароли",
"newPasswordLabel": "Новый пароль галереи",
"passwordReset": {
"title": "Сбросить пароль галереи",
@@ -475,15 +466,10 @@
"errorMinLength": "Пароль должен содержать не менее 6 символов",
"errorMismatch": "Пароли не совпадают"
},
- "gallerySettings": "Настройки галереи",
"themeAndStyle": "Тема и стиль",
- "colorTheme": "Цветовая тема",
"galleryExpiration": "Срок действия галереи",
- "galleryExpiresIn": "Галерея истекает через",
"daysAfterEvent": "дней после даты события",
"expiresOn": "Истекает",
- "galleryWillExpireOn": "Галерея истечёт {{date}}",
- "expirationWarning": "Гости получат предупреждение по email за 7 дней до истечения.",
"noExpiration": "Без срока действия",
"noExpirationHelp": "Эта галерея будет активна до ручного архивирования.",
"photoCap": "Лимит фото",
@@ -495,11 +481,7 @@
"uploadCategory": "Категория загрузки",
"selectCategory": "Выберите категорию для загрузок пользователей",
"uploadCategoryHelp": "Все загружаемые гостями фото будут добавлены в эту категорию",
- "userUploadWarning": "Загрузки пользователей проверяются и могут быть удалены администраторами в любое время.",
"allowDownloads": "Разрешить скачивание фото",
- "allowDownloadsHelp": "Разрешить гостям скачивать фотографии из этой галереи",
- "downloadPermissions": "Разрешения на скачивание",
- "downloadsEnabled": "Скачивание разрешено",
"downloadsDisabled": "Скачивание запрещено",
"downloadProtection": "Защита от скачивания",
"disableRightClick": "Заблокировать контекстное меню",
@@ -548,15 +530,6 @@
"heroImageAnchorBottom": "Снизу",
"heroPreview": "Предпросмотр баннера",
"noPhotosAvailable": "Фотографии недоступны",
- "processingRequest": "Обработка запроса...",
- "eventTypeWedding": "Свадьба",
- "eventTypeBirthday": "День рождения",
- "eventTypeCorporate": "Корпоратив",
- "eventTypeOther": "Прочее",
- "days30": "30 дней",
- "days60": "60 дней",
- "days90": "90 дней",
- "days365": "1 год",
"inactive": "Неактивный",
"expired": "Истёк",
"draft": "Черновик",
@@ -564,31 +537,44 @@
"publishConfirm": "Галерея станет доступной, и клиенту будет отправлено уведомление по электронной почте. Продолжить?",
"publishSuccess": "Галерея опубликована, клиент уведомлён!",
"draftBanner": "Эта галерея находится в режиме черновика. Загрузите фотографии, затем опубликуйте, когда будете готовы.",
- "daysLeft": "(осталось {{count}} день)",
- "daysLeft_plural": "(осталось {{count}} дней)",
"subtitle": "Управляйте своими фотогалереями и событиями",
- "loadingEvents": "Загрузка событий...",
"failedToLoadEvents": "Не удалось загрузить события",
"tryAgain": "Попробовать снова",
- "bulkArchiveSuccess": "Успешно архивировано {{count}} событий",
"bulkArchivePartial": "Архивировано {{success}} событий, {{failed}} не удалось",
"deleteSelected": "Удалить выбранные",
"bulkDelete": {
- "title": "Безвозвратно удалить {{count}} событий?",
"warning": "Выбранные события, все их фотографии, архивы и журналы аудита будут удалены безвозвратно. Это действие невозможно отменить.",
+ "passwordLabel": "Введите пароль для подтверждения",
+ "passwordPlaceholder": "Ваш пароль администратора",
+ "passwordHelp": "Мы запрашиваем пароль для защиты от случайного массового удаления.",
+ "incorrectPassword": "Неверный пароль. События не были удалены.",
"confirmLabel": "Введите {{literal}} для подтверждения",
"confirmHelp": "Подтверждение вводом текста предотвращает случайные удаления и не зависит от автозаполнения браузера или сочетаний клавиш с passkey.",
"submit": "Удалить {{count}} событий",
"processing": "Удаление {{count}} событий. Это может занять несколько минут — пожалуйста, не закрывайте это окно.",
"successAll": "Безвозвратно удалено {{count}} событий",
"successPartial": "Удалено {{success}} событий, {{failed}} не удалось",
- "errorGeneric": "Не удалось удалить события"
+ "errorGeneric": "Не удалось удалить события",
+ "successAll_few": "{{count}} события удалены навсегда",
+ "successAll_many": "{{count}} событий удалено навсегда",
+ "successAll_one": "{{count}} событие удалено навсегда",
+ "successAll_other": "{{count}} событий удалено навсегда",
+ "title_few": "Удалить навсегда {{count}} события?",
+ "title_many": "Удалить навсегда {{count}} событий?",
+ "title_one": "Удалить навсегда {{count}} событие?",
+ "title_other": "Удалить навсегда {{count}} событий?",
+ "processing_few": "Удаление {{count}} событий. Это может занять несколько минут — не закрывайте окно.",
+ "processing_many": "Удаление {{count}} событий. Это может занять несколько минут — не закрывайте окно.",
+ "processing_one": "Удаление {{count}} события. Это может занять несколько минут — не закрывайте окно.",
+ "processing_other": "Удаление {{count}} событий. Это может занять несколько минут — не закрывайте окно.",
+ "submit_few": "Удалить {{count}} события",
+ "submit_many": "Удалить {{count}} событий",
+ "submit_one": "Удалить {{count}} событие",
+ "submit_other": "Удалить {{count}} событий"
},
"searchEventsPlaceholder": "Поиск событий...",
"all": "Все",
"expiring": "Истекающие",
- "eventsSelected": "{{count}} событие выбрано",
- "eventsSelected_plural": "{{count}} событий выбрано",
"clear": "Очистить",
"archiveSelected": "Архивировать выбранные",
"publicAccess": "Открытый доступ",
@@ -617,22 +603,14 @@
"extendSevenDays": "Продлить на 7 дней",
"welcomeMessageLabel": "Приветственное сообщение",
"noWelcomeMessageSet": "Приветственное сообщение не задано",
- "createdOn": "Создано",
"copy": "Копировать",
"copied": "Скопировано!",
- "organizingPhotosInfo": "Организуйте фотографии по категориям. Это помогает гостям ориентироваться.",
"archiveStatusTitle": "Статус архива",
"downloadingArchive": "Скачивание архива {{name}}...",
"downloadStarted": "Скачивание началось",
"failedToDownloadArchive": "Не удалось скачать архив",
- "statisticsNotAvailable": "Статистика пока недоступна",
- "photoFilters": "Фильтры фото",
- "noStatisticsAvailableYet": "Статистика пока недоступна",
- "addPlus": "Добавить+",
"galleryTheme": "Тема галереи",
- "customizeTheme": "Настроить тему",
"noThemeSet": "Тема не настроена",
- "customizingTheme": "Настройка темы галереи",
"customizingThemeFor": "Настройка темы для {{event}}",
"customCssTemplate": "Пользовательский CSS-шаблон",
"customCssTemplateDesc": "Примените пользовательский CSS-шаблон для уникального оформления галереи.",
@@ -646,26 +624,52 @@
"renamingFiles": "Переименование файлов...",
"complete": "Готово!",
"failed": "Ошибка переименования",
- "filesRenamed": "Обновлено {{count}} файлов",
- "confirm": "Переименовать событие"
+ "confirm": "Переименовать событие",
+ "success": "Событие успешно переименовано!",
+ "filesRenamed_few": "{{count}} файла обновлено",
+ "filesRenamed_many": "{{count}} файлов обновлено",
+ "filesRenamed_one": "{{count}} файл обновлён",
+ "filesRenamed_other": "{{count}} файлов обновлено",
+ "newLink": "Новая ссылка на галерею",
+ "currentName": "Текущее имя:",
+ "newName": "Новое название события",
+ "enterNewName": "Введите новое название события",
+ "newUrl": "Новый URL:",
+ "checkingAvailability": "Проверка доступности…",
+ "resendEmail": "Повторно отправить приглашение с новой ссылкой",
+ "emailTo": "Отправить письмо с доступом к галерее на",
+ "warningTitle": "Обратите внимание:",
+ "warning1": "URL галереи изменится",
+ "warning2": "Старые URL автоматически перенаправят на новый",
+ "warning3": "Файлы фото могут быть переименованы"
},
- "activeFilter": "Активные",
- "archivedFilter": "Архивированные",
- "sortByName": "По имени",
- "sortByDate": "По дате",
- "sortByExpiration": "По сроку",
- "photosCount": "Фото",
- "moreActions": "Ещё",
- "copyLinkTooltip": "Копировать ссылку",
- "viewGalleryTooltip": "Просмотр галереи",
- "uploadPhotosTooltip": "Загрузить фото",
- "editTooltip": "Редактировать",
- "archiveTooltip": "Архивировать",
- "noEvents": "События не найдены",
- "noEventsDescription": "Создайте своё первое событие, чтобы начать.",
- "bulkArchive": "Архивировать",
- "confirmBulkArchive": "Вы уверены, что хотите архивировать {{count}} событие(й)?",
- "confirmBulkArchiveDescription": "Это действие нельзя отменить. Архивированные события больше не будут доступны публично."
+ "bulkArchiveSuccess_few": "{{count}} события успешно архивированы",
+ "bulkArchiveSuccess_many": "{{count}} событий успешно архивировано",
+ "bulkArchiveSuccess_one": "{{count}} событие успешно архивировано",
+ "bulkArchiveSuccess_other": "{{count}} событий успешно архивировано",
+ "daysLeft_few": "(осталось {{count}} дня)",
+ "daysLeft_many": "(осталось {{count}} дней)",
+ "daysLeft_one": "(остался {{count}} день)",
+ "daysLeft_other": "(осталось {{count}} дней)",
+ "eventsSelected_few": "Выбрано {{count}} события",
+ "eventsSelected_many": "Выбрано {{count}} событий",
+ "eventsSelected_one": "Выбрано {{count}} событие",
+ "eventsSelected_other": "Выбрано {{count}} событий",
+ "paginationLabel": "{{from}}–{{to}} из {{total}}",
+ "filtered": "отфильтровано",
+ "pageOf": "Страница {{page}} из {{totalPages}}",
+ "notFound": "Событие не найдено",
+ "customerPhone": "Телефон клиента",
+ "customerPhonePlaceholder": "+7 999 123 4567",
+ "allowPresignedDownload": "Разрешить прямое скачивание с S3 (без водяного знака, только режим S3)",
+ "neverExpires": "Никогда",
+ "rightClickBlocked": "Правая кнопка мыши заблокирована",
+ "devtoolsDetection": "Обнаружение инструментов разработчика",
+ "watermarked": "С водяным знаком",
+ "importExternal": "Импорт из внешней папки",
+ "externalImportInfo": "Все изображения из выбранной папки будут импортированы.",
+ "selectExternalFolder": "Выберите внешнюю папку в /external-media",
+ "importFromSelectedFolder": "Импортировать из выбранной папки"
},
"settings": {
"title": "Системные настройки",
@@ -677,9 +681,7 @@
"siteUrl": "URL сайта",
"siteUrlHelp": "Используется для генерации ссылок галереи в письмах",
"defaultExpiration": "Срок действия по умолчанию (дней)",
- "defaultExpirationHelp": "Как долго галереи остаются активными по умолчанию",
"maxFileSize": "Макс. размер файла (МБ)",
- "maxFileSizeHelp": "Максимальный размер загружаемого фото",
"maxFilesPerUpload": "Макс. файлов за загрузку",
"maxFilesPerUploadHelp": "Максимальное количество фото за одну загрузку (1–{{max}}).",
"allowedFileTypes": "Допустимые типы файлов",
@@ -691,13 +693,7 @@
"enableShortGalleryUrlsHelp": "Убирает slug события из новых ссылок, сохраняя работоспособность существующих.",
"maintenanceMode": "Включить режим обслуживания",
"language": "Язык",
- "defaultLanguage": "Язык по умолчанию",
"defaultLanguageHelp": "Язык, отображаемый гостям до входа",
- "defaultWelcomeMessage": "Приветственное сообщение по умолчанию",
- "welcomeMessage": "Приветственное сообщение",
- "welcomeMessagePlaceholder": "Введите приветственное сообщение по умолчанию для писем о создании галереи",
- "welcomeMessageHelp": "Это сообщение будет включено во все письма о создании галереи, если не переопределено при создании события",
- "saveSettings": "Сохранить основные настройки",
"saveGeneralSettings": "Сохранить основные настройки",
"dateTimeFormat": "Формат даты и времени",
"dateFormat": "Формат даты",
@@ -715,7 +711,6 @@
"accountSaveSuccess": "Данные аккаунта обновлены"
},
"publicSite": {
- "tabLabel": "Публичный сайт",
"badge": "Публичная страница",
"title": "Публичная страница",
"subtitle": "Опубликуйте настроенную страницу для гостей, посещающих ваш домен.",
@@ -743,8 +738,6 @@
"htmlRequired": "Добавьте HTML-контент перед включением публичного сайта."
},
"storage": {
- "title": "Хранилище",
- "overview": "Обзор хранилища",
"totalUsed": "Всего использовано",
"archiveStorage": "Хранилище архивов",
"storageLimit": "Лимит хранилища",
@@ -756,7 +749,6 @@
"diskCapacityReported": "Ёмкость диска (отчётная)",
"diskAvailable": "Доступно",
"diskAvailableReported": "Доступно (отчётное)",
- "diskFree": "Свободно",
"diskFreeReported": "Свободно (отчётное)",
"diskMetricsUnavailable": "Метрики диска недоступны в Docker Desktop или виртуализированных средах.",
"applyRecommended": "Использовать рекомендуемое",
@@ -775,17 +767,12 @@
"capacityRequiredForAvailable": "Введите общую ёмкость перед указанием доступного места.",
"availableExceedsCapacity": "Доступное место не может превышать общую ёмкость.",
"storageUsage": "Использование хранилища",
- "storageByEvent": "Хранилище по событиям",
- "storageManagement": "Управление хранилищем",
- "storageManagementHelp": "Рассмотрите архивирование или удаление старых событий для освобождения места. Архивированные события сжаты и занимают меньше места.",
- "noEventsUsingStorage": "События, использующие хранилище, не найдены",
"unlimited": "Без ограничений"
},
"security": {
"title": "Безопасность",
"passwordSettings": "Настройки пароля",
"minPasswordLength": "Минимальная длина пароля",
- "minPasswordLengthHelp": "Минимальное количество символов для паролей галерей",
"passwordComplexity": "Сложность пароля",
"passwordComplexityHelp": "Требуемый уровень безопасности паролей галерей",
"complexitySimple": "Простой (6+ символов, любой текст)",
@@ -794,7 +781,6 @@
"complexityVeryStrong": "Очень сильный (12+ символов, все типы символов)",
"sessionAuth": "Сессия и аутентификация",
"sessionTimeout": "Таймаут сессии (минут)",
- "sessionTimeoutHelp": "Таймаут сессии администратора в минутах",
"maxLoginAttempts": "Макс. попыток входа",
"maxLoginAttemptsHelp": "Максимальное количество неудачных попыток входа с одного IP перед блокировкой",
"attemptWindowMinutes": "Окно попыток (минут)",
@@ -805,11 +791,8 @@
"recaptchaSettings": "Настройки reCAPTCHA",
"enableRecaptcha": "Включить reCAPTCHA для форм входа",
"siteKey": "Ключ сайта",
- "siteKeyHelp": "Ваш публичный ключ reCAPTCHA v2",
"secretKey": "Секретный ключ",
- "secretKeyHelp": "Ваш секретный ключ reCAPTCHA v2 (храните в тайне)",
"recaptchaHelp": "Получите ключи reCAPTCHA на",
- "saveSettings": "Сохранить настройки безопасности",
"saveSecuritySettings": "Сохранить настройки безопасности"
},
"categories": {
@@ -857,11 +840,14 @@
"sendTest": "Отправить тестовое письмо",
"saved": "Настройки сохранены",
"saveError": "Не удалось сохранить настройки",
- "emailSent": "Уведомление отправлено {{count}} получателям",
"emailFailed": "Не удалось отправить уведомление",
"checkSuccess": "Уведомление отправлено о новой версии",
"checkNoAction": "Уведомление не нужно: {{reason}}",
- "checkError": "Не удалось проверить обновления"
+ "checkError": "Не удалось проверить обновления",
+ "emailSent_few": "Уведомление отправлено {{count}} получателям",
+ "emailSent_many": "Уведомление отправлено {{count}} получателям",
+ "emailSent_one": "Уведомление отправлено {{count}} получателю",
+ "emailSent_other": "Уведомление отправлено {{count}} получателям"
},
"events": {
"title": "Создание событий",
@@ -883,7 +869,13 @@
"expirationWarning": "Галереи без срока действия будут активны до ручного архивирования",
"saveSettings": "Сохранить настройки событий",
"noteTitle": "Примечание",
- "noteText": "Эти настройки влияют только на создание новых событий. Существующие события не затрагиваются. По умолчанию все поля обязательны."
+ "noteText": "Эти настройки влияют только на создание новых событий. Существующие события не затрагиваются. По умолчанию все поля обязательны.",
+ "defaultRequirePassword": "Требовать пароль по умолчанию",
+ "defaultRequirePasswordHelp": "Предварительно устанавливать флажок «Требовать пароль» при создании событий. Отключите для быстрого создания публичных галерей.",
+ "showGalleryFilterBar": "Показывать панель фильтров в галереях",
+ "showGalleryFilterBarHelp": "Отображает поиск по имени файла и элементы управления сортировкой над галереями с сеткой. Отключите для более чистого интерфейса.",
+ "enablePhoneField": "Включить поле номера телефона",
+ "enablePhoneFieldHelp": "Добавляет необязательное поле ввода номера телефона в форму события. Полезно для автоматизаций, таких как доставка в WhatsApp через n8n. Всегда необязательно, даже если включено."
},
"imageSecurity": {
"title": "Защита изображений",
@@ -1008,11 +1000,6 @@
"format": "Формат",
"fit": "Режим подгонки",
"fitHelp": "Как изображения подгоняются под размер миниатюры. «Заполнение» обрезает для заполнения, «Вписывание» вписывает в границы.",
- "fit_cover": "Заполнение (обрезка)",
- "fit_contain": "Вписывание (внутри)",
- "fit_fill": "Растягивание",
- "fit_inside": "Внутри (уменьшить)",
- "fit_outside": "Снаружи (увеличить)",
"regenerateTitle": "Перегенерация миниатюр",
"regenerateHelp": "После изменения настроек миниатюр перегенерируйте все существующие миниатюры для применения новой конфигурации. Процесс выполняется в фоновом режиме и может занять время для больших галерей.",
"regenerateButton": "Перегенерировать все миниатюры",
@@ -1031,16 +1018,60 @@
"missingDimensions": "Без размеров",
"repairButton": "Восстановить размеры",
"repairing": "Восстановление...",
- "alreadyRunning": "Восстановление уже выполняется",
- "started": "Начато восстановление {{count}} фотографий",
"noneToRepair": "У всех фотографий уже есть размеры",
"resultSuccess": "Последнее восстановление: {{success}} обновлено, {{failed}} с ошибками",
"description": "Заполнение отсутствующих ширины/высоты для фотографий, загруженных до добавления отслеживания размеров. Необходимо для макетов Masonry и Mosaic."
- }
+ },
+ "groups": {
+ "general": "Основные",
+ "display": "Отображение",
+ "privacySecurity": "Конфиденциальность и безопасность",
+ "integrations": "Интеграции",
+ "system": "Система"
+ },
+ "apiTokens": {
+ "title": "API-токены",
+ "createError": "Не удалось создать токен",
+ "revoked": "Токен отозван",
+ "subtitle": "Долгосрочные токены-носители для публичного интерфейса /api/v1 — интеграции n8n, пользовательские приложения, скрипты. Токены действуют от имени администратора, их создавшего, в рамках выбранных областей.",
+ "copyNow": "Скопируйте токен сейчас — он не будет показан повторно.",
+ "copied": "Скопировано",
+ "copyFailed": "Не удалось скопировать",
+ "name": "Название",
+ "namePlaceholder": "например, n8n production",
+ "scopes": "Области",
+ "generate": "Создать токен",
+ "scopeHint": "admin > запись > чтение. Токен только для чтения не может вносить изменения, даже если его владелец — super_admin.",
+ "existing": "Существующие токены",
+ "lastUsed": "Последнее использование",
+ "created": "Создан",
+ "status": "Статус",
+ "statusRevoked": "Отозван",
+ "statusExpired": "Истёк",
+ "statusActive": "Активен",
+ "confirmRevoke": "Отозвать этот токен? Это действие нельзя отменить.",
+ "revoke": "Отозвать",
+ "empty": "Токенов пока нет. Создайте один выше, чтобы начать."
+ },
+ "webhooks": {
+ "title": "Вебхуки",
+ "subtitle": "Отправляйте POST-уведомления на ваш URL при каждом событии — галерея опубликована, фото загружено, событие архивировано и т. д. Подписывается HMAC-SHA256 в заголовке X-PicPeak-Signature.",
+ "piiNotice": "Полезные данные event.* включают контактную информацию клиента (имя, email, телефон) и токен доступа к галерее. Указывайте вебхуки только на доверенные получатели.",
+ "copyNow": "Скопируйте секрет подписи сейчас — он не будет показан повторно.",
+ "name": "Название",
+ "url": "URL получателя",
+ "events": "Подписаться на события",
+ "filter": "Фильтр (JSON, необязательно)",
+ "template": "Шаблон (необязательно)",
+ "create": "Создать вебхук",
+ "existing": "Существующие вебхуки",
+ "empty": "Вебхуков пока нет. Создайте один выше для получения уведомлений."
+ },
+ "sectionLabel": "Раздел настроек",
+ "navAriaLabel": "Навигация по настройкам"
},
"analytics": {
"title": "Панель аналитики",
- "titleSimple": "Аналитика",
"subtitle": "Отслеживание производительности галерей и вовлечённости посетителей",
"detailedSubtitle": "Подробная аналитика на основе Umami",
"loadingAnalytics": "Загрузка аналитики...",
@@ -1068,13 +1099,10 @@
"totalPhotos": "Всего фото",
"activeEvents": "Активных событий",
"notConfigured": "Umami Analytics не настроен",
- "configureInstructions": "Для отображения данных аналитики настройте Umami в переменных среды и настройках панели администратора.",
- "noData": "Данные недоступны",
- "percentChange": "{{percent}}% по сравнению с прошлым периодом"
+ "configureInstructions": "Для отображения данных аналитики настройте Umami в переменных среды и настройках панели администратора."
},
"branding": {
"title": "Брендинг и темы",
- "titleFull": "Брендинг и кастомизация",
"subtitle": "Настройка внешнего вида галерей",
"loadingBranding": "Загрузка настроек брендинга...",
"themeAndStyle": "Тема и стиль",
@@ -1086,18 +1114,14 @@
"supportEmail": "Email поддержки",
"supportEmailHelp": "Контактный email для поддержки гостей",
"footerText": "Текст подвала",
- "footerTextHelp": "Отображается внизу галерей",
"logo": "Логотип",
- "currentLogo": "Текущий логотип",
"uploadLogo": "Загрузить логотип",
- "removeLogo": "Удалить логотип",
"logoHelp": "Рекомендуемый размер: 200x60px, PNG или JPEG",
"favicon": "Фавикон",
"currentFavicon": "Текущий фавикон",
"uploadFavicon": "Загрузить фавикон",
"removeFavicon": "Удалить фавикон",
"faviconHelp": "Формат PNG или ICO, рекомендуемый размер: 32x32px",
- "watermark": "Водяной знак",
"watermarkSettings": "Настройки водяного знака",
"enableWatermarks": "Включить водяные знаки",
"watermarkHelp": "Добавить название компании как водяной знак на скачиваемых фото",
@@ -1114,11 +1138,7 @@
"watermarkSize": "Размер водяного знака",
"theme": "Тема",
"galleryTheme": "Тема галереи",
- "themeCustomization": "Настройка темы",
- "selectPreset": "Выберите пресет темы",
"colors": "Цвета",
- "primaryColor": "Основной цвет",
- "secondaryColor": "Вторичный цвет",
"accentColor": "Акцентный цвет",
"backgroundColor": "Цвет фона",
"textColor": "Цвет текста",
@@ -1127,27 +1147,13 @@
"colorModeDark": "Тёмный",
"colorModeAuto": "Авто",
"colorModeHelp": "Авто следует системным настройкам посетителя.",
- "customCSS": "Пользовательский CSS",
"preview": "Предпросмотр",
- "previewInNewTab": "Открыть в новой вкладке",
- "reset": "Сбросить",
"saveChanges": "Сохранить изменения",
"applyLivePreview": "Применить изменения немедленно (живой предпросмотр)",
"eventSpecificThemes": "Темы конкретных событий",
"eventThemesInfo": "Эти глобальные настройки темы можно переопределить для отдельных событий при создании или редактировании.",
"themePresets": "Пресеты тем",
"galleryLayout": "Макет галереи",
- "layoutDescriptions": {
- "grid": "Классическая сетка с одинаковыми размерами фото",
- "masonry": "Pinterest-стиль с переменной высотой",
- "carousel": "Полноэкранное слайд-шоу с навигацией",
- "timeline": "Фото, упорядоченные по дате",
- "hero": "Главное изображение с сеткой ниже",
- "mosaic": "Художественный макет со смешанными размерами",
- "justified": "Строчный макет с сохранением пропорций",
- "gallery-premium": "Элегантная светлая тема с баннером и masonry (Бета)",
- "gallery-story": "Кинематографическая тёмная тема со сценами (Бета)"
- },
"layoutSettings": "Настройки макета",
"photoSpacing": "Отступы между фото",
"spacing": {
@@ -1204,16 +1210,6 @@
"xl": "XL — Самые крупные фото"
},
"thumbnailScaleHint": "Изменяет количество колонок относительно базовых колонок сетки",
- "showHeroSection": "Показывать секцию баннера",
- "showHeroSectionHint": "Отображать главное фото баннера над justified-галереей",
- "heroHeight": "Высота секции баннера",
- "heroHeightOptions": {
- "small": "Маленький (40–50%)",
- "medium": "Средний (50–70%)",
- "large": "Большой (60–80%)"
- },
- "heroOverlayOpacity": "Прозрачность наложения баннера",
- "heroOverlayHint": "Затемнить главное фото для улучшения читаемости текста",
"typographyAndStyle": "Типографика и стиль",
"bodyFont": "Шрифт текста",
"headingFont": "Шрифт заголовков",
@@ -1259,8 +1255,6 @@
},
"resetToDefault": "Сбросить до умолчания",
"applyTheme": "Применить тему",
- "customTheme": "Пользовательская тема",
- "customizeTheme": "Настроить тему",
"saveTheme": "Сохранить тему",
"previewLayout": "Предпросмотр макета",
"livePreview": "Живой предпросмотр",
@@ -1278,9 +1272,6 @@
"logoMaxHeight": "Максимальная высота (пикселей)",
"logoMaxHeightHelp": "Задайте пользовательскую максимальную высоту логотипа (20–200 пикселей)",
"logoPosition": "Положение логотипа в заголовке",
- "positionLeft": "Слева",
- "positionCenter": "По центру",
- "positionRight": "Справа",
"logoDisplayMode": "Режим отображения",
"logoOnly": "Только логотип",
"textOnly": "Только название компании",
@@ -1291,29 +1282,8 @@
"showLogoInHeroHelp": "Отображать логотип в секциях баннера (для нестандартных макетов)",
"headerStyle": "Стиль заголовка",
"headerStyleDescription": "Выберите, как выглядит заголовок галереи. Стиль заголовка не зависит от макета фото.",
- "headerStyleOptions": {
- "hero": "Изображение-баннер",
- "standard": "Стандартный заголовок",
- "banner": "Баннер",
- "minimal": "Минималистичный",
- "none": "Без заголовка"
- },
- "headerStyleDescriptions": {
- "hero": "Полноэкранное изображение с информацией о событии поверх",
- "standard": "Компактный заголовок с деталями события",
- "banner": "Стандартный заголовок с цветным баннером сверху",
- "minimal": "Компактный заголовок с основной информацией",
- "none": "Полностью скрыть заголовок"
- },
"heroDividerStyle": "Стиль разделителя",
"heroDividerDescription": "Выберите, как выглядит переход между изображением баннера и контентом галереи.",
- "dividerOptions": {
- "wave": "Волна",
- "straight": "Прямой",
- "angle": "Угол",
- "curve": "Кривая",
- "none": "Нет"
- },
"controlsStyle": "Стиль элементов управления",
"controlsStyleDescription": "Выберите, как отображаются фильтры и элементы управления галереи.",
"controlsStyleOptions": {
@@ -1327,15 +1297,43 @@
"controlsStyleHeroWarning": "Для заголовков-баннеров рекомендуется боковая панель, чтобы элементы управления не перекрывали изображение.",
"betaThumbnailWarningTitle": "Обнаружено низкое разрешение миниатюр",
"betaThumbnailWarningText": "Ваши миниатюры сейчас {{width}}×{{height}}px. Бета-темы отображают фото в большем размере и требуют минимум {{recommended}}×{{recommended}}px для хорошего качества. Увеличьте размеры миниатюр в Настройки > Миниатюры и пересоздайте их.",
- "betaThumbnailWarningLink": "Перейти к настройкам миниатюр"
+ "betaThumbnailWarningLink": "Перейти к настройкам миниатюр",
+ "logoSize": "Размер логотипа",
+ "surfaceColor": "Поверхность",
+ "elevatedColor": "Приподнятый",
+ "borderColor": "Граница",
+ "mutedTextColor": "Приглушённый текст",
+ "accentDarkColor": "Акцент (заполненный)",
+ "syncFromBranding": "Синхронизировать с брендингом",
+ "forceColorMode": "Принудительный цветовой режим",
+ "forceColorModeHelp": "Блокирует весь сайт администратора и публичный сайт в тёмном или светлом режиме. Переключатель тёмного/светлого режима скрыт при активной блокировке.",
+ "forceColorModeNone": "Не принудительно (выбор пользователя)",
+ "forceColorModeDark": "Принудительно тёмный",
+ "forceColorModeLight": "Принудительно светлый",
+ "colorGroupSurfaces": "Поверхности",
+ "colorGroupSurfacesHelp": "Нейтральные слои за вашим контентом. Фон находится дальше всего; Поверхность и Приподнятый накладываются сверху.",
+ "backgroundColorHelp": "Сама страница — фон каждой галереи, страницы администратора и страницы CMS.",
+ "surfaceColorHelp": "Карточки, боковая панель, шапка и навигация. Первый слой над фоном.",
+ "elevatedColorHelp": "Панели, парящие над карточками: заполнители изображений, строки при наведении, заголовки модальных окон, блоки кода.",
+ "borderColorHelp": "Разделители, линии сетки таблицы, контуры карточек, рамки полей ввода.",
+ "colorGroupText": "Текст",
+ "colorGroupTextHelp": "Цвета текста переднего плана. Основной — для всего, на чём читатели сосредотачиваются; Дополнительный — для вспомогательного текста.",
+ "textColorHelp": "Заголовки, основной текст, ячейки таблицы, значения полей ввода, метки навигации — основной цвет текста.",
+ "mutedTextColorHelp": "Подписи, вспомогательный текст под полями, заголовки столбцов, ссылки в подвале, даты и метаданные.",
+ "colorGroupAccent": "Акцент",
+ "colorGroupAccentHelp": "Фирменные цвета, выделяющие интерактивные элементы. Используйте яркую пару цветов — Акцент для контуров/текста, Акцент (заполненный) для кнопок.",
+ "accentColorHelp": "Ссылки, иконки, кольца фокуса, состояния наведения на основные кнопки, подчёркивание активного элемента боковой панели.",
+ "accentDarkColorHelp": "Заполненные кнопки CTA, фон активного элемента боковой панели, значки и метки. Необходим достаточный контраст для читаемого белого текста.",
+ "cssTemplate": "CSS-шаблон",
+ "cssTemplateDescription": "Выберите готовый CSS-шаблон для применения общесайтовых стилей к этой галерее. Шаблонами можно управлять в Настройки > CSS-шаблоны.",
+ "noTemplate": "Без шаблона",
+ "noTemplateDescription": "Использовать только настройки темы без CSS-шаблона",
+ "templateSlot": "Слот {{slot}}",
+ "eventCustomCSS": "Пользовательский CSS для события"
},
"admin": {
"title": "Панель администратора",
- "welcome": "Добро пожаловать, {{name}}",
"recentActivity": "Последняя активность",
- "systemStatus": "Статус системы",
- "totalEvents": "Всего событий",
- "activeGalleries": "Активных галерей",
"storageUsed": "Занято места",
"totalPhotos": "Всего фото",
"storagePercent": "{{percent}}% от лимита {{limit}}",
@@ -1345,9 +1343,6 @@
"archivedEvents": "Архивированных событий",
"systemHealth": "Состояние системы",
"health": {
- "healthy": "Здорово",
- "warning": "Предупреждение",
- "error": "Ошибка",
"checking": "Проверка..."
},
"updates": {
@@ -1360,9 +1355,7 @@
"beta": "БЕТА",
"viewReleaseNotes": "Посмотреть примечания к выпуску",
"updateAvailableShort": "Доступна v{{version}}",
- "checkForUpdates": "Проверить обновления",
"upToDate": "У вас актуальная версия",
- "lastChecked": "Последняя проверка: {{time}}",
"updateNow": "Обновить сейчас",
"updateDialog": {
"title": "Обновление PicPeak",
@@ -1376,8 +1369,6 @@
}
},
"notifications": "Уведомления",
- "viewAllNotifications": "Просмотреть все уведомления",
- "noNotifications": "Нет новых уведомлений",
"markAllRead": "Отметить все как прочитанные",
"clearAll": "Очистить все",
"close": "Закрыть",
@@ -1387,16 +1378,13 @@
"eventArchived": "Событие «{{eventName}}» архивировано",
"eventUpdated": "Событие «{{eventName}}» обновлено",
"eventDeleted": "Событие «{{eventName}}» удалено",
- "photosUploaded": "{{count}} фото загружено в «{{eventName}}»",
"photoDeleted": "Фото удалено из «{{eventName}}»",
- "photosBulkDeleted": "{{count}} фото удалено из «{{eventName}}»",
"eventExpiring": "Событие «{{eventName}}» истекает через {{days}} дней",
"eventExpired": "Событие «{{eventName}}» истекло",
"passwordChanged": "Пароль изменён пользователем {{actorName}}",
"passwordReset": "Пароль сброшен для «{{eventName}}»",
"settingsUpdated": "Обновлены настройки {{type}}",
"emailTemplateUpdated": "Обновлён email-шаблон «{{template}}»",
- "bulkDownload": "{{count}} фото скачано из «{{eventName}}»",
"storageWarning": "Использование хранилища: {{percentage}}%",
"adminLogout": "Администратор {{actorName}} вышел из системы",
"categoryCreated": "Создана категория «{{name}}» для «{{eventName}}»",
@@ -1413,29 +1401,30 @@
"archiveDeleted": "Архив удалён для «{{eventName}}»",
"archiveRestored": "Архив восстановлен для «{{eventName}}»",
"systemActivity": "Системная активность: {{type}}",
- "adminProfileUpdated": "Профиль администратора обновлён пользователем {{actorName}}"
+ "adminProfileUpdated": "Профиль администратора обновлён пользователем {{actorName}}",
+ "photosUploaded_few": "{{count}} фото загружено в «{{eventName}}»",
+ "photosUploaded_many": "{{count}} фото загружено в «{{eventName}}»",
+ "photosUploaded_one": "{{count}} фото загружено в «{{eventName}}»",
+ "photosUploaded_other": "{{count}} фото загружено в «{{eventName}}»",
+ "photosBulkDeleted_few": "{{count}} фото удалено из «{{eventName}}»",
+ "photosBulkDeleted_many": "{{count}} фото удалено из «{{eventName}}»",
+ "photosBulkDeleted_one": "{{count}} фото удалено из «{{eventName}}»",
+ "photosBulkDeleted_other": "{{count}} фото удалено из «{{eventName}}»",
+ "bulkDownload_few": "{{count}} фото скачано из «{{eventName}}»",
+ "bulkDownload_many": "{{count}} фото скачано из «{{eventName}}»",
+ "bulkDownload_one": "{{count}} фото скачано из «{{eventName}}»",
+ "bulkDownload_other": "{{count}} фото скачано из «{{eventName}}»"
},
"notificationToasts": {
"markedAllRead": "Все уведомления отмечены как прочитанные",
- "clearedAll": "Удалено {{count}} уведомлений",
- "profileUpdated": "Профиль администратора обновлён"
+ "clearedAll_few": "{{count}} уведомления удалены",
+ "clearedAll_many": "{{count}} уведомлений удалено",
+ "clearedAll_one": "{{count}} уведомление удалено",
+ "clearedAll_other": "{{count}} уведомлений удалено"
},
- "markAsRead": "Отметить как прочитанное",
- "markAllAsRead": "Отметить все как прочитанные",
- "notificationSettings": "Настройки уведомлений",
"changePassword": "Изменить пароль",
"darkMode": "Переключить на тёмную тему",
"lightMode": "Переключить на светлую тему",
- "accountSettings": {
- "title": "Аккаунт администратора",
- "description": "Обновите учётные данные для входа в PicPeak.",
- "username": "Имя пользователя",
- "usernamePlaceholder": "Администратор",
- "email": "Email",
- "emailPlaceholder": "admin@example.com",
- "updateButton": "Обновить профиль"
- },
- "profileUpdateError": "Не удалось обновить профиль администратора. Попробуйте снова.",
"loadingDashboard": "Загрузка панели управления...",
"activeEvents": "Активных событий",
"expiringSoon": "Скоро истекают",
@@ -1446,110 +1435,96 @@
"dashboardSubtitle": "Добро пожаловать! Вот что происходит с вашими галереями.",
"eventsExpiringSoon": "Скоро истекающие события",
"noEventsExpiring": "Нет событий, истекающих в ближайшие 7 дней",
- "daysLeft": "Остался {{count}} день",
- "daysLeft_plural": "Осталось {{count}} дней",
- "viewAllExpiringEvents": "Просмотреть все {{count}} истекающих события",
"noRecentActivity": "Последней активности нет",
- "viewAllActivity": "Просмотреть всю активность",
- "quickActions": "Быстрые действия",
- "viewArchives": "Просмотреть архивы",
- "analytics": "Аналитика",
- "activities": {
- "event_created": "Создано новое событие: {{eventName}}",
- "photos_uploaded": "{{count}} фото загружено в {{eventName}}",
- "event_archived": "Событие архивировано: {{eventName}}",
- "archive_restored": "Архив восстановлен: {{eventName}}",
- "archive_deleted": "Архив удалён: {{eventName}}",
- "archive_downloaded": "Архив скачан: {{eventName}}",
- "email_config_updated": "Конфигурация email обновлена",
- "email_template_updated": "Шаблон email обновлён: {{template}}",
- "branding_updated": "Настройки брендинга обновлены",
- "theme_updated": "Настройки темы обновлены",
- "bulk_download": "{{count}} фото скачано из {{eventName}}",
- "gallery_password_entry": "Введён пароль для {{eventName}}",
- "expiration_warning_viewed": "Просмотрено предупреждение об истечении для {{eventName}}",
- "feedback_settings_updated": "Настройки отзывов обновлены",
- "feedback_moderated": "Отзыв отмодерирован",
- "feedback_deleted": "Отзыв удалён",
- "photo_like": "Фото отмечено «нравится» в {{eventName}}",
- "photo_favorite": "Фото добавлено в избранное в {{eventName}}",
- "photo_rating": "Фото оценено в {{eventName}}",
- "photo_comment": "Комментарий к фото в {{eventName}}",
- "guest_feedback_like": "Гость отметил фото «нравится» в {{eventName}}",
- "guest_feedback_favorite": "Гость добавил фото в избранное в {{eventName}}",
- "guest_feedback_rating": "Гость оценил фото в {{eventName}}",
- "guest_feedback_comment": "Гость прокомментировал фото в {{eventName}}",
- "word_filter_added": "Фильтр слова добавлен",
- "external_import_completed": "Импорт внешних медиафайлов завершён ({{imported}} импортировано, {{skipped}} пропущено)",
- "bulk_archive_completed": "Массовое архивирование завершено",
- "event_activated": "Событие активировано: {{eventName}}",
- "event_deactivated": "Событие деактивировано: {{eventName}}",
- "photo_deleted": "Фото удалено из {{eventName}}",
- "photos_bulk_deleted": "{{count}} фото удалено из {{eventName}}",
- "settings_updated": "Настройки обновлены",
- "event_updated": "Событие обновлено: {{eventName}}",
- "event_renamed": "Событие переименовано: {{eventName}}",
- "event_deleted": "Событие удалено: {{eventName}}",
- "password_changed": "Пароль изменён",
- "email_resent": "Письмо о создании отправлено повторно для: {{eventName}}",
- "category_created": "Категория создана: {{categoryName}}",
- "category_updated": "Категория обновлена: {{categoryName}}",
- "category_deleted": "Категория удалена: {{categoryName}}",
- "general_settings_updated": "Общие настройки обновлены",
- "favicon_uploaded": "Фавикон загружен",
- "analytics_settings_updated": "Настройки аналитики обновлены",
- "cms_page_updated": "Страница CMS обновлена: {{page}}",
- "security_settings_updated": "Настройки безопасности обновлены",
- "password_reset": "Пароль сброшен для: {{eventName}}",
- "admin_logout": "Администратор {{actorName}} вышел из системы",
- "system_activity": "Системная активность: {{type}}",
- "unknown": "Неизвестная активность"
- },
- "userManagement": "Управление пользователями",
- "inviteUser": "Пригласить пользователя",
- "pendingInvitations": "Ожидающие приглашения",
- "roles": {
- "super_admin": "Супер-администратор",
- "admin": "Администратор",
- "editor": "Редактор",
- "viewer": "Наблюдатель"
- },
- "userStatus": {
- "active": "Активный",
- "inactive": "Неактивный"
- },
- "inviteForm": {
- "email": "Адрес электронной почты",
- "role": "Роль",
- "send": "Отправить приглашение"
- },
- "acceptInvite": {
- "title": "Принять приглашение администратора",
- "username": "Выберите имя пользователя",
- "password": "Создайте пароль",
- "submit": "Создать аккаунт"
- },
"photos": {
"hidden": "Скрыто",
"hideSelected": "Скрыть",
"showSelected": "Показать",
"hiddenSuccess": "Фотографии скрыты от гостей",
- "visibleSuccess": "Фотографии теперь видны гостям"
+ "visibleSuccess": "Фотографии теперь видны гостям",
+ "processingStatus": "Обработка…",
+ "processingFailed": "Ошибка",
+ "retryQueued": "Повтор в очереди"
+ },
+ "events": {
+ "tabs": {
+ "guests": "Гости"
+ }
+ },
+ "daysLeft_few": "{{count}} дня осталось",
+ "daysLeft_many": "{{count}} дней осталось",
+ "daysLeft_one": "{{count}} день остался",
+ "daysLeft_other": "{{count}} дней осталось",
+ "viewAllExpiringEvents_few": "Посмотреть все {{count}} истекающих события",
+ "viewAllExpiringEvents_many": "Посмотреть все {{count}} истекающих событий",
+ "viewAllExpiringEvents_one": "Посмотреть {{count}} истекающее событие",
+ "viewAllExpiringEvents_other": "Посмотреть все {{count}} истекающих событий",
+ "guests": {
+ "loading": "Загрузка…",
+ "aggregate": {
+ "empty": "Гости ещё ничего не выбрали.",
+ "description": "Фотографии, отсортированные по количеству гостей, которым они понравились или которые добавили их в избранное."
+ },
+ "inviteCreated": "Приглашение создано",
+ "inviteCreateError": "Не удалось создать приглашение",
+ "inviteRevoked": "Приглашение отозвано",
+ "inviteRevokeError": "Не удалось отозвать приглашение",
+ "invitesTitle": "Приглашения гостей",
+ "createInvite": "Создать приглашение",
+ "inviteName": "Имя гостя",
+ "inviteEmail": "Электронная почта (необязательно)",
+ "generateInvite": "Создать ссылку-приглашение",
+ "existingInvites": "Существующие приглашения",
+ "noInvites": "Приглашений пока нет",
+ "copyLink": "Копировать ссылку",
+ "revokeInvite": "Отозвать",
+ "deletedToast": "Гость удалён",
+ "deletedError": "Не удалось удалить гостя",
+ "mergedToast": "Гости объединены",
+ "mergedError": "Не удалось объединить гостей",
+ "forgetGuestConfirm": "Удалить этого гостя? Их выборки будут анонимизированы, но сохранены в общих итогах.",
+ "exportError": "Экспорт не удался",
+ "mergeSelectAtLeastTwo": "Выберите не менее 2 гостей для объединения",
+ "mergeConfirm_few": "Объединить {{count}} гостей с {{name}}? Это действие нельзя отменить.",
+ "mergeConfirm_many": "Объединить {{count}} гостей с {{name}}? Это действие нельзя отменить.",
+ "mergeConfirm_one": "Объединить {{count}} гостя с {{name}}? Это действие нельзя отменить.",
+ "mergeConfirm_other": "Объединить {{count}} гостей с {{name}}? Это действие нельзя отменить.",
+ "backToList": "Вернуться к списку",
+ "title": "Гости",
+ "mergeSelected_few": "Выбрано {{count}}",
+ "mergeSelected_many": "Выбрано {{count}}",
+ "mergeSelected_one": "Выбрано {{count}}",
+ "mergeSelected_other": "Выбрано {{count}}",
+ "mergeNow": "Объединить выбранных",
+ "aggregateView": "По популярности",
+ "mergeMode": "Объединить",
+ "exportAll": "Экспортировать всё",
+ "empty": "Гостей пока нет.",
+ "columns": {
+ "name": "Имя",
+ "email": "Электронная почта",
+ "likes": "Лайки",
+ "favorites": "Избранное",
+ "comments": "Комментарии",
+ "ratings": "Оценки",
+ "lastSeen": "Последний визит"
+ },
+ "view": "Подробнее",
+ "export": "Экспортировать",
+ "forgetGuest": "Удалить гостя",
+ "loadingDetail": "Загрузка выборок…",
+ "detail": {
+ "noComments": "Нет комментариев",
+ "empty": "Нет выборок в этой категории"
+ }
}
},
- "permissions": {
- "insufficient": "У вас нет прав для выполнения этого действия",
- "viewOnly": "Только просмотр"
- },
"acceptInvitation": {
"title": "Принять приглашение",
"subtitle": "Создайте аккаунт администратора",
"validating": "Проверка приглашения...",
"invalidToken": "Недействительное приглашение",
"invalidTokenMessage": "Ссылка-приглашение недействительна или устарела. Обратитесь к администратору за новым приглашением.",
- "expiredToken": "Приглашение истекло",
- "expiredTokenMessage": "Это приглашение истекло. Запросите новое у вашего администратора.",
- "alreadyUsed": "Приглашение уже использовано",
"alreadyUsedMessage": "Это приглашение уже было использовано для создания аккаунта.",
"invitedAs": "Вы приглашены как",
"expiresAt": "Приглашение истекает",
@@ -1576,7 +1551,6 @@
"strong": "Надёжный"
},
"createAccount": "Создать аккаунт",
- "creating": "Создание аккаунта...",
"success": "Аккаунт создан!",
"successMessage": "Ваш аккаунт успешно создан. Теперь вы можете войти с вашими учётными данными.",
"redirecting": "Перенаправление на страницу входа через {{seconds}}...",
@@ -1591,23 +1565,14 @@
"usernameTooLong": "Имя пользователя должно содержать не более 50 символов",
"usernameInvalid": "Имя пользователя может содержать только буквы, цифры, подчёркивания и дефисы",
"passwordRequired": "Пароль обязателен",
- "passwordTooShort": "Пароль должен содержать не менее 12 символов",
"passwordsDoNotMatch": "Пароли не совпадают",
"confirmPasswordRequired": "Подтвердите пароль",
- "usernameTaken": "Это имя пользователя уже занято",
- "emailTaken": "Аккаунт с таким email уже существует",
"genericError": "Не удалось создать аккаунт. Попробуйте снова."
}
},
"errors": {
- "notFound": "Не найдено",
"galleryNotFound": "Галерея не найдена",
"galleryNotFoundMessage": "Эта галерея не существует или была удалена.",
- "galleryArchived": "Галерея архивирована",
- "galleryArchivedMessage": "Эта галерея была архивирована и больше недоступна. Свяжитесь с организатором события, если вам нужен доступ к фотографиям.",
- "unauthorized": "Нет доступа",
- "forbidden": "Запрещено",
- "serverError": "Ошибка сервера",
"somethingWentWrong": "Что-то пошло не так",
"tryAgainLater": "Попробуйте позже",
"refreshPage": "Обновить страницу",
@@ -1617,10 +1582,9 @@
"errorDetails": "Детали ошибки",
"requiredFields": "Заполните все обязательные поля",
"enterTestEmail": "Введите тестовый адрес электронной почты",
- "failedToCreateEvent": "Не удалось создать событие",
"eventCreationFailed": "Не удалось создать событие",
- "networkError": "Ошибка сети. Проверьте соединение и попробуйте снова.",
- "sessionExpired": "Сессия истекла. Пожалуйста, войдите снова."
+ "noShareLink": "Ссылка для совместного доступа недоступна",
+ "copyFailed": "Не удалось скопировать ссылку"
},
"validation": {
"eventNameRequired": "Название события обязательно",
@@ -1631,14 +1595,15 @@
"passwordRequired": "Пароль обязателен",
"passwordMinLength": "Пароль должен содержать не менее 6 символов",
"passwordsDoNotMatch": "Пароли не совпадают",
- "passwordSecurityRequirements": "Пароль не соответствует требованиям безопасности",
- "expirationRange": "Срок действия должен быть от 1 до 365 дней"
+ "expirationRange": "Срок действия должен быть от 1 до 365 дней",
+ "required": "Это поле обязательно",
+ "expirationRequired": "Дата истечения обязательна.",
+ "eventDateRequired": "Дата события обязательна",
+ "passwordTooSimple": "Пароль не может состоять только из цифр. Используйте формат даты, например «04.07.2025»"
},
"legal": {
"impressum": "Правовая информация",
- "datenschutz": "Политика конфиденциальности",
- "termsOfService": "Условия использования",
- "cookiePolicy": "Политика использования cookie"
+ "datenschutz": "Политика конфиденциальности"
},
"toast": {
"saveSuccess": "Изменения успешно сохранены",
@@ -1647,9 +1612,6 @@
"deleteError": "Не удалось удалить",
"uploadSuccess": "Загрузка успешно завершена",
"uploadError": "Ошибка загрузки",
- "loginSuccess": "Вход выполнен успешно",
- "loginError": "Ошибка входа",
- "passwordChanged": "Пароль успешно изменён",
"linkCopied": "Ссылка скопирована в буфер обмена",
"eventCreated": "Событие успешно создано",
"eventUpdated": "Событие успешно обновлено",
@@ -1657,14 +1619,10 @@
"settingsSaved": "Настройки успешно сохранены",
"themeUpdated": "Тема успешно обновлена",
"brandingUpdated": "Брендинг успешно обновлён",
- "categoryAdded": "Категория успешно добавлена",
- "categoryDeleted": "Категория успешно удалена",
"categoryUpdated": "Категория успешно обновлена",
"emailConfigSaved": "Конфигурация email успешно сохранена",
- "testEmailSent": "Тестовое письмо успешно отправлено",
- "pageUpdated": "Страница успешно обновлена",
- "archiveRestored": "Архив успешно восстановлен",
- "archiveDeleted": "Архив безвозвратно удалён"
+ "brandingThemeMissing": "Тема брендинга ещё не сохранена.",
+ "brandingPaletteSynced": "Палитра синхронизирована с брендингом."
},
"email": {
"title": "Настройка email",
@@ -1672,28 +1630,9 @@
"loadingSettings": "Загрузка настроек email...",
"smtpConfiguration": "Конфигурация SMTP",
"smtpHost": "SMTP-хост",
- "smtpHostHelp": "Имя хоста вашего почтового сервера",
- "smtpPort": "SMTP-порт",
- "smtpPortHelp": "Обычно 587 для TLS, 465 для SSL, 25 для незашифрованного",
- "smtpSecure": "Использовать SSL/TLS",
- "smtpSecureHelp": "Включите для безопасной передачи email",
- "smtpUsername": "Имя пользователя SMTP",
- "smtpUsernameHelp": "Имя пользователя вашего email-аккаунта",
- "smtpPassword": "Пароль SMTP",
- "smtpPasswordHelp": "Пароль вашего email-аккаунта",
- "fromDetails": "Данные отправителя",
"fromEmail": "Email отправителя",
- "fromEmailHelp": "Адрес электронной почты, отображаемый как отправитель",
"fromName": "Имя отправителя",
- "fromNameHelp": "Имя, отображаемое как отправитель",
- "testConfiguration": "Тестирование конфигурации",
- "testEmail": "Тестовый адрес",
- "testEmailHelp": "Отправить тестовое письмо для проверки настроек",
- "sendTestEmail": "Отправить тестовое письмо",
- "saveConfiguration": "Сохранить конфигурацию",
"emailTemplates": "Шаблоны email",
- "templateVariables": "Доступные переменные",
- "previewTemplate": "Предпросмотр шаблона",
"smtpSettings": "Настройки SMTP",
"testEmailSuccess": "Тестовое письмо успешно отправлено",
"saveSmtpSettings": "Сохранить настройки SMTP",
@@ -1711,23 +1650,18 @@
"emailBody": "Тело письма",
"preview": "Предпросмотр",
"save": "Сохранить",
- "saveChanges": "Сохранить изменения",
"templates": "Шаблоны",
- "variableHelp": "Используйте эти переменные в шаблоне. Они будут заменены реальными значениями при отправке писем.",
"port": "Порт",
"security": "Безопасность",
"username": "Имя пользователя",
"password": "Пароль",
"enterPassword": "Введите пароль",
- "required": "обязательно",
"ignoreSslErrors": "Игнорировать ошибки SSL/TLS-сертификата",
"ignoreSslWarning": "Предупреждение: Отключение проверки сертификата делает соединение уязвимым для атак «человек посередине». Включайте только если доверяете SMTP-серверу и понимаете риски.",
"brandingTitle": "Оформление писем",
"brandingDescription": "Настройте цвета в шаблонах писем. Изменения применяются к шапке, кнопкам, ссылкам и фону подвала.",
"primaryColor": "Основной цвет",
- "primaryColorHint": "Используется для шапки, кнопок и ссылок",
"secondaryColor": "Фон подвала",
- "secondaryColorHint": "Используется для фона подвала письма",
"saveEmailColors": "Сохранить цвета",
"editor": {
"bold": "Жирный",
@@ -1753,7 +1687,23 @@
"copiedFromLanguage": "Содержимое скопировано из {{language}}",
"noTranslation": "Перевод отсутствует",
"noTranslationYet": "Перевод для этого языка ещё не существует. Скопируйте из существующего языка:",
- "copyFrom": "Копировать из"
+ "copyFrom": "Копировать из",
+ "syncedFromBranding": "Цвета писем синхронизированы с брендингом. Нажмите «Сохранить» для применения.",
+ "syncFromBranding": "Синхронизировать с брендингом",
+ "primaryColorHelp": "Шапка, заголовки H2, фон кнопок, цвет ссылок. Соответствует Брендинг → Акцент (заполненный).",
+ "secondaryColorHelp": "Фон полосы подвала. Соответствует Брендинг → Поверхность.",
+ "bodyBgColor": "Фон страницы",
+ "bodyBgColorHelp": "Обёртка вокруг карточки письма — то, что получатель видит за письмом. Соответствует Брендинг → Фон.",
+ "containerBgColor": "Карточка письма",
+ "containerBgColorHelp": "Белая карточка, содержащая содержимое письма. Соответствует Брендинг → Поверхность.",
+ "listBgColor": "Информационная панель",
+ "listBgColorHelp": "Фон маркированных информационных панелей в теле письма. Соответствует Брендинг → Приподнятый.",
+ "bodyTextColor": "Основной текст",
+ "bodyTextColorHelp": "Цвет абзацев и жирного текста. Соответствует Брендинг → Основной текст.",
+ "mutedTextColor": "Текст подвала",
+ "mutedTextColorHelp": "Текст подвала и строка авторского права. Соответствует Брендинг → Дополнительный текст.",
+ "buttonTextColor": "Текст кнопок",
+ "buttonTextColorHelp": "Цвет текста на заполненных кнопках. Должен хорошо контрастировать с основным цветом. Обычно белый."
},
"cms": {
"title": "Страницы CMS",
@@ -1767,17 +1717,22 @@
"pageTitle": "Заголовок страницы",
"pageContent": "Содержимое страницы",
"pageTitlePlaceholder": "Введите заголовок страницы...",
- "saveChanges": "Сохранить изменения",
"lastUpdated": "Последнее обновление:",
- "impressum": "Правовая информация",
- "datenschutz": "Политика конфиденциальности",
"pageUpdated": "Страница успешно обновлена",
"useExternalUrl": "Использовать внешний URL",
"useExternalUrlHelp": "Перенаправлять посетителей на внешнюю страницу вместо показа внутреннего содержимого. Внутренний заголовок и содержимое остаются сохранёнными как резервная копия.",
"externalUrl": "Внешний URL",
"externalUrlPlaceholder": "https://example.com/impressum",
"externalUrlInvalid": "Должен быть действительный URL вида https://",
- "externalUrlActive": "Внешний URL активен — внутреннее содержимое сохранено, но не отображается посетителям."
+ "externalUrlActive": "Внешний URL активен — внутреннее содержимое сохранено, но не отображается посетителям.",
+ "logoUploaded": "Логотип загружен",
+ "logoCleared": "Логотип удалён",
+ "pageLogo": "Логотип страницы",
+ "pageLogoHelp": "Необязательно. Если задан, используется вместо глобального логотипа брендинга на этой странице.",
+ "noLogo": "без замены",
+ "replaceLogo": "Заменить логотип",
+ "uploadLogo": "Загрузить логотип",
+ "clearLogo": "Использовать стандартный сайта"
},
"eventTypes": {
"title": "Типы событий",
@@ -1828,12 +1783,6 @@
}
},
"backup": {
- "external": {
- "warning": {
- "title": "Внешние медиафайлы исключены",
- "body": "Эта установка ссылается на фото из /external-media. Оригиналы исключены из резервных копий. Миниатюры и база данных по-прежнему сохраняются."
- }
- },
"title": "Управление резервными копиями",
"subtitle": "Управление резервными копиями системы, настройка автоматического резервирования и восстановление из предыдущих копий.",
"tabs": {
@@ -1854,22 +1803,12 @@
"actions": {
"runBackupNow": "Создать копию сейчас",
"starting": "Запуск...",
- "running": "Выполняется...",
"testConnection": "Проверить подключение",
- "save": "Сохранить конфигурацию",
"delete": "Удалить",
"view": "Подробности",
- "download": "Скачать",
- "refresh": "Обновить"
+ "download": "Скачать"
},
"dashboard": {
- "backupHealth": "Состояние резервного копирования",
- "healthStatus": {
- "excellent": "Отличное",
- "good": "Хорошее",
- "warning": "Предупреждение",
- "critical": "Критическое"
- },
"health": {
"title": "Состояние резервного копирования"
},
@@ -1879,9 +1818,7 @@
"upToDate": "Резервная копия актуальна",
"recent": "Резервная копия свежая",
"gettingOld": "Резервная копия устаревает",
- "outdated": "Резервная копия устарела",
- "failed": "Последнее резервное копирование не удалось",
- "old": "Резервная копия устаревает"
+ "outdated": "Резервная копия устарела"
},
"stats": {
"totalBackups": "Всего копий",
@@ -1890,7 +1827,6 @@
"backupStatus": "Статус копии",
"last": "Последняя",
"files": "файлов",
- "minutes": "{{count}} мин.",
"active": "Активный",
"inactive": "Неактивный",
"noBackupsYet": "Копий пока нет"
@@ -1908,16 +1844,10 @@
},
"coverage": {
"title": "Охват резервного копирования",
- "database": "База данных",
- "photos": "Фото",
- "archives": "Архивы",
- "systemFiles": "Системные файлы",
"included": "Включено",
- "excluded": "Исключено",
- "optional": "Необязательно"
+ "excluded": "Исключено"
},
"storageDestination": "Место хранения",
- "nextScheduledBackup": "Следующее запланированное копирование",
"backupType": "Резервная копия {{type}}",
"noDestinationSet": "Место хранения не задано"
},
@@ -1944,42 +1874,24 @@
"destinationPathHelp": "Путь к локальной директории для хранения копий",
"destinationPathPlaceholder": "/path/to/backup/directory",
"rsyncHost": "Удалённый хост",
- "rsyncHostHelp": "Имя хоста или IP-адрес SSH",
"rsyncHostPlaceholder": "backup.example.com",
"rsyncUser": "Пользователь SSH",
- "rsyncUserHelp": "Имя пользователя для SSH-подключения",
"rsyncUserPlaceholder": "backup-user",
"rsyncPath": "Удалённый путь",
- "rsyncPathHelp": "Путь к директории на удалённом сервере",
"rsyncPathPlaceholder": "/home/backup/photo-sharing",
"rsyncSshKey": "Приватный ключ SSH",
"rsyncSshKeyHelp": "Приватный ключ SSH для аутентификации (необязательно)",
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
"s3Endpoint": "Эндпоинт S3",
"s3EndpointHelp": "Эндпоинт API S3 (например, s3.amazonaws.com)",
- "s3EndpointPlaceholder": "https://s3.amazonaws.com",
"s3Bucket": "Имя корзины",
- "s3BucketHelp": "Корзина S3 для хранения копий",
- "s3BucketPlaceholder": "my-backup-bucket",
"s3AccessKey": "ID ключа доступа",
- "s3AccessKeyHelp": "ID ключа доступа AWS/S3",
- "s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXAMPLE",
"s3SecretKey": "Секретный ключ доступа",
- "s3SecretKeyHelp": "Секретный ключ доступа AWS/S3",
- "s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
- "s3Region": "Регион",
- "s3RegionHelp": "Регион S3 (например, us-east-1)",
- "s3RegionPlaceholder": "us-east-1"
+ "s3Region": "Регион"
},
"schedule": {
"title": "Расписание резервного копирования",
"scheduleType": "Тип расписания",
- "scheduleOptions": {
- "hourly": "Каждый час",
- "daily": "Ежедневно",
- "weekly": "Еженедельно",
- "custom": "Пользовательское cron-выражение"
- },
"options": {
"hourly": "Каждый час",
"daily": "Ежедневно",
@@ -2001,9 +1913,7 @@
"archives": "Архивы",
"archivesHelp": "ZIP-файлы архивированных событий",
"thumbnails": "Миниатюры",
- "thumbnailsHelp": "Сгенерированные миниатюры (можно пересоздать)",
- "tempFiles": "Временные файлы",
- "tempFilesHelp": "Временные файлы загрузки и обработки"
+ "thumbnailsHelp": "Сгенерированные миниатюры (можно пересоздать)"
},
"advancedOptions": {
"title": "Расширенные параметры",
@@ -2012,15 +1922,7 @@
"encryption": "Включить шифрование",
"encryptionHelp": "Шифровать копии для дополнительной безопасности",
"encryptionPassphrase": "Парольная фраза шифрования",
- "encryptionPassphraseHelp": "Надёжная парольная фраза для шифрования копий",
- "confirmPassphrase": "Подтвердить парольную фразу",
- "passphrasesDontMatch": "Парольные фразы не совпадают"
- },
- "validation": {
- "requiredFields": "Заполните все обязательные поля",
- "invalidCron": "Неверное cron-выражение",
- "connectionTestFailed": "Тест подключения не пройден",
- "connectionTestSuccess": "Тест подключения успешен!"
+ "encryptionPassphraseHelp": "Надёжная парольная фраза для шифрования копий"
},
"messages": {
"requiredFields": "Заполните все обязательные поля",
@@ -2033,23 +1935,6 @@
},
"history": {
"searchPlaceholder": "Поиск копий...",
- "allStatus": "Все статусы",
- "status": {
- "completed": "Завершено",
- "failed": "Ошибка",
- "running": "Выполняется",
- "partial": "Частично"
- },
- "deleteConfirm": "Вы уверены, что хотите удалить резервную копию от {{date}}?",
- "noBackups": "Резервные копии не найдены",
- "tableHeaders": {
- "date": "Дата",
- "type": "Тип",
- "status": "Статус",
- "size": "Размер",
- "duration": "Длительность",
- "actions": "Действия"
- },
"columns": {
"status": "Статус",
"dateTime": "Дата и время",
@@ -2058,36 +1943,11 @@
"duration": "Длительность",
"actions": "Действия"
},
- "statistics": "Статистика",
- "errors": "Ошибки",
- "backupDetails": {
- "backupId": "ID копии",
- "startTime": "Время начала",
- "endTime": "Время окончания",
- "destination": "Назначение",
- "filesProcessed": "Обработано файлов",
- "totalSize": "Общий размер",
- "compressionRatio": "Коэффициент сжатия",
- "errorLog": "Журнал ошибок",
- "noErrors": "Ошибок не возникло"
- },
"pagination": {
"showing": "Показано {{from}}–{{to}} из {{total}} копий",
"previous": "Назад",
"next": "Далее"
},
- "filter": {
- "allStatus": "Все статусы",
- "completed": "Завершено",
- "failed": "Ошибка",
- "running": "Выполняется",
- "partial": "Частично"
- },
- "noBackupsFound": "Резервные копии не найдены",
- "backupsWillAppear": "Копии появятся здесь после создания",
- "messages": {
- "deleteSuccess": "Резервная копия успешно удалена"
- },
"details": {
"backupDetails": "Подробности резервной копии",
"destination": "Место назначения",
@@ -2208,12 +2068,6 @@
"current": "Текущий",
"statusDetails": "Детали статуса",
"restoreLogs": "Журналы восстановления",
- "steps": {
- "completed": "Завершено",
- "running": "Выполняется",
- "failed": "Ошибка",
- "pending": "Ожидание"
- },
"success": {
"title": "Восстановление успешно завершено",
"message": "Ваши данные восстановлены. Пожалуйста, убедитесь, что всё работает корректно."
@@ -2226,20 +2080,13 @@
"starting": "Запуск...",
"validating": "Проверка...",
"startNewRestore": "Начать новое восстановление"
- },
- "messages": {
- "restoreStarted": "Восстановление успешно запущено"
}
},
"messages": {
"backupStarted": "Резервное копирование успешно запущено",
"backupFailed": "Не удалось запустить резервное копирование",
"configUpdated": "Конфигурация резервного копирования обновлена",
- "configUpdateFailed": "Не удалось обновить конфигурацию",
- "backupDeleted": "Резервная копия успешно удалена",
- "deleteFailed": "Не удалось удалить резервную копию",
- "testEmailSent": "Тест подключения успешен!",
- "testEmailFailed": "Тест подключения не пройден"
+ "configUpdateFailed": "Не удалось обновить конфигурацию"
}
},
"cssTemplates": {
@@ -2266,8 +2113,6 @@
"maintenance": {
"title": "Техническое обслуживание",
"message": "В данный момент проводится плановое техническое обслуживание для улучшения нашего сервиса. Мы скоро вернёмся.",
- "expectedCompletion": "Ожидаемое время завершения:",
- "checkBackLater": "Пожалуйста, зайдите позже",
"urgentMatters": "По срочным вопросам обращайтесь"
},
"passwordChange": {
@@ -2346,18 +2191,7 @@
"pendingApproval": "Ожидает одобрения",
"noComments": "Комментариев пока нет. Будьте первым!",
"rating": "Рейтинг",
- "ratePhoto": "Оценить это фото",
- "yourRating": "Ваша оценка",
- "averageRating": "Средняя оценка",
- "totalRatings": "оценок",
"likes": "Нравится",
- "favorites": "Избранное",
- "likePhoto": "Отметить «нравится»",
- "favoritePhoto": "Добавить в избранное",
- "photoFeedback": "Отзыв о фото",
- "hasFeedback": "Есть отзыв",
- "hasComments": "Есть комментарии",
- "hasRating": "Есть оценка",
"settings": {
"title": "Настройки отзывов гостей",
"enableFeedback": "Включить отзывы",
@@ -2369,25 +2203,118 @@
"comments": "Комментарии",
"commentsDesc": "Текстовые комментарии к фото",
"favorites": "Избранное",
- "favoritesDesc": "Отмечать фото как избранные"
- }
+ "favoritesDesc": "Отмечать фото как избранные",
+ "identityMode": "Режим идентификации",
+ "identityModeSimple": "Простые отзывы",
+ "identityModeSimpleDesc": "Анонимно, на основе устройства. Все посетители на одном устройстве используют общее состояние.",
+ "identityModeGuest": "Выборки по гостям",
+ "identityModeGuestDesc": "Каждый посетитель вводит своё имя. Включает отслеживание по гостям и аналитику для администратора.",
+ "privacyModeration": "Конфиденциальность и модерация",
+ "requireInfo": "Требовать имя и email",
+ "requireInfoDesc": "Гости должны указать имя и email для оставления отзывов",
+ "moderateComments": "Модерировать комментарии",
+ "moderateCommentsDesc": "Комментарии требуют одобрения перед публикацией",
+ "showToGuests": "Показывать отзывы гостям",
+ "showToGuestsDesc": "Другие гости могут видеть оценки, лайки и одобренные комментарии",
+ "enableRateLimiting": "Включить ограничение частоты",
+ "rateLimitingDesc": "Предотвращает спам, ограничивая частоту отзывов",
+ "timeWindow": "Временное окно (минуты)",
+ "maxRequests": "Макс. запросов"
+ },
+ "settingsUpdated": "Настройки отзывов обновлены",
+ "settingsUpdateError": "Не удалось обновить настройки",
+ "moderated": "Отзыв прошёл модерацию",
+ "deleted": "Отзыв удалён",
+ "exported": "Отзывы экспортированы",
+ "exportError": "Не удалось экспортировать отзывы",
+ "title": "Управление отзывами",
+ "exportCSV": "Экспорт CSV",
+ "exportJSON": "Экспорт JSON",
+ "tabs": {
+ "settings": "Настройки",
+ "feedback": "Отзывы",
+ "analytics": "Аналитика",
+ "moderation": "Модерация"
+ },
+ "allTypes": "Все типы",
+ "types": {
+ "rating": "Оценки",
+ "like": "Лайки",
+ "comment": "Комментарии",
+ "favorite": "Избранное"
+ },
+ "allStatuses": "Все статусы",
+ "status": {
+ "pending": "Ожидает",
+ "approved": "Одобрен",
+ "hidden": "Скрыт"
+ },
+ "noFeedback": "Отзывы не найдены",
+ "approve": "Одобрить",
+ "hide": "Скрыть",
+ "unhide": "Показать",
+ "confirmDelete": "Вы уверены, что хотите удалить этот отзыв?",
+ "avgRating": "Средняя оценка",
+ "totalRatings_few": "{{count}} оценки",
+ "totalRatings_many": "{{count}} оценок",
+ "totalRatings_one": "{{count}} оценка",
+ "totalRatings_other": "{{count}} оценок",
+ "totalLikes": "Всего лайков",
+ "totalComments": "Всего комментариев",
+ "pendingModeration_few": "{{count}} на проверке",
+ "pendingModeration_many": "{{count}} на проверке",
+ "pendingModeration_one": "{{count}} на проверке",
+ "pendingModeration_other": "{{count}} на проверке",
+ "totalInteractions": "Всего взаимодействий",
+ "topRated": "Фото с высшей оценкой",
+ "recentComments": "Последние комментарии",
+ "wordFilters": "Фильтры слов",
+ "wordFiltersDesc": "Управление заблокированными словами для модерации комментариев",
+ "manageFilters": "Управление фильтрами слов",
+ "manage": "Управление отзывами",
+ "ratingSubmitted": "Оценка отправлена",
+ "ratingError": "Не удалось отправить оценку",
+ "rateStar_few": "Оценить {{count}} звезды",
+ "rateStar_many": "Оценить {{count}} звёзд",
+ "rateStar_one": "Оценить {{count}} звезду",
+ "rateStar_other": "Оценить {{count}} звёзд",
+ "ratingsCount_few": "{{count}} оценки",
+ "ratingsCount_many": "{{count}} оценок",
+ "ratingsCount_one": "{{count}} оценка",
+ "ratingsCount_other": "{{count}} оценок",
+ "likeError": "Не удалось обновить лайк",
+ "unlike": "Убрать лайк",
+ "like": "Лайк",
+ "favoriteError": "Не удалось обновить избранное",
+ "unfavorite": "Убрать из избранного",
+ "favorite": "Добавить в избранное",
+ "invalidEmail": "Неверный адрес электронной почты",
+ "identityRequired": "Требуется ваша информация",
+ "identityReason": "Укажите имя и email для отправки {{type}}.",
+ "namePlaceholder": "Введите ваше имя",
+ "emailPlaceholder": "Введите ваш email",
+ "submitFeedback": "Отправить отзыв",
+ "moderationSuccess": "Отзыв успешно промодерирован",
+ "pendingModeration": "На модерации",
+ "pending": "ожидает",
+ "noPendingComments": "Нет комментариев, ожидающих модерации",
+ "onPhoto": "На фото",
+ "showAll_few": "Показать все {{count}} ожидающих комментария",
+ "showAll_many": "Показать все {{count}} ожидающих комментариев",
+ "showAll_one": "Показать {{count}} ожидающий комментарий",
+ "showAll_other": "Показать все {{count}} ожидающих комментариев",
+ "viewAllFeedback": "Просмотреть все отзывы и настройки"
},
"filter": {
"feedbackFilters": "Фильтры отзывов",
"clear": "Очистить",
"rating": "Рейтинг",
- "allPhotos": "Все фото",
- "anyRating": "Любой рейтинг",
- "oneStarPlus": "1+ звезда",
- "twoStarsPlus": "2+ звезды",
- "threeStarsPlus": "3+ звезды",
- "fourStarsPlus": "4+ звезды",
- "fiveStarsOnly": "Только 5 звёзд",
"hasLikes": "Есть лайки",
"hasFavorites": "Есть в избранном",
"hasComments": "Есть комментарии",
"showingPhotos": "Всего фото",
- "withRatings": "С оценками"
+ "withRatings": "С оценками",
+ "combineWith": "Объединить с"
},
"adminLogin": {
"title": "Вход для администратора",
@@ -2402,7 +2329,6 @@
"passwordRequired": "Пароль обязателен",
"passwordMinLength": "Пароль должен содержать не менее 6 символов",
"rememberMe": "Запомнить меня",
- "forgotPassword": "Забыли пароль?",
"signIn": "Войти",
"loginSuccess": "Вход выполнен успешно!",
"networkError": "Ошибка сети. Проверьте подключение и попробуйте снова.",
@@ -2442,9 +2368,12 @@
"button": "Экспорт",
"success": "Экспорт успешно загружен",
"error": "Ошибка экспорта: ",
- "exportSelected": "Экспортировать {{count}} выбранных",
"exportFiltered": "Экспортировать отфильтрованные фото",
- "hint": "Выберите фото или примените фильтры для экспорта"
+ "hint": "Выберите фото или примените фильтры для экспорта",
+ "exportSelected_few": "Экспортировать {{count}} выбранных",
+ "exportSelected_many": "Экспортировать {{count}} выбранных",
+ "exportSelected_one": "Экспортировать {{count}} выбранный",
+ "exportSelected_other": "Экспортировать {{count}} выбранных"
},
"photoSort": {
"defaultSort": "Сортировка фото по умолчанию",
@@ -2455,5 +2384,21 @@
"filenameAZ": "Имя файла (А-Я)",
"filenameZA": "Имя файла (Я-А)",
"dateTaken": "Дата съёмки"
+ },
+ "photos": {
+ "moveToCategory_few": "Переместить {{count}} фото в категорию",
+ "moveToCategory_many": "Переместить {{count}} фото в категорию",
+ "moveToCategory_one": "Переместить {{count}} фото в категорию",
+ "moveToCategory_other": "Переместить {{count}} фото в категорию",
+ "selectCategory": "Выбрать категорию",
+ "uncategorized": "Без категории",
+ "movePhotos": "Переместить фото",
+ "selectedCategory": "выбранная категория",
+ "movedToCategory_few": "{{count}} фото перемещено в {{category}}",
+ "movedToCategory_many": "{{count}} фото перемещено в {{category}}",
+ "movedToCategory_one": "{{count}} фото перемещено в {{category}}",
+ "movedToCategory_other": "{{count}} фото перемещено в {{category}}",
+ "moveToCategoryFailed": "Не удалось переместить фото в категорию",
+ "moveToCategory": "Переместить в категорию"
}
}
From e7228b07805a40aa67ccb7e3592848218eabbca2 Mon Sep 17 00:00:00 2001
From: PiR1
Date: Fri, 8 May 2026 20:07:41 +0200
Subject: [PATCH 017/169] feat(localization): add i18next extraction helper &
refactor backup configuration component to tsx
---
frontend/i18next.config.ts | 5 +-
frontend/package-lock.json | 540 ++++++++++++
frontend/package.json | 2 +
frontend/scripts/i18nextExtractionHelper.ts | 251 ++++++
.../src/components/admin/AdminSidebar.tsx | 13 +-
.../components/admin/BackupConfiguration.d.ts | 3 -
...figuration.jsx => BackupConfiguration.tsx} | 84 +-
.../src/components/admin/BackupDashboard.d.ts | 3 -
...ackupDashboard.jsx => BackupDashboard.tsx} | 102 ++-
.../src/components/admin/PhotoFilterPanel.tsx | 2 +-
frontend/src/i18n/locales/de.json | 829 ++++++++++--------
frontend/src/i18n/locales/en.json | 125 ++-
frontend/src/i18n/locales/fr.json | 127 ++-
frontend/src/i18n/locales/nl.json | 127 ++-
frontend/src/i18n/locales/pt.json | 127 ++-
frontend/src/i18n/locales/ru.json | 127 ++-
frontend/src/pages/admin/AdminDashboard.tsx | 13 +-
.../src/pages/admin/BackupManagement.d.ts | 3 -
...kupManagement.jsx => BackupManagement.tsx} | 74 +-
frontend/src/services/admin.service.ts | 53 +-
20 files changed, 2093 insertions(+), 517 deletions(-)
create mode 100644 frontend/scripts/i18nextExtractionHelper.ts
delete mode 100644 frontend/src/components/admin/BackupConfiguration.d.ts
rename frontend/src/components/admin/{BackupConfiguration.jsx => BackupConfiguration.tsx} (94%)
delete mode 100644 frontend/src/components/admin/BackupDashboard.d.ts
rename frontend/src/components/admin/{BackupDashboard.jsx => BackupDashboard.tsx} (88%)
delete mode 100644 frontend/src/pages/admin/BackupManagement.d.ts
rename frontend/src/pages/admin/{BackupManagement.jsx => BackupManagement.tsx} (85%)
diff --git a/frontend/i18next.config.ts b/frontend/i18next.config.ts
index 38c090be..70080284 100644
--- a/frontend/i18next.config.ts
+++ b/frontend/i18next.config.ts
@@ -1,4 +1,6 @@
import { defineConfig } from 'i18next-cli';
+import { typescriptPlugin } from "./scripts/i18nextExtractionHelper";
+
export default defineConfig({
locales: ['en', 'de', 'nl', 'pt', 'ru', 'fr'],
@@ -18,6 +20,7 @@ export default defineConfig({
preserveContextVariants: true,
indentation: 2,
- sort:false
+ sort: false,
},
+ plugins: [typescriptPlugin(["./src/App.tsx"]) ]
});
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 57f7f305..997cbd90 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -53,6 +53,7 @@
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.6.1",
+ "@types/node": "^25.6.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.5.3",
@@ -64,6 +65,7 @@
"globals": "^16.2.0",
"i18next-cli": "^1.56.11",
"jsdom": "^25.0.1",
+ "memfs": "^4.57.2",
"postcss": "^8.5.10",
"tailwindcss": "^3.3.0",
"typescript": "~5.8.3",
@@ -1618,6 +1620,436 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@jsonjoy.com/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/buffers": {
+ "version": "17.67.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz",
+ "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/codegen": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz",
+ "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-core": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.2.tgz",
+ "integrity": "sha512-SVjwklkpIV5wrynpYtuYnfYH1QF4/nDuLBX7VXdb+3miglcAgBVZb/5y0cOsehRV/9Vb+3UqhkMq3/NR3ztdkQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-node-builtins": "4.57.2",
+ "@jsonjoy.com/fs-node-utils": "4.57.2",
+ "thingies": "^2.5.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-fsa": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.2.tgz",
+ "integrity": "sha512-fhO8+iR2I+OCw668ISDJdn1aArc9zx033sWejIyzQ8RBeXa9bDSaUeA3ix0poYOfrj1KdOzytmYNv2/uLDfV6g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-core": "4.57.2",
+ "@jsonjoy.com/fs-node-builtins": "4.57.2",
+ "@jsonjoy.com/fs-node-utils": "4.57.2",
+ "thingies": "^2.5.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-node": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.2.tgz",
+ "integrity": "sha512-nX2AdL6cOFwLdju9G4/nbRnYevmCJbh7N7hvR3gGm97Cs60uEjyd0rpR+YBS7cTg175zzl22pGKXR5USaQMvKg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-core": "4.57.2",
+ "@jsonjoy.com/fs-node-builtins": "4.57.2",
+ "@jsonjoy.com/fs-node-utils": "4.57.2",
+ "@jsonjoy.com/fs-print": "4.57.2",
+ "@jsonjoy.com/fs-snapshot": "4.57.2",
+ "glob-to-regex.js": "^1.0.0",
+ "thingies": "^2.5.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-node-builtins": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.2.tgz",
+ "integrity": "sha512-xhiegylRmhw43Ki2HO1ZBL7DQ5ja/qpRsL29VtQ2xuUHiuDGbgf2uD4p9Qd8hJI5P6RCtGYD50IXHXVq/Ocjcg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-node-to-fsa": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.2.tgz",
+ "integrity": "sha512-18LmWTSONhoAPW+IWRuf8w/+zRolPFGPeGwMxlAhhfY11EKzX+5XHDBPAw67dBF5dxDErHJbl40U+3IXSDRXSQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-fsa": "4.57.2",
+ "@jsonjoy.com/fs-node-builtins": "4.57.2",
+ "@jsonjoy.com/fs-node-utils": "4.57.2"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-node-utils": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.2.tgz",
+ "integrity": "sha512-rsPSJgekz43IlNbLyAM/Ab+ouYLWGp5DDBfYBNNEqDaSpsbXfthBn29Q4muFA9L0F+Z3mKo+CWlgSCXrf+mOyQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-node-builtins": "4.57.2"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-print": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.2.tgz",
+ "integrity": "sha512-wK9NSow48i4DbDl9F1CQE5TqnyZOJ04elU3WFG5aJ76p+YxO/ulyBBQvKsessPxdo381Bc2pcEoyPujMOhcRqQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-node-utils": "4.57.2",
+ "tree-dump": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-snapshot": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.2.tgz",
+ "integrity": "sha512-GdduDZuoP5V/QCgJkx9+BZ6SC0EZ/smXAdTS7PfMqgMTGXLlt/bH/FqMYaqB9JmLf05sJPtO0XRbAwwkEEPbVw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/buffers": "^17.65.0",
+ "@jsonjoy.com/fs-node-utils": "4.57.2",
+ "@jsonjoy.com/json-pack": "^17.65.0",
+ "@jsonjoy.com/util": "^17.65.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": {
+ "version": "17.67.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz",
+ "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": {
+ "version": "17.67.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz",
+ "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": {
+ "version": "17.67.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz",
+ "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/base64": "17.67.0",
+ "@jsonjoy.com/buffers": "17.67.0",
+ "@jsonjoy.com/codegen": "17.67.0",
+ "@jsonjoy.com/json-pointer": "17.67.0",
+ "@jsonjoy.com/util": "17.67.0",
+ "hyperdyperid": "^1.2.0",
+ "thingies": "^2.5.0",
+ "tree-dump": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": {
+ "version": "17.67.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz",
+ "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/util": "17.67.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": {
+ "version": "17.67.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz",
+ "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/buffers": "17.67.0",
+ "@jsonjoy.com/codegen": "17.67.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/json-pack": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz",
+ "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/base64": "^1.1.2",
+ "@jsonjoy.com/buffers": "^1.2.0",
+ "@jsonjoy.com/codegen": "^1.0.0",
+ "@jsonjoy.com/json-pointer": "^1.0.2",
+ "@jsonjoy.com/util": "^1.9.0",
+ "hyperdyperid": "^1.2.0",
+ "thingies": "^2.5.0",
+ "tree-dump": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz",
+ "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/json-pointer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz",
+ "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/codegen": "^1.0.0",
+ "@jsonjoy.com/util": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/util": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz",
+ "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/buffers": "^1.0.0",
+ "@jsonjoy.com/codegen": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
+ "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz",
+ "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -3038,6 +3470,16 @@
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"license": "MIT"
},
+ "node_modules/@types/node": {
+ "version": "25.6.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz",
+ "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.19.0"
+ }
+ },
"node_modules/@types/prop-types": {
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
@@ -5100,6 +5542,23 @@
"node": ">=10.13.0"
}
},
+ "node_modules/glob-to-regex.js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz",
+ "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
"node_modules/glob/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
@@ -5298,6 +5757,16 @@
"node": ">=18.18.0"
}
},
+ "node_modules/hyperdyperid": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz",
+ "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.18"
+ }
+ },
"node_modules/i18next": {
"version": "25.7.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.7.3.tgz",
@@ -6190,6 +6659,36 @@
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"license": "MIT"
},
+ "node_modules/memfs": {
+ "version": "4.57.2",
+ "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.2.tgz",
+ "integrity": "sha512-2nWzSsJzrukurSDna4Z0WywuScK4Id3tSKejgu74u8KCdW4uNrseKRSIDg75C6Yw5ZRqBe0F0EtMNlTbUq8bAQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jsonjoy.com/fs-core": "4.57.2",
+ "@jsonjoy.com/fs-fsa": "4.57.2",
+ "@jsonjoy.com/fs-node": "4.57.2",
+ "@jsonjoy.com/fs-node-builtins": "4.57.2",
+ "@jsonjoy.com/fs-node-to-fsa": "4.57.2",
+ "@jsonjoy.com/fs-node-utils": "4.57.2",
+ "@jsonjoy.com/fs-print": "4.57.2",
+ "@jsonjoy.com/fs-snapshot": "4.57.2",
+ "@jsonjoy.com/json-pack": "^1.11.0",
+ "@jsonjoy.com/util": "^1.9.0",
+ "glob-to-regex.js": "^1.0.1",
+ "thingies": "^2.5.0",
+ "tree-dump": "^1.0.3",
+ "tslib": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -8003,6 +8502,23 @@
"node": ">=0.8"
}
},
+ "node_modules/thingies": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz",
+ "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "^2"
+ }
+ },
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
@@ -8125,6 +8641,23 @@
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
+ "node_modules/tree-dump": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz",
+ "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/streamich"
+ },
+ "peerDependencies": {
+ "tslib": "2"
+ }
+ },
"node_modules/ts-api-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
@@ -8208,6 +8741,13 @@
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT"
},
+ "node_modules/undici-types": {
+ "version": "7.19.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
+ "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/unicorn-magic": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index bcf50c7e..7ffafb96 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -60,6 +60,7 @@
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.6.1",
+ "@types/node": "^25.6.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.5.3",
@@ -71,6 +72,7 @@
"globals": "^16.2.0",
"i18next-cli": "^1.56.11",
"jsdom": "^25.0.1",
+ "memfs": "^4.57.2",
"postcss": "^8.5.10",
"tailwindcss": "^3.3.0",
"typescript": "~5.8.3",
diff --git a/frontend/scripts/i18nextExtractionHelper.ts b/frontend/scripts/i18nextExtractionHelper.ts
new file mode 100644
index 00000000..f3c07c3c
--- /dev/null
+++ b/frontend/scripts/i18nextExtractionHelper.ts
@@ -0,0 +1,251 @@
+import type { ExtractedKey, Plugin } from 'i18next-cli'
+import * as ts from 'typescript'
+import { vol } from 'memfs'
+import * as path from 'path'
+
+// based on https://github.com/i18next/i18next-cli/blob/49188621ae5534d940c7cc86eca1e3ece99506e7/test/plugin.typescript.test.ts
+
+// --- HELPER FUNCTIONS FOR PLUGIN ---
+function isTranslationFunction (node: ts.CallExpression): boolean {
+ const expr = node.expression
+ // Matches t('...')
+ if (ts.isIdentifier(expr) && expr.text === 't') return true
+
+ // Matches i18n.t('...')
+ if (ts.isPropertyAccessExpression(expr) && expr.name.text === 't') return true
+
+ return false
+}
+
+function extractStringsFromType (type: ts.Type): string[] {
+ if (type.isStringLiteral()) {
+ return [type.value]
+ }
+ if (type.isUnion()) {
+ return type.types.flatMap(t => extractStringsFromType(t))
+ }
+ if (type.isIntersection()) {
+ return type.types.flatMap(t => extractStringsFromType(t))
+ }
+ return []
+}
+
+export function typescriptPlugin (
+ entryPoints: string[],
+ options: { defaultNS?: string } = {}
+): Plugin {
+ const defaultNS = options.defaultNS
+
+ return {
+ name: 'typescript-resolver',
+ async onEnd (keys: Map) {
+ // 1. Setup Compiler Options
+ const compilerOptions: ts.CompilerOptions = {
+ allowJs: true,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ESNext,
+ module: ts.ModuleKind.CommonJS,
+ moduleResolution: ts.ModuleResolutionKind.NodeJs,
+ esModuleInterop: true
+ }
+
+ // 2. Create a custom CompilerHost that reads from memfs (vol)
+ const host = ts.createCompilerHost(compilerOptions)
+ const originalReadFile = host.readFile
+ const originalFileExists = host.fileExists
+
+ host.readFile = (fileName: string) => {
+ if (vol.existsSync(fileName)) {
+ return vol.readFileSync(fileName, 'utf-8') as string
+ }
+ return originalReadFile(fileName)
+ }
+
+ host.fileExists = (fileName: string) => {
+ if (vol.existsSync(fileName)) return true
+ return originalFileExists(fileName)
+ }
+
+ // Override module resolution to look in memfs
+ host.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, containingSourceFile, reusedNames) => {
+ return moduleLiterals.map(moduleLiteral => {
+ const moduleName = moduleLiteral.text
+ // Simple resolution for test: resolve relative paths against the containing file's directory
+ if (moduleName.startsWith('.')) {
+ const dir = path.dirname(containingFile)
+ const candidates: [string, ts.Extension][] = [
+ [path.join(dir, moduleName + '.tsx'), ts.Extension.Tsx],
+ [path.join(dir, moduleName + '.ts'), ts.Extension.Ts],
+ ]
+ for (const [resolvedPath, ext] of candidates) {
+ if (vol.existsSync(resolvedPath)) {
+ return {
+ resolvedModule: {
+ resolvedFileName: resolvedPath,
+ extension: ext,
+ isExternalLibraryImport: false
+ }
+ }
+ }
+ }
+ }
+ // Fallback to standard resolution (for node_modules etc)
+ return ts.resolveModuleName(moduleName, containingFile, options, host)
+ })
+ }
+
+ // 3. Create Program
+ const program = ts.createProgram(entryPoints, compilerOptions, host)
+ const checker = program.getTypeChecker()
+
+ // 4. Visit AST
+ for (const sourceFile of program.getSourceFiles()) {
+ if (sourceFile.isDeclarationFile) continue
+ ts.forEachChild(sourceFile, node => { visit(node, undefined) })
+ }
+
+ // Extract namespace from useTranslation call
+ function getUseTranslationNamespace (node: ts.CallExpression): string | undefined {
+ const expr = node.expression
+ if (ts.isIdentifier(expr) && expr.text === 'useTranslation') {
+ const arg = node.arguments[0]
+ if (arg && ts.isStringLiteral(arg)) {
+ return arg.text
+ }
+ // Handle array of namespaces: useTranslation(['ns1', 'ns2']) - use the first one
+ if (arg && ts.isArrayLiteralExpression(arg)) {
+ const firstElement = arg.elements[0]
+ if (firstElement && ts.isStringLiteral(firstElement)) {
+ return firstElement.text
+ }
+ }
+ }
+ return undefined
+ }
+
+ function visit (node: ts.Node, scopeNs: string | undefined) {
+ // Track useTranslation namespace in current scope
+ let currentScopeNs = scopeNs
+
+ // Check if this is a function with useTranslation
+ if (ts.isFunctionDeclaration(node) ||
+ ts.isFunctionExpression(node) ||
+ ts.isArrowFunction(node) ||
+ ts.isMethodDeclaration(node)) {
+ const body = 'body' in node ? node.body : undefined
+ if (body) {
+ // Look for useTranslation in this function
+ const searchForUseTranslation = (n: ts.Node): string | undefined => {
+ if (ts.isVariableDeclaration(n) && n.initializer &&
+ ts.isCallExpression(n.initializer)) {
+ const ns = getUseTranslationNamespace(n.initializer)
+ if (ns) return ns
+ }
+ if (ts.isCallExpression(n)) {
+ const ns = getUseTranslationNamespace(n)
+ if (ns) return ns
+ }
+ let result: string | undefined
+ ts.forEachChild(n, child => {
+ if (!result) result = searchForUseTranslation(child)
+ })
+ return result
+ }
+ currentScopeNs = searchForUseTranslation(body) ?? scopeNs
+ }
+ }
+
+ if (ts.isCallExpression(node) && isTranslationFunction(node)) {
+ const arg = node.arguments[0]
+ if (arg) {
+ if (ts.isStringLiteral(arg) || ts.isNoSubstitutionTemplateLiteral(arg)) {
+ ts.forEachChild(node, child => { visit(child, currentScopeNs) })
+ return
+ }
+
+ let values: string[] = []
+
+ // Handle function arguments (e.g. t(() => ...)) by checking return type
+ if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
+ const signature = checker.getSignatureFromDeclaration(arg)
+ if (signature) {
+ const returnType = signature.getReturnType()
+ values = extractStringsFromType(returnType)
+ }
+ } else {
+ // Try standard type resolution first
+ const type = checker.getTypeAtLocation(arg)
+ values = extractStringsFromType(type)
+ }
+
+ // Fallback: If type resolution failed (generic string) but it's a TemplateExpression,
+ // try to manually resolve the parts. This helps in test environments where full type inference is flaky.
+ if (values.length === 0 && ts.isTemplateExpression(arg)) {
+ const head = arg.head.text
+ // Only handle simple case: `prefix.${var}`
+ if (arg.templateSpans.length === 1) {
+ const span = arg.templateSpans[0]
+ const spanType = checker.getTypeAtLocation(span.expression)
+ const spanValues = extractStringsFromType(spanType)
+
+ if (spanValues.length > 0) {
+ values = spanValues.map(v => head + v + span.literal.text)
+ }
+ }
+ }
+
+ // Extract namespace from options (second argument)
+ let optionsNs: string | undefined
+ const optionsArg = node.arguments[1]
+ if (optionsArg && ts.isObjectLiteralExpression(optionsArg)) {
+ const nsProp = optionsArg.properties.find(
+ p => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'ns'
+ )
+ if (nsProp && ts.isPropertyAssignment(nsProp)) {
+ if (ts.isStringLiteral(nsProp.initializer)) {
+ optionsNs = nsProp.initializer.text
+ }
+ }
+ }
+
+ values.forEach(val => {
+ let key = val
+ // Priority: 1. options ns, 2. key contains ns, 3. useTranslation ns, 4. default 'all'
+ let ns = optionsNs
+
+ // Check if key contains namespace separator (e.g., "namespace:key")
+ const separatorIndex = val.indexOf(':')
+ if (separatorIndex > 0) {
+ ns = val.substring(0, separatorIndex)
+ key = val.substring(separatorIndex + 1)
+ }
+
+ let uniqueKey = key
+
+ // Fallback to useTranslation namespace or default
+ if (!ns) {
+ if(currentScopeNs) {
+ ns = currentScopeNs
+ } else if (defaultNS) {
+ ns = defaultNS
+ }
+ }
+ if (ns) {
+ uniqueKey = `${ns}:${key}`
+ }
+
+ if (!keys.has(uniqueKey)) {
+ keys.set(uniqueKey, {
+ key,
+ defaultValue: key,
+ nsIsImplicit: !optionsNs && !val.includes(':') && !currentScopeNs,
+ })
+ }
+ })
+ }
+ }
+ ts.forEachChild(node, child => { visit(child, currentScopeNs) })
+ }
+ }
+ }
+}
diff --git a/frontend/src/components/admin/AdminSidebar.tsx b/frontend/src/components/admin/AdminSidebar.tsx
index 03e88795..441a84d4 100644
--- a/frontend/src/components/admin/AdminSidebar.tsx
+++ b/frontend/src/components/admin/AdminSidebar.tsx
@@ -25,15 +25,8 @@ interface AdminSidebarProps {
onClose: () => void;
}
-interface NavItem {
- nameKey: string;
- href: string;
- icon: React.ComponentType<{ className?: string }>;
- permission?: string;
-}
-
-const navigation: NavItem[] = [
- { nameKey: 'navigation.dashboard', href: '/admin/dashboard', icon: LayoutDashboard },
+const navigation = [
+ { nameKey: 'navigation.dashboard', href: '/admin/dashboard', icon: LayoutDashboard, permission: false },
{ nameKey: 'navigation.events', href: '/admin/events', icon: Calendar, permission: 'events.view' },
{ nameKey: 'navigation.archives', href: '/admin/archives', icon: Archive, permission: 'archives.view' },
{ nameKey: 'admin.analytics', href: '/admin/analytics', icon: BarChart3, permission: 'analytics.view' },
@@ -44,7 +37,7 @@ const navigation: NavItem[] = [
{ nameKey: 'navigation.backup', href: '/admin/backup', icon: HardDrive, permission: 'backup.view' },
{ nameKey: 'navigation.cmsPages', href: '/admin/cms', icon: FileText, permission: 'cms.view' },
{ nameKey: 'navigation.users', href: '/admin/users', icon: Users, permission: 'users.view' },
-];
+] as const;
export const AdminSidebar: React.FC = ({ isOpen, onClose }) => {
const location = useLocation();
diff --git a/frontend/src/components/admin/BackupConfiguration.d.ts b/frontend/src/components/admin/BackupConfiguration.d.ts
deleted file mode 100644
index 78d4eca5..00000000
--- a/frontend/src/components/admin/BackupConfiguration.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import type { ComponentType } from 'react';
-
-export const BackupConfiguration: ComponentType;
diff --git a/frontend/src/components/admin/BackupConfiguration.jsx b/frontend/src/components/admin/BackupConfiguration.tsx
similarity index 94%
rename from frontend/src/components/admin/BackupConfiguration.jsx
rename to frontend/src/components/admin/BackupConfiguration.tsx
index 050ffad7..19890291 100644
--- a/frontend/src/components/admin/BackupConfiguration.jsx
+++ b/frontend/src/components/admin/BackupConfiguration.tsx
@@ -5,18 +5,11 @@ import {
Server,
Cloud,
HardDrive,
- Clock,
- Calendar,
- Shield,
AlertCircle,
- Info,
Eye,
EyeOff,
Wifi,
- CheckCircle,
- XCircle,
Loader2,
- FolderOpen,
Database,
Image,
FileArchive
@@ -24,26 +17,58 @@ import {
import { toast } from 'react-toastify';
import { Button, Card, Input } from '../common';
-export const BackupConfiguration = ({ config, onSave, isSaving }) => {
+interface BackupFormData {
+ backup_enabled: boolean;
+ backup_destination_type: 'local' | 'rsync' | 's3';
+ backup_destination_path: string;
+ backup_rsync_host: string;
+ backup_rsync_user: string;
+ backup_rsync_path: string;
+ backup_rsync_ssh_key: string;
+ backup_s3_endpoint: string;
+ backup_s3_bucket: string;
+ backup_s3_access_key: string;
+ backup_s3_secret_key: string;
+ backup_s3_region: string;
+ backup_schedule: string;
+ backup_schedule_cron: string;
+ backup_retention_days: number;
+ backup_include_database: boolean;
+ backup_include_photos: boolean;
+ backup_include_archives: boolean;
+ backup_include_thumbnails: boolean;
+ backup_include_temp: boolean;
+ backup_compression: boolean;
+ backup_encryption: boolean;
+ backup_encryption_passphrase: string;
+}
+
+interface BackupConfigurationProps {
+ config?: Partial;
+ onSave: (data: BackupFormData) => void;
+ isSaving: boolean;
+}
+
+export const BackupConfiguration: React.FC = ({ config, onSave, isSaving }) => {
const { t } = useTranslation();
-
+
const destinationTypes = [
{
- id: 'local',
+ id: 'local' as const,
name: t('backup.configuration.destinationTypes.local.name'),
icon: HardDrive,
description: t('backup.configuration.destinationTypes.local.description'),
fields: ['backup_destination_path']
},
{
- id: 'rsync',
+ id: 'rsync' as const,
name: t('backup.configuration.destinationTypes.rsync.name'),
icon: Server,
description: t('backup.configuration.destinationTypes.rsync.description'),
fields: ['backup_rsync_host', 'backup_rsync_user', 'backup_rsync_path', 'backup_rsync_ssh_key']
},
{
- id: 's3',
+ id: 's3' as const,
name: t('backup.configuration.destinationTypes.s3.name'),
icon: Cloud,
description: t('backup.configuration.destinationTypes.s3.description'),
@@ -57,8 +82,8 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => {
{ value: 'weekly', label: t('backup.configuration.schedule.options.weekly') },
{ value: 'custom', label: t('backup.configuration.schedule.options.custom') }
];
-
- const [formData, setFormData] = useState({
+
+ const [formData, setFormData] = useState({
backup_enabled: false,
backup_destination_type: 'local',
backup_destination_path: '',
@@ -101,33 +126,32 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => {
}
}, [config]);
- const handleChange = (field, value) => {
+ const handleChange = (field: K, value: BackupFormData[K]) => {
setFormData(prev => ({
...prev,
[field]: value
}));
};
- const handleSubmit = (e) => {
+ const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
-
- // Validate required fields
- const destinationType = destinationTypes.find(t => t.id === formData.backup_destination_type);
- const missingFields = [];
-
+
+ const destinationType = destinationTypes.find(dt => dt.id === formData.backup_destination_type);
+ const missingFields: string[] = [];
+
if (formData.backup_enabled && destinationType) {
destinationType.fields.forEach(field => {
- if (!formData[field] && !field.includes('optional')) {
+ if (!formData[field as keyof BackupFormData] && !field.includes('optional')) {
missingFields.push(field);
}
});
}
-
+
if (missingFields.length > 0) {
toast.error(t('backup.configuration.messages.requiredFields'));
return;
}
-
+
onSave(formData);
};
@@ -138,14 +162,12 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => {
await new Promise(resolve => setTimeout(resolve, 2000));
toast.success(t('backup.configuration.messages.connectionSuccess'));
} catch (error) {
- toast.error(t('backup.configuration.messages.connectionFailed') + ': ' + error.message);
+ toast.error(t('backup.configuration.messages.connectionFailed') + ': ' + (error as Error).message);
} finally {
setTestingConnection(false);
}
};
- const selectedDestination = destinationTypes.find(t => t.id === formData.backup_destination_type);
-
return (