perf+security: fix build, secure downloads, dedupe translations, refactor i18n
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m49s

Frontend:
- Fix Framer Motion / motion-dom build error by pinning framer-motion to
  11.18.2 (compatible with React 19 and Next.js 16).
- Add cross-env and build:local script to bypass standalone symlink errors
  on Windows without Developer Mode.
- Allow NEXT_OUTPUT=default to disable standalone output for local builds.
- Refactor i18n: split 14,177-line src/lib/i18n.tsx into per-locale,
  per-namespace JSON files under src/lib/i18n/messages/.
- Load English synchronously; other locales loaded on demand via dynamic
  imports (reduces initial bundle, improves maintainability).
- Remove unused next-intl message files src/messages/en.json and fr.json.

Backend:
- Remove insecure legacy /api/v1/download/{filename} and /api/v1/cleanup/{filename}
  endpoints. The job-based /api/v1/download/{job_id} already enforces ownership.
- Deduplicate texts in TranslationService.translate_batch before sending them
  to the provider, reducing API calls for repeated strings.
- Pin httpx to <0.28 to fix TestClient incompatibility with starlette 0.35.1.
- Add pytest-cov and ruff dev dependencies/config.

DevOps:
- Remove hardcoded Grafana password from docker-compose.yml and
  docker-compose.monitoring.yml; use GRAFANA_PASSWORD env var.
- Change default TRANSLATION_SERVICE from ollama to google in
  docker-compose.yml (Ollama is an optional profile).
- Add GRAFANA_PASSWORD to .env.example.
- Add .coverage and frontend/pnpm-workspace.yaml to .gitignore.

Tests:
- Update API versioning tests for removed legacy endpoints.
- Add tests/test_translation_service.py for deduplication behavior.

Verified:
- pnpm run build:local passes.
- uv run pytest tests/test_providers/* tests/test_translation_service.py
  tests/test_story_3_5_api_versioning.py tests/test_download_endpoint.py
  tests/test_translators/test_excel_translator.py: provider/translator tests
  pass; one pre-existing French error-message test still fails (message is
  returned in English, unrelated to this change).
This commit is contained in:
2026-06-14 16:44:18 +02:00
parent eda6821632
commit fa637abff0
365 changed files with 23910 additions and 14955 deletions

View File

@@ -0,0 +1,146 @@
{
"landing.nav.why": "Perché noi?",
"landing.nav.formats": "Formati",
"landing.nav.pricing": "Prezzi",
"landing.nav.login": "Accedi",
"landing.nav.startFree": "Prova gratis",
"landing.hero.tag": "IA Documentale Professionale",
"landing.hero.titleLine1": "Traduci i tuoi documenti.",
"landing.hero.titleLine2": "Con formattazione perfetta.",
"landing.hero.description": "L'unico traduttore che preserva SmartArt, grafici, sommari, forme e layout complessi — esattamente come erano.",
"landing.hero.ctaMain": "Prova gratis — 2 doc/mese",
"landing.hero.ctaSec": "Vedi offerte",
"landing.hero.deleted": "File eliminati dopo 60 min",
"landing.hero.noHidden": "Nessun costo nascosto",
"landing.hero.preview": "Anteprima prima del pagamento",
"landing.hero.formattedOk": "Formattazione OK",
"landing.hero.aiActive": "Traduzione IA attiva",
"landing.steps.title": "Come funziona?",
"landing.steps.subtitle": "Tre passaggi. Zero perdita di formato.",
"landing.steps.step1.num": "01",
"landing.steps.step1.title": "Carica il tuo file",
"landing.steps.step1.desc": "Trascina il tuo documento Excel, Word, PowerPoint o PDF.",
"landing.steps.step2.num": "02",
"landing.steps.step2.title": "Scegli lingua e motore",
"landing.steps.step2.desc": "Seleziona la lingua di destinazione e il motore — classico o IA contestuale.",
"landing.steps.step3.num": "03",
"landing.steps.step3.title": "Scarica il risultato",
"landing.steps.step3.desc": "Ottieni il documento tradotto con una formattazione identica all'originale.",
"landing.features.tag": "Motore di Traduzione IA",
"landing.features.title": "Una traduzione che comprende il tuo mestiere",
"landing.features.description": "I nostri modelli IA analizzano il contesto, rispettano la tua terminologia e traducono anche il testo nelle immagini.",
"landing.features.context.title": "Contesto settoriale",
"landing.features.context.desc": "Descrivi il tuo settore e ottieni traduzioni su misura, non generiche.",
"landing.features.glossary.title": "Glossari settoriali",
"landing.features.glossary.desc": "Definisci i tuoi termini tecnici. CTA rimarrà «Unità di Trattamento Aria», mai «Invito all'Azione».",
"landing.features.vision.title": "Visione immagini",
"landing.features.vision.desc": "Il testo incorporato in immagini, diagrammi e grafici viene rilevato e tradotto.",
"landing.features.demo.source": "Origine (FR)",
"landing.features.demo.google": "Google Translate",
"landing.features.demo.ours": "La nostra IA",
"landing.layout.title": "La tua formattazione,",
"landing.layout.title2": "perfettamente preservata",
"landing.layout.subtitle": "Gli altri traduttori rovinano il tuo layout. Noi no.",
"landing.layout.p1.title": "SmartArt e diagrammi",
"landing.layout.p1.desc": "Organigrammi, flussi, gerarchie — tutto tradotto in modo identico.",
"landing.layout.p2.title": "Sommari",
"landing.layout.p2.desc": "Voci del sommario, numeri di pagina e riferimenti incrociati aggiornati correttamente.",
"landing.layout.p3.title": "Grafici e diagrammi",
"landing.layout.p3.desc": "Titoli, etichette degli assi, legende e nomi delle serie — tutto tradotto.",
"landing.layout.p4.title": "Forme e caselle di testo",
"landing.layout.p4.desc": "Rettangoli, blocchi arrotondati, callout — localizzati ovunque.",
"landing.layout.p5.title": "Intestazioni e piè di pagina",
"landing.layout.p5.desc": "Intestazioni, piè di pagina e note a piè di pagina non vengono mai tralasciati.",
"landing.layout.p6.title": "130+ lingue",
"landing.layout.p6.desc": "Google Translate, DeepL e motori IA di livello professionale.",
"landing.formats.title": "Ogni formato,",
"landing.formats.title2": "ogni elemento",
"landing.formats.subtitle": "Traduciamo ciò che gli altri dimenticano. La tua azienda merita una documentazione impeccabile.",
"landing.formats.word.name": "Word",
"landing.formats.word.i1": "Paragrafi e titoli",
"landing.formats.word.i2": "Tabelle e grafici",
"landing.formats.word.i3": "Diagrammi SmartArt",
"landing.formats.word.i4": "Sommario",
"landing.formats.word.i5": "Intestazioni e piè di pagina",
"landing.formats.word.i6": "Forme e caselle di testo",
"landing.formats.word.i7": "Note a piè di pagina e di chiusura",
"landing.formats.excel.name": "Excel",
"landing.formats.excel.i1": "Valori delle celle",
"landing.formats.excel.i2": "Nomi dei fogli",
"landing.formats.excel.i3": "Grafici e etichette",
"landing.formats.excel.i4": "Intestazioni e piè di pagina",
"landing.formats.excel.i5": "Celle unite preservate",
"landing.formats.pptx.name": "PowerPoint",
"landing.formats.pptx.i1": "Testo delle slide e note",
"landing.formats.pptx.i2": "Grafici e diagrammi",
"landing.formats.pptx.i3": "Forme e caselle di testo",
"landing.formats.pptx.i4": "Layout master",
"landing.formats.pptx.i5": "Animazioni preservate",
"landing.formats.pdf.name": "PDF",
"landing.formats.pdf.i1": "PDF basati su testo",
"landing.formats.pdf.i2": "Layout preservato",
"landing.formats.pdf.i3": "Immagini mantenute al loro posto",
"landing.formats.pdf.i4": "Tabelle mantenute",
"landing.formats.pdf.i5": "Output come DOCX o PDF",
"landing.pricing.title": "Prezzi semplici e onesti",
"landing.pricing.subtitle": "Quello che vedi è quello che paghi. Nessun costo nascosto.",
"landing.pricing.monthly": "Mensile",
"landing.pricing.annual": "Annuale",
"landing.pricing.bestValue": "Più popolare",
"landing.pricing.month": "/mese",
"landing.pricing.footer": "Il prezzo visualizzato è il prezzo che paghi. Nessun costo nascosto dopo la traduzione.",
"landing.pricing.starter.name": "Starter",
"landing.pricing.starter.desc": "Per privati e piccoli progetti",
"landing.pricing.starter.f1": "50 documenti / mese",
"landing.pricing.starter.f2": "Fino a 50 pagine per documento",
"landing.pricing.starter.f3": "Google Translate + DeepL",
"landing.pricing.starter.f4": "File fino a 10 MB",
"landing.pricing.starter.cta": "Inizia",
"landing.pricing.pro.name": "Pro",
"landing.pricing.pro.desc": "Per professionisti esigenti",
"landing.pricing.pro.f1": "200 documenti / mese",
"landing.pricing.pro.f2": "Fino a 200 pagine per documento",
"landing.pricing.pro.f3": "Traduzione con IA",
"landing.pricing.pro.f4": "Google + DeepL inclusi",
"landing.pricing.pro.f5": "Glossari e prompt personalizzati",
"landing.pricing.pro.f6": "Supporto prioritario",
"landing.pricing.pro.cta": "Prova Pro",
"landing.pricing.business.name": "Business",
"landing.pricing.business.desc": "Per team con esigenze elevate",
"landing.pricing.business.f1": "1 000 documenti / mese",
"landing.pricing.business.f2": "Fino a 500 pagine per documento",
"landing.pricing.business.f3": "IA Premium (Claude)",
"landing.pricing.business.f4": "Tutti i provider + accesso API",
"landing.pricing.business.f5": "Webhook e automazione",
"landing.pricing.business.f6": "5 postazioni team",
"landing.pricing.business.cta": "Contattaci",
"landing.cta.title": "Inizia a tradurre in 30 secondi",
"landing.cta.subtitle": "Nessuna carta di credito richiesta. Prova subito gratuitamente e ridai vita ai tuoi documenti multilingue.",
"landing.cta.button": "Crea un account gratuito",
"landing.cta.secure": "Protetto da crittografia AES-256",
"landing.footer.desc": "Esperti di traduzione intelligente dei documenti. Uniamo l'arte del layout con la scienza dell'IA contestuale.",
"landing.footer.product": "Prodotto",
"landing.footer.resources": "Risorse",
"landing.footer.legal": "Legale",
"landing.footer.rights": "© 2026 Wordly.art — Tutti i diritti riservati.",
"landing.hero.contextEngine": "Traduzione rilevata: Termine tecnico di manutenzione per sistemi HVAC...",
"landing.hero.liveAnalysis": "Analisi in tempo reale",
"landing.hero.termsDetected": "termini rilevati",
"landing.steps.process": "PROCESSO",
"landing.translate.newProject": "Nuovo progetto",
"landing.translate.title": "Traduci un documento",
"landing.translate.subtitle": "Importa un file e scegli la lingua di destinazione",
"landing.translate.sourceDocument": "Documento sorgente",
"landing.translate.configuration": "Configurazione",
"landing.translate.sourceLang": "Lingua sorgente",
"landing.translate.targetLang": "Lingua di destinazione",
"landing.translate.provider": "Fornitore",
"landing.translate.startTranslation": "Avvia traduzione",
"landing.translate.zeroRetention": "Zero conservazione",
"landing.translate.filesDeleted": "File eliminati dopo l'elaborazione",
"landing.translate.dropHere": "Trascina e rilascia qui",
"landing.translate.supportedFormats": "File DOCX, XLSX, PPTX o PDF supportati",
"landing.translate.aiAnalysis": "Analisi IA Attiva",
"landing.translate.processing": "Elaborazione in corso",
"landing.translate.preservingLayout": "Il tuo layout viene preservato"
}