mirror of
https://github.com/polaroi8d/cactoide.git
synced 2026-03-22 06:05:28 +00:00
feat: add i18n translatation check
This commit is contained in:
20
Makefile
20
Makefile
@@ -1,4 +1,4 @@
|
||||
.PHONY: help build up db-only logs db-clean prune
|
||||
.PHONY: help build up db-only logs db-clean prune i18n lint format
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@@ -15,6 +15,7 @@ help:
|
||||
@echo " make logs - Show logs from all services"
|
||||
@echo " make db-clean - Stop & remove database container"
|
||||
@echo " make prune - Remove all containers, images, and volumes"
|
||||
@echo " make i18n - Validate translation files against messages.json"
|
||||
@echo " make help - Show this help message"
|
||||
|
||||
# Build the Docker images
|
||||
@@ -46,4 +47,21 @@ prune:
|
||||
@echo "Cleaning up all Docker resources..."
|
||||
docker compose down -v --rmi all
|
||||
|
||||
# Validate translation files
|
||||
i18n:
|
||||
@echo "Validating translation files..."
|
||||
@if [ -n "$(FILE)" ]; then \
|
||||
./scripts/i18n-check.sh $(FILE); \
|
||||
else \
|
||||
./scripts/i18n-check.sh; \
|
||||
fi
|
||||
|
||||
lint:
|
||||
@echo "Linting the project..."
|
||||
npm run lint
|
||||
|
||||
format:
|
||||
@echo "Formatting the project..."
|
||||
npm run format
|
||||
|
||||
|
||||
|
||||
18
README.md
18
README.md
@@ -55,8 +55,24 @@ Your app will be available at `http://localhost:5173`. You can use the Makefile
|
||||
|
||||
Use the `database/seed.sql` if you want to populate your database with dummy data.
|
||||
|
||||
### i18n
|
||||
|
||||
There is no proper i18n implemented, we have an `/i18n` folder with specific languages. To use an existing translation, just rename the language code JSON file to `messages.json` and you are ready to go. If you would like to add a new translation (which is really appreciated), just create a new `<language_code>.json` file and add the translations from the `messages.json`.
|
||||
|
||||
The project includes a translation validation script to ensure all translation files are complete and up-to-date with the source `messages.json` file.
|
||||
|
||||
```bash
|
||||
# Validate all translation files
|
||||
make i18n
|
||||
```
|
||||
|
||||
```bash
|
||||
# Validate a specific translation file
|
||||
make i18n FILE=src/lib/i18n/it.json
|
||||
```
|
||||
|
||||
### License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|
||||
This project is licensed under the `AGPL-3.0 License` - see the [LICENSE](./LICENSE) file for details.
|
||||
|
||||
**Made with ❤️ by @polaroi8d**
|
||||
|
||||
191
scripts/i18n-check.sh
Executable file
191
scripts/i18n-check.sh
Executable file
@@ -0,0 +1,191 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Translation validation script
|
||||
# Compares a translation file against the source messages.json to find missing keys
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default paths
|
||||
SOURCE_FILE="src/lib/i18n/messages.json"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Function to show usage
|
||||
show_usage() {
|
||||
echo "Usage: $0 [LANGUAGE_FILE]"
|
||||
echo ""
|
||||
echo "Validates a translation file against the source messages.json"
|
||||
echo ""
|
||||
echo "Arguments:"
|
||||
echo " LANGUAGE_FILE Path to the translation file to validate (e.g., src/lib/i18n/it.json)"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 src/lib/i18n/it.json"
|
||||
echo " $0 src/lib/i18n/fr.json"
|
||||
echo ""
|
||||
echo "If no file is provided, it will check all .json files in src/lib/i18n/ except messages.json"
|
||||
}
|
||||
|
||||
# Function to get all keys from a JSON file recursively
|
||||
get_keys() {
|
||||
local file="$1"
|
||||
local prefix="$2"
|
||||
|
||||
# Use jq to extract all keys recursively
|
||||
jq -r 'paths(scalars) as $p | $p | join(".")' "$file" | while read -r key; do
|
||||
if [ -n "$prefix" ]; then
|
||||
echo "${prefix}.${key}"
|
||||
else
|
||||
echo "$key"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Function to validate a single translation file
|
||||
validate_file() {
|
||||
local translation_file="$1"
|
||||
local source_file="$2"
|
||||
|
||||
echo -e "${YELLOW}Validating: $translation_file${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Check if files exist
|
||||
if [ ! -f "$source_file" ]; then
|
||||
echo -e "${RED}Error: Source file $source_file not found${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$translation_file" ]; then
|
||||
echo -e "${RED}Error: Translation file $translation_file not found${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get all keys from source file
|
||||
local source_keys
|
||||
source_keys=$(get_keys "$source_file")
|
||||
|
||||
# Get all keys from translation file
|
||||
local translation_keys
|
||||
translation_keys=$(get_keys "$translation_file")
|
||||
|
||||
# Find missing keys
|
||||
local missing_keys
|
||||
missing_keys=$(comm -23 <(echo "$source_keys" | sort) <(echo "$translation_keys" | sort))
|
||||
|
||||
# Find extra keys (in translation but not in source)
|
||||
local extra_keys
|
||||
extra_keys=$(comm -13 <(echo "$source_keys" | sort) <(echo "$translation_keys" | sort))
|
||||
|
||||
# Count missing and extra keys
|
||||
local missing_count
|
||||
if [ -z "$missing_keys" ]; then
|
||||
missing_count=0
|
||||
else
|
||||
missing_count=$(echo "$missing_keys" | wc -l | tr -d ' ')
|
||||
fi
|
||||
|
||||
local extra_count
|
||||
if [ -z "$extra_keys" ]; then
|
||||
extra_count=0
|
||||
else
|
||||
extra_count=$(echo "$extra_keys" | wc -l | tr -d ' ')
|
||||
fi
|
||||
|
||||
# Report results
|
||||
if [ "$missing_count" -eq 0 ] && [ "$extra_count" -eq 0 ]; then
|
||||
echo -e "${GREEN} Perfect! All keys match.${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$missing_count" -gt 0 ]; then
|
||||
echo -e "${RED} Missing $missing_count key(s) in translation:${NC}"
|
||||
echo "$missing_keys" | while read -r key; do
|
||||
echo -e " ${RED}• $key${NC}"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "$extra_count" -gt 0 ]; then
|
||||
echo -e "${YELLOW} Extra $extra_count key(s) in translation (not in source):${NC}"
|
||||
echo "$extra_keys" | while read -r key; do
|
||||
echo -e " ${YELLOW}• $key${NC}"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Return error code if there are missing keys
|
||||
if [ "$missing_count" -gt 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
local translation_file="$1"
|
||||
local source_file="$PROJECT_ROOT/$SOURCE_FILE"
|
||||
local exit_code=0
|
||||
|
||||
# Change to project root directory
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# If no file specified, check all translation files
|
||||
if [ -z "$translation_file" ]; then
|
||||
echo -e "${YELLOW}No file specified. Checking all translation files...${NC}"
|
||||
echo ""
|
||||
|
||||
# Find all .json files in i18n directory except messages.json
|
||||
local files
|
||||
files=$(find src/lib/i18n -name "*.json" -not -name "messages.json" 2>/dev/null || true)
|
||||
|
||||
if [ -z "$files" ]; then
|
||||
echo -e "${YELLOW}No translation files found in src/lib/i18n/${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Validate each file
|
||||
echo "$files" | while read -r file; do
|
||||
if [ -n "$file" ]; then
|
||||
if ! validate_file "$file" "$source_file"; then
|
||||
exit_code=1
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
return $exit_code
|
||||
fi
|
||||
|
||||
# Validate the specified file
|
||||
if ! validate_file "$translation_file" "$source_file"; then
|
||||
exit_code=1
|
||||
fi
|
||||
|
||||
return $exit_code
|
||||
}
|
||||
|
||||
# Check if jq is installed
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo -e "${RED}Error: jq is required but not installed.${NC}"
|
||||
echo "Please install jq:"
|
||||
echo " macOS: brew install jq"
|
||||
echo " Ubuntu/Debian: sudo apt-get install jq"
|
||||
echo " CentOS/RHEL: sudo yum install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle help flag
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
show_usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run main function
|
||||
main "$1"
|
||||
259
src/lib/i18n/hu.json
Normal file
259
src/lib/i18n/hu.json
Normal file
@@ -0,0 +1,259 @@
|
||||
{
|
||||
"common": {
|
||||
"required": "*",
|
||||
"cancel": "Annulla",
|
||||
"create": "Crea",
|
||||
"edit": "Modifica",
|
||||
"delete": "Elimina",
|
||||
"view": "Visualizza",
|
||||
"home": "Home",
|
||||
"loading": "Caricamento...",
|
||||
"error": "Errore",
|
||||
"success": "Successo",
|
||||
"name": "Nome",
|
||||
"date": "Data",
|
||||
"time": "Ora",
|
||||
"location": "Luogo",
|
||||
"locationType": "Tipo di Luogo",
|
||||
"locationNone": "Nessuno",
|
||||
"locationText": "Testo",
|
||||
"locationMaps": "Google Maps",
|
||||
"locationNoneDescription": "Nessun luogo specificato",
|
||||
"locationTextDescription": "Inserisci il luogo come testo semplice.",
|
||||
"locationMapsDescription": "Inserisci il link di Google Maps.",
|
||||
"googleMapsUrl": "URL di Google Maps",
|
||||
"googleMapsUrlPlaceholder": "https://maps.google.com/...",
|
||||
"type": "Tipo",
|
||||
"visibility": "Visibilità",
|
||||
"public": "Pubblico",
|
||||
"private": "Privato",
|
||||
"limited": "Limitato",
|
||||
"unlimited": "Illimitato",
|
||||
"capacity": "Capacità",
|
||||
"attendees": "Partecipanti",
|
||||
"attendeeLimit": "Limite di Partecipanti",
|
||||
"enterLimit": "Inserisci il limite",
|
||||
"enterEventName": "Inserisci il nome dell'evento",
|
||||
"enterLocation": "Inserisci il luogo",
|
||||
"enterYourName": "Inserisci il tuo nome",
|
||||
"enterNumberOfGuests": "Inserisci il numero di ospiti",
|
||||
"yourName": "Il tuo nome",
|
||||
"numberOfGuests": "Numero di Ospiti",
|
||||
"addGuests": "Aggiungi ospiti",
|
||||
"joinEvent": "Partecipa all'Evento",
|
||||
"copyLink": "Copia Link",
|
||||
"addToCalendar": "Aggiungi al Calendario",
|
||||
"close": "Chiudi",
|
||||
"closeModal": "Chiudi finestra",
|
||||
"removeRSVP": "Rimuovi RSVP",
|
||||
"updating": "Aggiornamento...",
|
||||
"creating": "Creazione...",
|
||||
"adding": "Aggiunta...",
|
||||
"updateEvent": "Aggiorna Evento",
|
||||
"createEvent": "Crea Evento",
|
||||
"createNewEvent": "Crea Nuovo Evento",
|
||||
"createYourFirstEvent": "Crea il Tuo Primo Evento",
|
||||
"editEvent": "Modifica Evento",
|
||||
"deleteEvent": "Elimina Evento",
|
||||
"myEvents": "I Miei Eventi",
|
||||
"discover": "Scopri",
|
||||
"noEventsYet": "Ancora Nessun Evento",
|
||||
"noPublicEventsYet": "Ancora Nessun Evento Pubblico",
|
||||
"noAttendeesYet": "Ancora nessun partecipante",
|
||||
"beFirstToJoin": "Sii il primo a partecipare!",
|
||||
"eventNotFound": "Evento Non Trovato",
|
||||
"eventIsFull": "L'Evento è Pieno!",
|
||||
"maximumCapacityReached": "Raggiunta la capacità massima",
|
||||
"eventLinkCopied": "Link dell'evento copiato negli appunti!",
|
||||
"rsvpAddedSuccessfully": "RSVP aggiunto con successo!",
|
||||
"removedRsvpSuccessfully": "RSVP rimosso con successo.",
|
||||
"anUnexpectedErrorOccurred": "Si è verificato un errore inaspettato.",
|
||||
"somethingWentWrong": "Qualcosa è andato storto. Riprova.",
|
||||
"failedToAddRsvp": "Impossibile aggiungere RSVP",
|
||||
"failedToRemoveRsvp": "Impossibile rimuovere RSVP",
|
||||
"failedToDeleteEvent": "Impossibile eliminare l'evento",
|
||||
"youMayNotHavePermission": "Potresti non avere il permesso di eliminare questo evento.",
|
||||
"anErrorOccurredWhileDeleting": "Si è verificato un errore durante l'eliminazione dell'evento:",
|
||||
"databaseUnreachable": "Database non raggiungibile.",
|
||||
"eventIdNotFound": "EventId non trovato",
|
||||
"eventNotExists": "Evento non trovato",
|
||||
"failedToLoadEvent": "Impossibile caricare l'evento",
|
||||
"nameAndUserIdRequired": "Nome e ID utente sono obbligatori",
|
||||
"eventCapacityExceeded": "Capacità dell'evento superata. Stai cercando di aggiungere {guests} partecipanti (te compreso/a), ma rimangono solo {remaining} posti.",
|
||||
"nameAlreadyExists": "Il nome esiste già per questo evento",
|
||||
"missingOrEmptyFields": "Campi mancanti o vuoti: {fields}",
|
||||
"dateCannotBeInPast": "La data non può essere nel passato.",
|
||||
"limitMustBeAtLeast2": "Il limite deve essere almeno 2 per eventi limitati.",
|
||||
"unauthorized": "Non autorizzato",
|
||||
"youCanOnlyEditYourOwnEvents": "Puoi modificare solo i tuoi eventi",
|
||||
"youDoNotHavePermissionToDelete": "Non hai il permesso di eliminare questo evento",
|
||||
"eventIdAndUserIdRequired": "ID evento e ID utente sono obbligatori",
|
||||
"guestsWillBeAddedAs": "Gli ospiti verranno aggiunti come \"Ospite #1 di {name}\", \"Ospite #2 di {name}\", ecc.",
|
||||
"yourNamePlaceholder": "Il tuo nome",
|
||||
"atTime": "alle"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"discover": "Scopri",
|
||||
"create": "Crea",
|
||||
"myEvents": "I Miei Eventi"
|
||||
},
|
||||
"home": {
|
||||
"title": "Cactoide - Il sito per gli RSVP",
|
||||
"description": "Crea e gestisci gli RSVP degli eventi. Nessuna registrazione richiesta, condivisione immediata.",
|
||||
"mainTitle": "Cactoide(ea)",
|
||||
"subtitle": "La Piattaforma Definitiva per gli RSVP",
|
||||
"tagline": "Crea, condividi e gestisci eventi senza intoppi.",
|
||||
"whyCactoideTitle": "Perché Cactoide(ae)? 🌵",
|
||||
"whyCactoideDescription": "Come il cactus, i grandi eventi fioriscono in ogni condizione se gestiti con cura. Cactoide(ae) ti aiuta a semplificare gli RSVP, coordinare in modo semplice e mantenere ogni dettaglio efficiente: così i tuoi incontri sono resilienti, vivaci e indimenticabili.",
|
||||
"createEventNow": "Crea Evento Ora",
|
||||
"discoverPublicEventsTitle": "Scopri Eventi Pubblici",
|
||||
"discoverPublicEventsDescription": "Guarda cosa stanno pianificando gli altri e lasciati ispirare",
|
||||
"browseAllPublicEvents": "Sfoglia Tutti gli Eventi Pubblici",
|
||||
"whyCactoideFeatureTitle": "Perché Cactoide?",
|
||||
"instantEventCreationTitle": "Creazione Istantanea di Eventi",
|
||||
"instantEventCreationDescription": "Crea eventi in pochi secondi con il nostro modulo semplificato. Nessun account, nessuna attesa, solo pura efficienza.",
|
||||
"oneClickSharingTitle": "Condivisione con un Clic",
|
||||
"oneClickSharingDescription": "Ogni evento ottiene un URL unico e memorabile. Condividi istantaneamente tramite qualsiasi piattaforma o app di messaggistica.",
|
||||
"allInOneClarityTitle": "Chiarezza Tutto-in-Uno",
|
||||
"allInOneClarityDescription": "Niente più scorrimento infinito tra chat e reazioni. Visualizza la disponibilità e le risposte di tutti in un unico posto.",
|
||||
"noHassleNoSignUpsTitle": "Nessun Problema, Nessuna Registrazione",
|
||||
"noHassleNoSignUpsDescription": "Salta le registrazioni e i moduli infiniti. A differenza di altre piattaforme di eventi, crei e condividi istantaneamente: nessun account, nessuna barriera.",
|
||||
"smartLimitsTitle": "Limiti Intelligenti",
|
||||
"smartLimitsDescription": "Scegli tra RSVP illimitati o imposta una capacità limitata. Perfetto per eventi di qualsiasi dimensione.",
|
||||
"effortlessSimplicityTitle": "Semplicità Senza Sforzo",
|
||||
"effortlessSimplicityDescription": "Progettato per essere immediatamente chiaro e facile. Nessuna curva di apprendimento: apri, crea e vai.",
|
||||
"howItWorksTitle": "Come Funziona",
|
||||
"step1Title": "Crea Evento",
|
||||
"step1Description": "Compila un semplice modulo con i dettagli dell'evento. Scegli tra capacità limitata o illimitata.",
|
||||
"step2Title": "Ottieni URL Unico",
|
||||
"step2Description": "Ricevi un URL casuale e memorabile per il tuo evento. Perfetto per la condivisione ovunque.",
|
||||
"step3Title": "Raccogli gli RSVP",
|
||||
"step3Description": "Le persone visitano il tuo link e partecipano solo con il loro nome. Nessun account necessario.",
|
||||
"ctaTitle": "Pronto a Creare il Tuo Primo Evento?",
|
||||
"ctaDescription": "Unisciti a migliaia di organizzatori di eventi che si fidano di Cactoide",
|
||||
"ctaButton": "Crea"
|
||||
},
|
||||
"create": {
|
||||
"title": "Crea Evento - Cactoide",
|
||||
"formTitle": "Crea Nuovo Evento",
|
||||
"eventNameLabel": "Nome",
|
||||
"eventNamePlaceholder": "Inserisci il nome dell'evento",
|
||||
"dateLabel": "Data",
|
||||
"timeLabel": "Ora",
|
||||
"locationLabel": "Luogo",
|
||||
"locationPlaceholder": "Inserisci il luogo",
|
||||
"locationTypeLabel": "Tipo di Luogo",
|
||||
"locationNoneOption": "Nessuno",
|
||||
"locationTextOption": "Testo Semplice",
|
||||
"locationMapsOption": "Google Maps",
|
||||
"locationNoneDescription": "Nessun luogo specificato.",
|
||||
"locationTextDescription": "Inserisci il luogo come testo semplice.",
|
||||
"locationMapsDescription": "Inserisci il link di Google Maps.",
|
||||
"googleMapsUrlLabel": "URL di Google Maps",
|
||||
"googleMapsUrlPlaceholder": "https://maps.google.com/...",
|
||||
"typeLabel": "Tipo",
|
||||
"unlimitedOption": "Illimitato",
|
||||
"limitedOption": "Limitato",
|
||||
"attendeeLimitLabel": "Limite di Partecipanti",
|
||||
"attendeeLimitPlaceholder": "Inserisci il limite",
|
||||
"visibilityLabel": "Visibilità",
|
||||
"publicOption": "🌍 Pubblico",
|
||||
"privateOption": "🔒 Privato",
|
||||
"publicDescription": "Gli eventi pubblici sono visibili a tutti e possono essere scoperti da altri.",
|
||||
"privateDescription": "Gli eventi privati sono visibili solo a te e alle persone con cui condividi il link.",
|
||||
"creatingEvent": "Creazione Evento...",
|
||||
"createEventButton": "Crea Evento"
|
||||
},
|
||||
"event": {
|
||||
"title": "{eventName} - Cactoide",
|
||||
"eventTitle": "Evento - Cactoide",
|
||||
"editTitle": "Modifica Evento - {eventName} - Cactoide",
|
||||
"myEventsTitle": "I Miei Eventi - Cactoide",
|
||||
"eventNotFoundTitle": "Evento Non Trovato",
|
||||
"eventNotFoundDescription": "L'evento che stai cercando non esiste o è stato rimosso.",
|
||||
"joinThisEvent": "Partecipa a Questo Evento",
|
||||
"eventIsFull": "L'Evento è Pieno!",
|
||||
"maximumCapacityReached": "Raggiunta la capacità massima",
|
||||
"yourNameLabel": "Il tuo nome",
|
||||
"yourNamePlaceholder": "Inserisci il tuo nome",
|
||||
"addGuestsLabel": "Aggiungi ospiti",
|
||||
"numberOfGuestsLabel": "Numero di Ospiti",
|
||||
"numberOfGuestsPlaceholder": "Inserisci il numero di ospiti",
|
||||
"guestsWillBeAddedAs": "Gli ospiti verranno aggiunti come \"Ospite #1 di {name}\", \"Ospite #2 di {name}\", ecc.",
|
||||
"joinEventButton": "Partecipa all'Evento",
|
||||
"joinEventWithGuests": "Partecipa all'Evento + {count} Ospite{plural}",
|
||||
"adding": "Aggiunta...",
|
||||
"attendeesTitle": "Partecipanti",
|
||||
"noAttendeesYet": "Ancora nessun partecipante",
|
||||
"beFirstToJoin": "Sii il primo a partecipare!",
|
||||
"copyLinkButton": "Copia Link",
|
||||
"addToCalendarButton": "Aggiungi al Calendario",
|
||||
"eventLinkCopied": "Link dell'evento copiato negli appunti!",
|
||||
"rsvpAddedSuccessfully": "RSVP aggiunto con successo!",
|
||||
"removedRsvpSuccessfully": "RSVP rimosso con successo.",
|
||||
"failedToAddRsvp": "Impossibile aggiungere RSVP",
|
||||
"failedToRemoveRsvp": "Impossibile rimuovere RSVP",
|
||||
"editEventTitle": "Modifica Evento",
|
||||
"editEventDescription": "Aggiorna i dettagli del tuo evento",
|
||||
"updatingEvent": "Aggiornamento...",
|
||||
"updateEventButton": "Aggiorna Evento",
|
||||
"myEventsDescription": "Gestisci i tuoi eventi creati",
|
||||
"noEventsYetTitle": "Ancora Nessun Evento",
|
||||
"noEventsYetDescription": "Non hai ancora creato nessun evento. Inizia creando il tuo primo evento!",
|
||||
"createYourFirstEventButton": "Crea il Tuo Primo Evento",
|
||||
"deleteEventTitle": "Elimina Evento",
|
||||
"deleteEventDescription": "Sei sicuro di voler eliminare \"{eventName}\"? Questa azione non può essere annullata e rimuoverà tutti gli RSVP.",
|
||||
"deleteButton": "Elimina",
|
||||
"viewEventAriaLabel": "Visualizza evento",
|
||||
"editEventAriaLabel": "Modifica evento",
|
||||
"deleteEventAriaLabel": "Elimina evento",
|
||||
"removeRsvpAriaLabel": "Rimuovi RSVP"
|
||||
},
|
||||
"discover": {
|
||||
"title": "Scopri Eventi - Cactoide",
|
||||
"noPublicEventsTitle": "Ancora Nessun Evento Pubblico",
|
||||
"noPublicEventsDescription": "Al momento non ci sono eventi pubblici disponibili. Sii il primo a crearne uno!",
|
||||
"createButton": "Crea",
|
||||
"publicEventsTitle": "Eventi Pubblici ({count})",
|
||||
"publicEventsDescription": "Scopri eventi creati dalla comunità",
|
||||
"searchPlaceholder": "Cerca eventi per nome, luogo...",
|
||||
"typeFilterUnlimited": "Illimitati",
|
||||
"statusFilterLabel": "Stato:",
|
||||
"statusFilterAll": "Tutti gli eventi",
|
||||
"statusFilterUpcoming": "Eventi imminenti",
|
||||
"statusFilterPast": "Eventi passati",
|
||||
"timeFilterLabel": "Orario:",
|
||||
"timeFilterAny": "Qualsiasi orario",
|
||||
"timeFilterNextWeek": "Prossima settimana",
|
||||
"timeFilterNextMonth": "Prossimo mese",
|
||||
"sortOrderLabel": "Ordina:",
|
||||
"sortOrderEarliest": "Prima i più vicini",
|
||||
"sortOrderLatest": "Prima i più recenti",
|
||||
"viewButton": "Visualizza",
|
||||
"noEventsFoundTitle": "Nessun evento trovato",
|
||||
"noEventsFoundDescription": "Prova a modificare i termini di ricerca o sfoglia tutti gli eventi"
|
||||
},
|
||||
"calendar": {
|
||||
"addToCalendarTitle": "Aggiungi al Calendario",
|
||||
"googleCalendarTitle": "Google Calendar",
|
||||
"googleCalendarDescription": "Aggiungi a Google Calendar",
|
||||
"microsoftOutlookTitle": "Microsoft Outlook",
|
||||
"microsoftOutlookDescription": "Aggiungi a Outlook Calendar",
|
||||
"downloadICalTitle": "Scarica File iCal",
|
||||
"downloadICalDescription": "Scarica file .ics per qualsiasi app di calendario"
|
||||
},
|
||||
"errors": {
|
||||
"title": "Errore - Cactoide",
|
||||
"errorTitle": "Errore",
|
||||
"anUnexpectedErrorOccurred": "Si è verificato un errore inaspettato.",
|
||||
"homeButton": "Home"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "Cactoide -",
|
||||
"defaultDescription": "Crea e gestisci gli RSVP degli eventi",
|
||||
"userIdCookieText": "Il tuo UserID memorizzato come cookie:",
|
||||
"firstTimeVisiting": "Prima visita. Generazione di un nuovo UserID...",
|
||||
"copyright": "© 2025 Cactoide"
|
||||
}
|
||||
}
|
||||
264
src/lib/i18n/it.json
Normal file
264
src/lib/i18n/it.json
Normal file
@@ -0,0 +1,264 @@
|
||||
{
|
||||
"common": {
|
||||
"required": "*",
|
||||
"cancel": "Annulla",
|
||||
"create": "Crea",
|
||||
"edit": "Modifica",
|
||||
"delete": "Elimina",
|
||||
"view": "Visualizza",
|
||||
"home": "Home",
|
||||
"loading": "Caricamento...",
|
||||
"error": "Errore",
|
||||
"success": "Successo",
|
||||
"name": "Nome",
|
||||
"date": "Data",
|
||||
"time": "Ora",
|
||||
"location": "Luogo",
|
||||
"locationType": "Tipo di Luogo",
|
||||
"locationNone": "Nessuno",
|
||||
"locationText": "Testo",
|
||||
"locationMaps": "Google Maps",
|
||||
"locationNoneDescription": "Nessun luogo specificato",
|
||||
"locationTextDescription": "Inserisci il luogo come testo semplice.",
|
||||
"locationMapsDescription": "Inserisci il link di Google Maps.",
|
||||
"googleMapsUrl": "URL di Google Maps",
|
||||
"googleMapsUrlPlaceholder": "https://maps.google.com/...",
|
||||
"type": "Tipo",
|
||||
"visibility": "Visibilità",
|
||||
"public": "Pubblico",
|
||||
"private": "Privato",
|
||||
"limited": "Limitato",
|
||||
"unlimited": "Illimitato",
|
||||
"capacity": "Capacità",
|
||||
"attendees": "Partecipanti",
|
||||
"attendeeLimit": "Limite di Partecipanti",
|
||||
"enterLimit": "Inserisci il limite",
|
||||
"enterEventName": "Inserisci il nome dell'evento",
|
||||
"enterLocation": "Inserisci il luogo",
|
||||
"enterYourName": "Inserisci il tuo nome",
|
||||
"enterNumberOfGuests": "Inserisci il numero di ospiti",
|
||||
"yourName": "Il tuo nome",
|
||||
"numberOfGuests": "Numero di Ospiti",
|
||||
"addGuests": "Aggiungi ospiti",
|
||||
"joinEvent": "Partecipa all'Evento",
|
||||
"copyLink": "Copia Link",
|
||||
"addToCalendar": "Aggiungi al Calendario",
|
||||
"close": "Chiudi",
|
||||
"closeModal": "Chiudi finestra",
|
||||
"removeRSVP": "Rimuovi RSVP",
|
||||
"updating": "Aggiornamento...",
|
||||
"creating": "Creazione...",
|
||||
"adding": "Aggiunta...",
|
||||
"updateEvent": "Aggiorna Evento",
|
||||
"createEvent": "Crea Evento",
|
||||
"createNewEvent": "Crea Nuovo Evento",
|
||||
"createYourFirstEvent": "Crea il Tuo Primo Evento",
|
||||
"editEvent": "Modifica Evento",
|
||||
"deleteEvent": "Elimina Evento",
|
||||
"myEvents": "I Miei Eventi",
|
||||
"discover": "Scopri",
|
||||
"noEventsYet": "Ancora Nessun Evento",
|
||||
"noPublicEventsYet": "Ancora Nessun Evento Pubblico",
|
||||
"noAttendeesYet": "Ancora nessun partecipante",
|
||||
"beFirstToJoin": "Sii il primo a partecipare!",
|
||||
"eventNotFound": "Evento Non Trovato",
|
||||
"eventIsFull": "L'Evento è Pieno!",
|
||||
"maximumCapacityReached": "Raggiunta la capacità massima",
|
||||
"eventLinkCopied": "Link dell'evento copiato negli appunti!",
|
||||
"rsvpAddedSuccessfully": "RSVP aggiunto con successo!",
|
||||
"removedRsvpSuccessfully": "RSVP rimosso con successo.",
|
||||
"anUnexpectedErrorOccurred": "Si è verificato un errore inaspettato.",
|
||||
"somethingWentWrong": "Qualcosa è andato storto. Riprova.",
|
||||
"failedToAddRsvp": "Impossibile aggiungere RSVP",
|
||||
"failedToRemoveRsvp": "Impossibile rimuovere RSVP",
|
||||
"failedToDeleteEvent": "Impossibile eliminare l'evento",
|
||||
"youMayNotHavePermission": "Potresti non avere il permesso di eliminare questo evento.",
|
||||
"anErrorOccurredWhileDeleting": "Si è verificato un errore durante l'eliminazione dell'evento:",
|
||||
"databaseUnreachable": "Database non raggiungibile.",
|
||||
"eventIdNotFound": "EventId non trovato",
|
||||
"eventNotExists": "Evento non trovato",
|
||||
"failedToLoadEvent": "Impossibile caricare l'evento",
|
||||
"nameAndUserIdRequired": "Nome e ID utente sono obbligatori",
|
||||
"eventCapacityExceeded": "Capacità dell'evento superata. Stai cercando di aggiungere {guests} partecipanti (te compreso/a), ma rimangono solo {remaining} posti.",
|
||||
"nameAlreadyExists": "Il nome esiste già per questo evento",
|
||||
"missingOrEmptyFields": "Campi mancanti o vuoti: {fields}",
|
||||
"dateCannotBeInPast": "La data non può essere nel passato.",
|
||||
"limitMustBeAtLeast2": "Il limite deve essere almeno 2 per eventi limitati.",
|
||||
"unauthorized": "Non autorizzato",
|
||||
"youCanOnlyEditYourOwnEvents": "Puoi modificare solo i tuoi eventi",
|
||||
"youDoNotHavePermissionToDelete": "Non hai il permesso di eliminare questo evento",
|
||||
"eventIdAndUserIdRequired": "ID evento e ID utente sono obbligatori",
|
||||
"guestsWillBeAddedAs": "Gli ospiti verranno aggiunti come \"Ospite #1 di {name}\", \"Ospite #2 di {name}\", ecc.",
|
||||
"yourNamePlaceholder": "Il tuo nome",
|
||||
"atTime": "alle"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"discover": "Scopri",
|
||||
"create": "Crea",
|
||||
"myEvents": "I Miei Eventi"
|
||||
},
|
||||
"home": {
|
||||
"title": "Cactoide - Il sito per gli RSVP",
|
||||
"description": "Crea e gestisci gli RSVP degli eventi. Nessuna registrazione richiesta, condivisione immediata.",
|
||||
"mainTitle": "Cactoide(ea)",
|
||||
"subtitle": "La Piattaforma Definitiva per gli RSVP",
|
||||
"tagline": "Crea, condividi e gestisci eventi senza intoppi.",
|
||||
"whyCactoideTitle": "Perché Cactoide(ae)? 🌵",
|
||||
"whyCactoideDescription": "Come il cactus, i grandi eventi fioriscono in ogni condizione se gestiti con cura. Cactoide(ae) ti aiuta a semplificare gli RSVP, coordinare in modo semplice e mantenere ogni dettaglio efficiente: così i tuoi incontri sono resilienti, vivaci e indimenticabili.",
|
||||
"createEventNow": "Crea Evento Ora",
|
||||
"discoverPublicEventsTitle": "Scopri Eventi Pubblici",
|
||||
"discoverPublicEventsDescription": "Guarda cosa stanno pianificando gli altri e lasciati ispirare",
|
||||
"browseAllPublicEvents": "Sfoglia Tutti gli Eventi Pubblici",
|
||||
"whyCactoideFeatureTitle": "Perché Cactoide?",
|
||||
"instantEventCreationTitle": "Creazione Istantanea di Eventi",
|
||||
"instantEventCreationDescription": "Crea eventi in pochi secondi con il nostro modulo semplificato. Nessun account, nessuna attesa, solo pura efficienza.",
|
||||
"oneClickSharingTitle": "Condivisione con un Clic",
|
||||
"oneClickSharingDescription": "Ogni evento ottiene un URL unico e memorabile. Condividi istantaneamente tramite qualsiasi piattaforma o app di messaggistica.",
|
||||
"allInOneClarityTitle": "Chiarezza Tutto-in-Uno",
|
||||
"allInOneClarityDescription": "Niente più scorrimento infinito tra chat e reazioni. Visualizza la disponibilità e le risposte di tutti in un unico posto.",
|
||||
"noHassleNoSignUpsTitle": "Nessun Problema, Nessuna Registrazione",
|
||||
"noHassleNoSignUpsDescription": "Salta le registrazioni e i moduli infiniti. A differenza di altre piattaforme di eventi, crei e condividi istantaneamente: nessun account, nessuna barriera.",
|
||||
"smartLimitsTitle": "Limiti Intelligenti",
|
||||
"smartLimitsDescription": "Scegli tra RSVP illimitati o imposta una capacità limitata. Perfetto per eventi di qualsiasi dimensione.",
|
||||
"effortlessSimplicityTitle": "Semplicità Senza Sforzo",
|
||||
"effortlessSimplicityDescription": "Progettato per essere immediatamente chiaro e facile. Nessuna curva di apprendimento: apri, crea e vai.",
|
||||
"howItWorksTitle": "Come Funziona",
|
||||
"step1Title": "Crea Evento",
|
||||
"step1Description": "Compila un semplice modulo con i dettagli dell'evento. Scegli tra capacità limitata o illimitata.",
|
||||
"step2Title": "Ottieni URL Unico",
|
||||
"step2Description": "Ricevi un URL casuale e memorabile per il tuo evento. Perfetto per la condivisione ovunque.",
|
||||
"step3Title": "Raccogli gli RSVP",
|
||||
"step3Description": "Le persone visitano il tuo link e partecipano solo con il loro nome. Nessun account necessario.",
|
||||
"ctaTitle": "Pronto a Creare il Tuo Primo Evento?",
|
||||
"ctaDescription": "Unisciti a migliaia di organizzatori di eventi che si fidano di Cactoide",
|
||||
"ctaButton": "Crea"
|
||||
},
|
||||
"create": {
|
||||
"title": "Crea Evento - Cactoide",
|
||||
"formTitle": "Crea Nuovo Evento",
|
||||
"eventNameLabel": "Nome",
|
||||
"eventNamePlaceholder": "Inserisci il nome dell'evento",
|
||||
"dateLabel": "Data",
|
||||
"timeLabel": "Ora",
|
||||
"locationLabel": "Luogo",
|
||||
"locationPlaceholder": "Inserisci il luogo",
|
||||
"locationTypeLabel": "Tipo di Luogo",
|
||||
"locationNoneOption": "Nessuno",
|
||||
"locationTextOption": "Testo Semplice",
|
||||
"locationMapsOption": "Google Maps",
|
||||
"locationNoneDescription": "Nessun luogo specificato.",
|
||||
"locationTextDescription": "Inserisci il luogo come testo semplice.",
|
||||
"locationMapsDescription": "Inserisci il link di Google Maps.",
|
||||
"googleMapsUrlLabel": "URL di Google Maps",
|
||||
"googleMapsUrlPlaceholder": "https://maps.google.com/...",
|
||||
"typeLabel": "Tipo",
|
||||
"unlimitedOption": "Illimitato",
|
||||
"limitedOption": "Limitato",
|
||||
"attendeeLimitLabel": "Limite di Partecipanti",
|
||||
"attendeeLimitPlaceholder": "Inserisci il limite",
|
||||
"visibilityLabel": "Visibilità",
|
||||
"publicOption": "🌍 Pubblico",
|
||||
"privateOption": "🔒 Privato",
|
||||
"publicDescription": "Gli eventi pubblici sono visibili a tutti e possono essere scoperti da altri.",
|
||||
"privateDescription": "Gli eventi privati sono visibili solo a te e alle persone con cui condividi il link.",
|
||||
"creatingEvent": "Creazione Evento...",
|
||||
"createEventButton": "Crea Evento"
|
||||
},
|
||||
"event": {
|
||||
"title": "{eventName} - Cactoide",
|
||||
"eventTitle": "Evento - Cactoide",
|
||||
"editTitle": "Modifica Evento - {eventName} - Cactoide",
|
||||
"myEventsTitle": "I Miei Eventi - Cactoide",
|
||||
"eventNotFoundTitle": "Evento Non Trovato",
|
||||
"eventNotFoundDescription": "L'evento che stai cercando non esiste o è stato rimosso.",
|
||||
"joinThisEvent": "Partecipa a Questo Evento",
|
||||
"eventIsFull": "L'Evento è Pieno!",
|
||||
"maximumCapacityReached": "Raggiunta la capacità massima",
|
||||
"yourNameLabel": "Il tuo nome",
|
||||
"yourNamePlaceholder": "Inserisci il tuo nome",
|
||||
"addGuestsLabel": "Aggiungi ospiti",
|
||||
"numberOfGuestsLabel": "Numero di Ospiti",
|
||||
"numberOfGuestsPlaceholder": "Inserisci il numero di ospiti",
|
||||
"guestsWillBeAddedAs": "Gli ospiti verranno aggiunti come \"Ospite #1 di {name}\", \"Ospite #2 di {name}\", ecc.",
|
||||
"joinEventButton": "Partecipa all'Evento",
|
||||
"joinEventWithGuests": "Partecipa all'Evento + {count} Ospite{plural}",
|
||||
"adding": "Aggiunta...",
|
||||
"attendeesTitle": "Partecipanti",
|
||||
"noAttendeesYet": "Ancora nessun partecipante",
|
||||
"beFirstToJoin": "Sii il primo a partecipare!",
|
||||
"copyLinkButton": "Copia Link",
|
||||
"addToCalendarButton": "Aggiungi al Calendario",
|
||||
"eventLinkCopied": "Link dell'evento copiato negli appunti!",
|
||||
"rsvpAddedSuccessfully": "RSVP aggiunto con successo!",
|
||||
"removedRsvpSuccessfully": "RSVP rimosso con successo.",
|
||||
"failedToAddRsvp": "Impossibile aggiungere RSVP",
|
||||
"failedToRemoveRsvp": "Impossibile rimuovere RSVP",
|
||||
"editEventTitle": "Modifica Evento",
|
||||
"editEventDescription": "Aggiorna i dettagli del tuo evento",
|
||||
"updatingEvent": "Aggiornamento...",
|
||||
"updateEventButton": "Aggiorna Evento",
|
||||
"myEventsDescription": "Gestisci i tuoi eventi creati",
|
||||
"noEventsYetTitle": "Ancora Nessun Evento",
|
||||
"noEventsYetDescription": "Non hai ancora creato nessun evento. Inizia creando il tuo primo evento!",
|
||||
"createYourFirstEventButton": "Crea il Tuo Primo Evento",
|
||||
"deleteEventTitle": "Elimina Evento",
|
||||
"deleteEventDescription": "Sei sicuro di voler eliminare \"{eventName}\"? Questa azione non può essere annullata e rimuoverà tutti gli RSVP.",
|
||||
"deleteButton": "Elimina",
|
||||
"viewEventAriaLabel": "Visualizza evento",
|
||||
"editEventAriaLabel": "Modifica evento",
|
||||
"deleteEventAriaLabel": "Elimina evento",
|
||||
"removeRsvpAriaLabel": "Rimuovi RSVP"
|
||||
},
|
||||
"discover": {
|
||||
"title": "Scopri Eventi - Cactoide",
|
||||
"noPublicEventsTitle": "Ancora Nessun Evento Pubblico",
|
||||
"noPublicEventsDescription": "Al momento non ci sono eventi pubblici disponibili. Sii il primo a crearne uno!",
|
||||
"createButton": "Crea",
|
||||
"publicEventsTitle": "Eventi Pubblici ({count})",
|
||||
"publicEventsDescription": "Scopri eventi creati dalla comunità",
|
||||
"searchPlaceholder": "Cerca eventi per nome, luogo...",
|
||||
"searchInputAriaLabel": "Input di ricerca",
|
||||
"toggleFiltersAriaLabel": "Attiva/Disattiva filtri",
|
||||
"typeFilterLabel": "Tipo:",
|
||||
"typeFilterAll": "Tutti",
|
||||
"typeFilterLimited": "Limitati",
|
||||
"typeFilterUnlimited": "Illimitati",
|
||||
"statusFilterLabel": "Stato:",
|
||||
"statusFilterAll": "Tutti gli eventi",
|
||||
"statusFilterUpcoming": "Eventi imminenti",
|
||||
"statusFilterPast": "Eventi passati",
|
||||
"timeFilterLabel": "Orario:",
|
||||
"timeFilterAny": "Qualsiasi orario",
|
||||
"timeFilterNextWeek": "Prossima settimana",
|
||||
"timeFilterNextMonth": "Prossimo mese",
|
||||
"sortOrderLabel": "Ordina:",
|
||||
"sortOrderEarliest": "Prima i più vicini",
|
||||
"sortOrderLatest": "Prima i più recenti",
|
||||
"viewButton": "Visualizza",
|
||||
"noEventsFoundTitle": "Nessun evento trovato",
|
||||
"noEventsFoundDescription": "Prova a modificare i termini di ricerca o sfoglia tutti gli eventi"
|
||||
},
|
||||
"calendar": {
|
||||
"addToCalendarTitle": "Aggiungi al Calendario",
|
||||
"googleCalendarTitle": "Google Calendar",
|
||||
"googleCalendarDescription": "Aggiungi a Google Calendar",
|
||||
"microsoftOutlookTitle": "Microsoft Outlook",
|
||||
"microsoftOutlookDescription": "Aggiungi a Outlook Calendar",
|
||||
"downloadICalTitle": "Scarica File iCal",
|
||||
"downloadICalDescription": "Scarica file .ics per qualsiasi app di calendario"
|
||||
},
|
||||
"errors": {
|
||||
"title": "Errore - Cactoide",
|
||||
"errorTitle": "Errore",
|
||||
"anUnexpectedErrorOccurred": "Si è verificato un errore inaspettato.",
|
||||
"homeButton": "Home"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "Cactoide -",
|
||||
"defaultDescription": "Crea e gestisci gli RSVP degli eventi",
|
||||
"userIdCookieText": "Il tuo UserID memorizzato come cookie:",
|
||||
"firstTimeVisiting": "Prima visita. Generazione di un nuovo UserID...",
|
||||
"copyright": "© 2025 Cactoide"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user