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": "Waarom wij?",
"landing.nav.formats": "Formaten",
"landing.nav.pricing": "Prijzen",
"landing.nav.login": "Inloggen",
"landing.nav.startFree": "Gratis starten",
"landing.hero.tag": "Professionele Document-AI",
"landing.hero.titleLine1": "Vertaal uw documenten.",
"landing.hero.titleLine2": "Met perfecte opmaak.",
"landing.hero.description": "De enige vertaler die SmartArt, grafieken, inhoudsopgaven, vormen en complexe lay-outs bewaart — precies zoals ze waren.",
"landing.hero.ctaMain": "Gratis starten — 2 docs/maand",
"landing.hero.ctaSec": "Aanbiedingen bekijken",
"landing.hero.deleted": "Bestanden na 60 min. verwijderd",
"landing.hero.noHidden": "Geen verborgen kosten",
"landing.hero.preview": "Voorbeeld voor betaling",
"landing.hero.formattedOk": "Opmaak OK",
"landing.hero.aiActive": "AI-vertaling actief",
"landing.steps.title": "Hoe werkt het?",
"landing.steps.subtitle": "Drie stappen. Geen opmaakverlies.",
"landing.steps.step1.num": "01",
"landing.steps.step1.title": "Upload uw bestand",
"landing.steps.step1.desc": "Sleep uw Excel-, Word-, PowerPoint- of PDF-document en laat het vallen.",
"landing.steps.step2.num": "02",
"landing.steps.step2.title": "Kies taal en engine",
"landing.steps.step2.desc": "Selecteer de doeltaal en engine — klassiek of contextbewuste AI.",
"landing.steps.step3.num": "03",
"landing.steps.step3.title": "Download het resultaat",
"landing.steps.step3.desc": "Ontvang uw vertaalde document met een opmaak identiek aan het origineel.",
"landing.features.tag": "AI-vertaalengine",
"landing.features.title": "Vertaling die uw vakgebied begrijpt",
"landing.features.description": "Onze AI-modellen analyseren de context, respecteren uw terminologie en vertalen zelfs tekst in afbeeldingen.",
"landing.features.context.title": "Branchcontext",
"landing.features.context.desc": "Beschrijf uw vakgebied en ontvang toegespitste vertalingen, geen generieke.",
"landing.features.glossary.title": "Brancheglossaria",
"landing.features.glossary.desc": "Definieer uw vaktermen. CTA blijft «Luchtbehandelingsunit», nooit «Call To Action».",
"landing.features.vision.title": "Beeldherkenning",
"landing.features.vision.desc": "Tekst in afbeeldingen, diagrammen en grafieken wordt gedetecteerd en vertaald.",
"landing.features.demo.source": "Bron (FR)",
"landing.features.demo.google": "Google Translate",
"landing.features.demo.ours": "Onze AI",
"landing.layout.title": "Uw opmaak,",
"landing.layout.title2": "perfect bewaard",
"landing.layout.subtitle": "Andere vertalers breken uw lay-out. Wij niet.",
"landing.layout.p1.title": "SmartArt en diagrammen",
"landing.layout.p1.desc": "Organigrammen, stroomdiagrammen, hiërarchieën — alles identiek vertaald.",
"landing.layout.p2.title": "Inhoudsopgaven",
"landing.layout.p2.desc": "Inhoudsopgave-items, paginanummers en kruisverwijzingen correct bijgewerkt.",
"landing.layout.p3.title": "Grafieken en diagrammen",
"landing.layout.p3.desc": "Titels, aslabels, legendas en serienamen — alles vertaald.",
"landing.layout.p4.title": "Vormen en tekstvakken",
"landing.layout.p4.desc": "Rechthoeken, afgeronde blokken, callouts — overal gelokaliseerd.",
"landing.layout.p5.title": "Kop- en voetteksten",
"landing.layout.p5.desc": "Koppen, voetteksten en voetnoten worden nooit over het hoofd gezien.",
"landing.layout.p6.title": "130+ talen",
"landing.layout.p6.desc": "Google Translate, DeepL en professionele AI-engines.",
"landing.formats.title": "Elk formaat,",
"landing.formats.title2": "elk element",
"landing.formats.subtitle": "Wij vertalen wat anderen missen. Uw bedrijf verdient onberispelijke documentatie.",
"landing.formats.word.name": "Word",
"landing.formats.word.i1": "Alinea's en koppen",
"landing.formats.word.i2": "Tabellen en grafieken",
"landing.formats.word.i3": "SmartArt-diagrammen",
"landing.formats.word.i4": "Inhoudsopgave",
"landing.formats.word.i5": "Kop- en voetteksten",
"landing.formats.word.i6": "Vormen en tekstvakken",
"landing.formats.word.i7": "Voet- en eindnoten",
"landing.formats.excel.name": "Excel",
"landing.formats.excel.i1": "Celwaarden",
"landing.formats.excel.i2": "Werkbladnamen",
"landing.formats.excel.i3": "Grafieken en labels",
"landing.formats.excel.i4": "Kop- en voetteksten",
"landing.formats.excel.i5": "Samengevoegde cellen behouden",
"landing.formats.pptx.name": "PowerPoint",
"landing.formats.pptx.i1": "Dia-tekst en notities",
"landing.formats.pptx.i2": "Grafieken en diagrammen",
"landing.formats.pptx.i3": "Vormen en tekstvakken",
"landing.formats.pptx.i4": "Masterlay-outs",
"landing.formats.pptx.i5": "Animaties behouden",
"landing.formats.pdf.name": "PDF",
"landing.formats.pdf.i1": "Tekstgebaseerde PDF's",
"landing.formats.pdf.i2": "Lay-out behouden",
"landing.formats.pdf.i3": "Afbeeldingen op hun plaats",
"landing.formats.pdf.i4": "Tabellen behouden",
"landing.formats.pdf.i5": "Output als DOCX of PDF",
"landing.pricing.title": "Eenvoudige, eerlijke prijzen",
"landing.pricing.subtitle": "Wat u ziet is wat u betaalt. Geen verborgen kosten.",
"landing.pricing.monthly": "Maandelijks",
"landing.pricing.annual": "Jaarlijks",
"landing.pricing.bestValue": "Meest populair",
"landing.pricing.month": "/maand",
"landing.pricing.footer": "De getoonde prijs is de prijs die u betaalt. Geen verborgen kosten na vertaling.",
"landing.pricing.starter.name": "Starter",
"landing.pricing.starter.desc": "Voor particulieren en kleine projecten",
"landing.pricing.starter.f1": "50 documenten / maand",
"landing.pricing.starter.f2": "Tot 50 pagina's per doc",
"landing.pricing.starter.f3": "Google Translate + DeepL",
"landing.pricing.starter.f4": "Bestanden tot 10 MB",
"landing.pricing.starter.cta": "Aan de slag",
"landing.pricing.pro.name": "Pro",
"landing.pricing.pro.desc": "Voor veeleisende professionals",
"landing.pricing.pro.f1": "200 documenten / maand",
"landing.pricing.pro.f2": "Tot 200 pagina's per doc",
"landing.pricing.pro.f3": "IA-aangedreven vertaling",
"landing.pricing.pro.f4": "Google + DeepL inbegrepen",
"landing.pricing.pro.f5": "Eigen glossaria en prompts",
"landing.pricing.pro.f6": "Prioriteitsondersteuning",
"landing.pricing.pro.cta": "Probeer Pro",
"landing.pricing.business.name": "Business",
"landing.pricing.business.desc": "Voor teams met grote behoeften",
"landing.pricing.business.f1": "1 000 documenten / maand",
"landing.pricing.business.f2": "Tot 500 pagina's per doc",
"landing.pricing.business.f3": "Premium AI (Claude)",
"landing.pricing.business.f4": "Alle providers + API-toegang",
"landing.pricing.business.f5": "Webhooks en automatisering",
"landing.pricing.business.f6": "5 teamplekken",
"landing.pricing.business.cta": "Neem contact op",
"landing.cta.title": "Begin met vertalen in 30 seconden",
"landing.cta.subtitle": "Geen creditcard vereist. Probeer nu gratis en geef uw meertalige documenten nieuw leven.",
"landing.cta.button": "Gratis account aanmaken",
"landing.cta.secure": "Beveiligd met AES-256-encryptie",
"landing.footer.desc": "Expert in intelligente documentvertaling. Wij combineren de kunst van lay-out met de wetenschap van contextuele AI.",
"landing.footer.product": "Product",
"landing.footer.resources": "Bronnen",
"landing.footer.legal": "Juridisch",
"landing.footer.rights": "© 2026 Wordly.art — Alle rechten voorbehouden.",
"landing.hero.contextEngine": "Vertaling gedetecteerd: Technische onderhoudsterm voor HVAC-systemen...",
"landing.hero.liveAnalysis": "Live-analyse",
"landing.hero.termsDetected": "termen gedetecteerd",
"landing.steps.process": "PROCES",
"landing.translate.newProject": "Nieuw project",
"landing.translate.title": "Vertaal een document",
"landing.translate.subtitle": "Importeer een bestand en kies de doeltaal",
"landing.translate.sourceDocument": "Brondocument",
"landing.translate.configuration": "Configuratie",
"landing.translate.sourceLang": "Brontaal",
"landing.translate.targetLang": "Doeltaal",
"landing.translate.provider": "Provider",
"landing.translate.startTranslation": "Vertaling starten",
"landing.translate.zeroRetention": "Nul retentie",
"landing.translate.filesDeleted": "Bestanden verwijderd na verwerking",
"landing.translate.dropHere": "Sleep en zet hier neer",
"landing.translate.supportedFormats": "DOCX, XLSX, PPTX of PDF bestanden ondersteund",
"landing.translate.aiAnalysis": "Actieve AI-analyse",
"landing.translate.processing": "Verwerking bezig",
"landing.translate.preservingLayout": "Uw opmaak wordt behouden"
}